From 5803d695c447630e755d6205bd223c398b850afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 18 Oct 2023 20:22:11 +0200 Subject: [PATCH 001/133] Adds `stake-tracker` pallet and integrates with the staking pallet --- Cargo.lock | 22 ++ Cargo.toml | 1 + substrate/frame/stake-tracker/Cargo.toml | 61 +++ substrate/frame/stake-tracker/README.md | 9 + substrate/frame/stake-tracker/src/lib.rs | 346 +++++++++++++++++ substrate/frame/stake-tracker/src/mock.rs | 392 ++++++++++++++++++++ substrate/frame/stake-tracker/src/tests.rs | 144 +++++++ substrate/frame/staking/Cargo.toml | 1 + substrate/frame/staking/src/ledger.rs | 69 +++- substrate/frame/staking/src/lib.rs | 4 + substrate/frame/staking/src/mock.rs | 47 ++- substrate/frame/staking/src/pallet/impls.rs | 133 +++++-- substrate/frame/staking/src/pallet/mod.rs | 54 ++- substrate/frame/staking/src/slashing.rs | 2 +- substrate/frame/staking/src/tests.rs | 229 +++++++++++- substrate/frame/staking/src/weights.rs | 10 + substrate/primitives/staking/src/lib.rs | 13 +- 17 files changed, 1466 insertions(+), 71 deletions(-) create mode 100644 substrate/frame/stake-tracker/Cargo.toml create mode 100644 substrate/frame/stake-tracker/README.md create mode 100644 substrate/frame/stake-tracker/src/lib.rs create mode 100644 substrate/frame/stake-tracker/src/mock.rs create mode 100644 substrate/frame/stake-tracker/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 033219583bd5..e7284c79ee00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10558,6 +10558,27 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-stake-tracker" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-bags-list", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", +] + [[package]] name = "pallet-staking" version = "4.0.0-dev" @@ -10571,6 +10592,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-session", + "pallet-stake-tracker", "pallet-staking-reward-curve", "pallet-timestamp", "parity-scale-codec", diff --git a/Cargo.toml b/Cargo.toml index c98fe6d1a3ac..8b21ff2505a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -336,6 +336,7 @@ members = [ "substrate/frame/session", "substrate/frame/session/benchmarking", "substrate/frame/society", + "substrate/frame/stake-tracker", "substrate/frame/staking", "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", diff --git a/substrate/frame/stake-tracker/Cargo.toml b/substrate/frame/stake-tracker/Cargo.toml new file mode 100644 index 000000000000..f41a0cbc6016 --- /dev/null +++ b/substrate/frame/stake-tracker/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "pallet-stake-tracker" +version = "0.1.0" +description = "FRAME stake tracker pallet" +authors = ["Parity Technologies "] +homepage = "https://substrate.io" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/paritytech/substrate" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } + +sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime", features = ["serde"] } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking", features = ["serde"] } +sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } + +sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support"} +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +[dev-dependencies] +sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "21.0.0", path = "../../primitives/core" } +sp-io = { version = "23.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime", features = ["serde"] } +sp-tracing = { version = "10.0.0", path = "../../primitives/tracing" } +pallet-bags-list = { version = "4.0.0-dev", path = "../bags-list" } +pallet-balances = { version = "4.0.0-dev", path = "../balances" } + +[features] +default = ["std"] + +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/stake-tracker/README.md b/substrate/frame/stake-tracker/README.md new file mode 100644 index 000000000000..0b42eb6529da --- /dev/null +++ b/substrate/frame/stake-tracker/README.md @@ -0,0 +1,9 @@ +# Pallet `stake-tracker` + +The stake-tracker pallet is listens to staking events through implemeting the +[`OnStakingUpdate`] trait and forwards those events to one or multiple types (e.g. pallets) that +must be kept up to date with certain updates in staking. The pallet does not expose any +callables and acts as a multiplexer of staking events. + + Currently, the stake tracker pallet is used to update the semi-sorted target and voter lists + implemented through bags lists. diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs new file mode 100644 index 000000000000..cc651779ac3d --- /dev/null +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -0,0 +1,346 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # StakeTracker +//! +//! FRAME stake tracker pallet +//! +//! ## Overview +//! +//! The stake-tracker pallet listens to staking events through implementing the +//! [`OnStakingUpdate`] trait and forwards those events to one or multiple types (e.g. pallets) that +//! must be kept track of the stake and staker's state. The pallet does not expose any +//! callables and acts as a multiplexer of staking events. +//! +//! Currently, the stake tracker pallet is used to update a voter and target sorted target list +//! implemented through the bags lists pallet. +//! +//! ## Goals +//! +//! The [`OnStakingUpdate`] implementation aims at achieving the following goals: +//! +//! * The [`Config::TargetList`] keeps a *lazily* sorted list of validators, sorted by approvals +//! (which include self-vote and nominations). +//! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. +//! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new +//! nomination updates, nominator/validator slashes and rewards. +//! +//! Note that from the POV of this pallet, all events will result in one or multiple +//! updates to the [`Config::VoterList`] and/or [`Config::TargetList`] state. If a update or set of +//! updates require too much weight to process (e.g. at nominator's rewards payout or at nominator's +//! slashes), the event emitter should handle that in some way (e.g. buffering events). +//! +//! ## Event emitter ordering and staking ledger state updates +//! +//! It is important to ensure that the events are emitted from staking (i.e. the calls into +//! [`OnStakingUpdate`]) *after* the caller ensures that the state of the staking ledger is up to +//! date, since the new state will be fetched and used to update the sorted lists accordingly. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +use frame_election_provider_support::SortedListProvider; +use frame_support::traits::{Currency, Defensive}; +use sp_staking::{ + currency_to_vote::CurrencyToVote, OnStakingUpdate, StakerStatus, StakingInterface, +}; +use sp_std::collections::btree_map::BTreeMap; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +/// The balance type of this pallet. +pub type BalanceOf = <::Staking as StakingInterface>::Balance; +/// The account ID of this pallet. +pub type AccountIdOf = ::AccountId; + +/// Represents a stake imbalance to be applied to a staker's score. +#[derive(Copy, Clone, Debug)] +pub enum StakeImbalance { + // Represents the reduction of stake by `Balance`. + Negative(Balance), + // Represents the increase of stake by `Balance`. + Positive(Balance), +} + +#[frame_support::pallet] +pub mod pallet { + use crate::*; + use frame_election_provider_support::VoteWeight; + use frame_support::pallet_prelude::*; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type Currency: Currency>; + + /// The staking interface. + type Staking: StakingInterface; + + /// Something that provides a best-effort sorted list of voters. + /// + /// To keep the load off the chain as much as possible, changes made to the staked amount + /// via rewards and slashes are dropped and thus need to be manually updated through + /// extrinsics. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. + type VoterList: SortedListProvider; + + /// Something that provides a best-effort sorted list of targets. + /// + /// Note that while at the time of nomination all targets are checked to be real + /// validators, they can chill at any point, and their approval stakes will still be + /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE + /// VALIDATOR. + type TargetList: SortedListProvider; + } + + impl Pallet { + /// Returns the vote weight of a staker based on its current *active* stake, as returned by + /// the staking interface. + pub(crate) fn active_vote_of(who: &T::AccountId) -> VoteWeight { + T::Staking::stake(who) + .map(|s| Self::to_vote(s.active)) + .defensive_unwrap_or_default() + } + + /// Converts a staker's balance to its vote weight. + pub(crate) fn to_vote(balance: BalanceOf) -> VoteWeight { + ::CurrencyToVote::to_vote( + balance, + T::Currency::total_issuance(), + ) + } + + /// Updates a staker's score by increasing/decreasing an imbalance of the current score in + /// the list. + pub(crate) fn update_score(who: &T::AccountId, imbalance: StakeImbalance) + where + L: SortedListProvider, Score = VoteWeight>, + { + // node does not exist, move on. + if !L::contains(who) { + return + } + + match imbalance { + StakeImbalance::Positive(imbalance) => { + let _ = L::on_increase(who, imbalance).defensive_proof( + "staker should exist in the list, otherwise returned earlier.", + ); + }, + StakeImbalance::Negative(imbalance) => { + let current_score = L::get_score(who) + .expect("staker exists in the list as per the check above; qed."); + + // TODO(gpestana): can we do better? correct assumption? + // if decreasing the imbalance makes the score lower than 0, the node will be + // removed from the list when calling `L::on_decrease`, which is not expected. + // Instead, we call `L::on_update` to set the score as 0. + if current_score.saturating_sub(imbalance) == 0 { + let _ = L::on_update(who, 0).defensive_proof( + "staker exists in the list, otherwise returned earlier.", + ); + } else { + let _ = L::on_decrease(who, imbalance) + .defensive_proof("staker exists in the list as per the check above."); + } + }, + } + } + } +} + +impl OnStakingUpdate> for Pallet { + // Fired when the stake amount of someone updates. + // + // When a nominator's stake is updated, all the nominated targets must be updated accordingly. + // + // Note: it is assumed that who's staking state is updated *before* this method is called. + fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { + if let Ok(stake) = T::Staking::stake(who) { + let voter_weight = Self::to_vote(stake.active); // TODO(gpestana): or use `active_vote_of`? + + match T::Staking::status(who).defensive_unwrap_or(StakerStatus::Idle) { + StakerStatus::Nominator(nominations) => { + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( + "staker should exist in VoterList, as per the contract \ + with staking.", + ); + + // calculate imbalace to update the score of nominated targets. + let stake_imbalance = if let Some(prev_stake) = prev_stake { + let prev_voter_weight = Self::to_vote(prev_stake.active); + + if prev_voter_weight > voter_weight { + StakeImbalance::Negative(prev_voter_weight - voter_weight) + } else { + StakeImbalance::Positive(voter_weight - prev_voter_weight) + } + } else { + // if nominator had no stake before update, then add all the voter weight + // to the target's score. + StakeImbalance::Positive(voter_weight) + }; + + // updates vote weight of nominated targets accordingly. Note: this will update + // the score of up to `T::MaxNominations` validators. + for target in nominations.into_iter() { + // target may be chilling due to a recent slash, verify if it is active + // before updating the score. + if ::is_validator(&target) { + Self::update_score::(&target, stake_imbalance); + } + } + }, + StakerStatus::Validator => { + // validator is both a target and a voter. + let _ = T::TargetList::on_update(who, voter_weight).defensive_proof( + "staker should exist in TargetList, as per the contract \ + with staking.", + ); + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( + "the staker should exit in VoterList, as per the \ + contract with staking.", + ); + }, + StakerStatus::Idle => (), // nothing to see here. + } + } + } + + // Fired when someone sets their intention to nominate. + // + // Note: it is assumed that who's staking state is updated *before* this method is called. + fn on_nominator_add(who: &T::AccountId) { + let nominator_vote = Self::active_vote_of(who); + + let _ = T::VoterList::on_insert(who.clone(), nominator_vote).defensive_proof( + "staker should not exist in VoterList, as per the contract with staking.", + ); + + // If who is a nominator, update the vote weight of the nominations if they exist. Note: + // this will update the score of up to `T::MaxNominations` validators. + match T::Staking::status(who) { + Ok(StakerStatus::Nominator(nominations)) => + for t in nominations { + Self::update_score::( + &t, + StakeImbalance::Positive(nominator_vote), + ) + }, + Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) | Err(_) => (), // nada. + }; + } + + // Fired when someone sets their intention to validate. + // + // A validator is also considered a voter with self-vote and should be added to + // [`Config::VoterList`]. + // + // Note: it is assumed that who's staking state is updated *before* calling this method. + fn on_validator_add(who: &T::AccountId) { + let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)).defensive_proof( + "staker should not exist in TargetList, as per the contract with staking.", + ); + + // a validator is also a nominator. + Self::on_nominator_add(who) + } + + // Fired when someone removes their intention to nominate, either due to chill or validating. + // + // Note: it is assumed that who's staking state is updated *before* the caller calling into + // this method. Thus, the nominations before the nominator has been removed from staking are + // passed in, so that the target list can be updated accordingly. + fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { + let nominator_vote = Self::active_vote_of(who); + + // updates the nominated target's score. Note: this may update the score of up to + // `T::MaxNominations` validators. + for t in nominations.iter() { + Self::update_score::(&t, StakeImbalance::Negative(nominator_vote)) + } + + let _ = T::VoterList::on_remove(&who).defensive_proof( + "the nominator exists in the list as per the contract with staking; qed.", + ); + } + + // Fired when someone removes their intention to validate, either due to chill or nominating. + fn on_validator_remove(who: &T::AccountId) { + let _ = T::TargetList::on_remove(&who).defensive_proof( + "the validator exists in the list as per the contract with staking; qed.", + ); + + // validator is also a nominator. + Self::on_nominator_remove(who, vec![]); + } + + // Fired when an existing nominator updates their nominations. + // + // This is called when a nominator updates their nominations. The nominator's stake remains the + // same (updates to the nominator's stake should emit [`Self::on_stake_update`] instead). + // However, the score of the nominated targets must be updated accordingly. + // + // Note: it is assumed that who's staking state is updated *before* calling this method. + fn on_nominator_update(who: &T::AccountId, prev_nominations: Vec) { + let nominator_vote = Self::active_vote_of(who); + let curr_nominations = + ::nominations(&who).unwrap_or_default(); + + // new nominations + for target in curr_nominations.iter() { + if !prev_nominations.contains(target) { + Self::update_score::( + &target, + StakeImbalance::Positive(nominator_vote), + ); + } + } + // removed nominations + for target in prev_nominations.iter() { + if !curr_nominations.contains(target) { + Self::update_score::( + &target, + StakeImbalance::Negative(nominator_vote), + ); + } + } + } + + // noop: the updates to target and voter lists when applying a slash are performed + // through [`Self::on_nominator_remove`] and [`Self::on_validator_remove`] when the stakers are + // chilled. When the slash is applied, the ledger is updated, thus the stake is propagated + // through the `[Self::update::]`. + fn on_slash( + _stash: &T::AccountId, + _slashed_active: BalanceOf, + _slashed_unlocking: &BTreeMap>, + _slashed_total: BalanceOf, + ) { + #[cfg(any(std, no_std))] + frame_support::defensive!("unexpected call to OnStakingUpdate::on_slash"); + } +} diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs new file mode 100644 index 000000000000..08f940beec35 --- /dev/null +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -0,0 +1,392 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +use crate::{self as pallet_stake_tracker, *}; + +use frame_election_provider_support::{ScoreProvider, VoteWeight}; +use frame_support::{derive_impl, parameter_types, traits::ConstU32}; +use sp_runtime::BuildStorage; +use sp_staking::{Stake, StakingInterface}; + +pub(crate) type AccountId = u64; +pub(crate) type Balance = u64; + +type Block = frame_system::mocking::MockBlockU32; + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, + TargetBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, + StakeTracker: crate, + } +); + +parameter_types! { + pub static ExistentialDeposit: Balance = 1; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; + type BaseCallFilter = frame_support::traits::Everything; + type BlockHashCount = ConstU32<10>; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type PalletInfo = PalletInfo; + type OnSetCode = (); + + type AccountData = pallet_balances::AccountData; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = frame_support::traits::ConstU32<1024>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = (); + type RuntimeHoldReason = (); + type MaxFreezes = (); +} + +const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = + [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + +parameter_types! { + pub static BagThresholds: &'static [VoteWeight] = &THRESHOLDS; +} + +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = StakingMock; + type BagThresholds = BagThresholds; + type Score = VoteWeight; +} + +type TargetBagsListInstance = pallet_bags_list::Instance2; +impl pallet_bags_list::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = StakingMock; + type BagThresholds = BagThresholds; + type Score = VoteWeight; +} + +impl pallet_stake_tracker::Config for Test { + type Currency = Balances; + + type Staking = StakingMock; + type VoterList = VoterBagsList; + type TargetList = TargetBagsList; +} + +pub struct StakingMock {} + +impl ScoreProvider for StakingMock { + type Score = VoteWeight; + + fn score(_id: &AccountId) -> Self::Score { + todo!(); + } + + fn set_score_of(_: &AccountId, _: Self::Score) { + unreachable!(); + } +} + +impl StakingInterface for StakingMock { + type Balance = Balance; + type AccountId = AccountId; + type CurrencyToVote = (); + + fn stake(who: &Self::AccountId) -> Result, sp_runtime::DispatchError> { + let n = TestNominators::get(); + match n.get(who) { + Some(nominator) => Some(nominator.0), + None => { + let v = TestValidators::get(); + v.get(who).copied() + }, + } + .ok_or("not a staker".into()) + } + + fn status( + who: &Self::AccountId, + ) -> Result, sp_runtime::DispatchError> { + let n = TestNominators::get(); + + if n.contains_key(who) { + Ok(StakerStatus::Nominator(n.get(&who).expect("exists").1.clone())) + } else if TestValidators::get().contains_key(who) { + Ok(StakerStatus::Validator) + } else { + Err("not a staker".into()) + } + } + + fn nominations(who: &Self::AccountId) -> Option> { + let n = TestNominators::get(); + if let Some(nominator) = n.get(&who) { + Some(nominator.1.clone()) + } else { + None + } + } + + fn minimum_nominator_bond() -> Self::Balance { + unreachable!(); + } + + fn minimum_validator_bond() -> Self::Balance { + unreachable!(); + } + + fn stash_by_ctrl( + _controller: &Self::AccountId, + ) -> Result { + unreachable!(); + } + + fn bonding_duration() -> sp_staking::EraIndex { + unreachable!(); + } + + fn current_era() -> sp_staking::EraIndex { + unreachable!(); + } + + fn bond( + _who: &Self::AccountId, + _value: Self::Balance, + _payee: &Self::AccountId, + ) -> sp_runtime::DispatchResult { + unreachable!(); + } + + fn nominate( + _who: &Self::AccountId, + _validators: Vec, + ) -> sp_runtime::DispatchResult { + unreachable!(); + } + + fn chill(_who: &Self::AccountId) -> sp_runtime::DispatchResult { + unreachable!(); + } + + fn bond_extra(_who: &Self::AccountId, _extra: Self::Balance) -> sp_runtime::DispatchResult { + unreachable!(); + } + + fn withdraw_unbonded( + _stash: Self::AccountId, + _num_slashing_spans: u32, + ) -> Result { + unreachable!(); + } + + fn desired_validator_count() -> u32 { + unreachable!(); + } + + fn election_ongoing() -> bool { + unreachable!(); + } + + fn force_unstake(_who: Self::AccountId) -> sp_runtime::DispatchResult { + unreachable!(); + } + + fn is_exposed_in_era(_who: &Self::AccountId, _era: &sp_staking::EraIndex) -> bool { + unreachable!(); + } + + fn unbond(_stash: &Self::AccountId, _value: Self::Balance) -> sp_runtime::DispatchResult { + unreachable!(); + } + + #[cfg(feature = "runtime-benchmarks")] + fn add_era_stakers( + current_era: &sp_staking::EraIndex, + stash: &Self::AccountId, + exposures: Vec<(Self::AccountId, Self::Balance)>, + ) { + unreachable!(); + } + + #[cfg(feature = "runtime-benchmarks")] + fn set_current_era(era: sp_staking::EraIndex) { + unreachable!(); + } +} + +type Nominations = Vec; + +parameter_types! { + pub static TestNominators: BTreeMap, Nominations)> = Default::default(); + pub static TestValidators: BTreeMap> = Default::default(); +} + +pub(crate) fn get_scores>( +) -> Vec<(AccountId, Balance)> { + let scores: Vec<_> = L::iter().map(|e| (e, L::get_score(&e).unwrap())).collect(); + scores +} + +pub(crate) fn populate_lists() { + add_validator(10, 100); + add_validator(11, 100); + + add_nominator_with_nominations(1, 100, vec![10]); + add_nominator_with_nominations(2, 100, vec![10, 11]); +} + +pub(crate) fn add_nominator(who: AccountId, stake: Balance) { + TestNominators::mutate(|n| { + n.insert(who, (Stake:: { active: stake, total: stake }, vec![])); + }); + + // add new nominator (called at `fn bond` in staking) + >::on_nominator_add(&who); +} + +pub(crate) fn stake_of(who: AccountId) -> Option> { + match StakingMock::stake(&who) { + Ok(stake) => Some(stake), + Err(_) => None, + } +} + +pub(crate) fn add_nominator_with_nominations( + who: AccountId, + stake: Balance, + nominations: Nominations, +) { + // add new nominator (called at `fn bond` in staking) + add_nominator(who, stake); + + // add nominations (called at `fn nominate` in staking) + TestNominators::mutate(|n| { + n.insert(who, (Stake:: { active: stake, total: stake }, nominations)); + }); + + >::on_nominator_update(&who, vec![]); +} + +pub(crate) fn update_nominations_of(who: AccountId, new_nominations: Nominations) { + // add nominations (called at `fn nominate` in staking) + let current_nom = TestNominators::get(); + let (current_stake, prev_nominations) = current_nom.get(&who).unwrap(); + + TestNominators::mutate(|n| { + n.insert(who, (current_stake.clone(), new_nominations)); + }); + + >::on_nominator_update( + &who, + prev_nominations.clone(), + ); +} + +pub(crate) fn add_validator(who: AccountId, stake: Balance) { + TestValidators::mutate(|v| { + v.insert(who, Stake:: { active: stake, total: stake }); + }); + + >::on_validator_add(&who); +} + +pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option>) { + match StakingMock::status(&who) { + Ok(StakerStatus::Nominator(nominations)) => { + TestNominators::mutate(|n| { + n.insert(who, (Stake { active: new, total: new }, nominations)); + }); + }, + Ok(StakerStatus::Validator) => { + TestValidators::mutate(|n| { + n.insert(who, Stake { active: new, total: new }); + }); + }, + Ok(StakerStatus::Idle) | Err(_) => panic!("not a staker"), + } + + >::on_stake_update(&who, prev_stake); +} + +pub(crate) fn remove_staker(who: AccountId) { + if TestNominators::get().contains_key(&who) { + let nominations = ::nominations(&who).unwrap(); + + >::on_nominator_remove( + &who, + nominations, + ); + TestNominators::mutate(|n| { + n.remove(&who); + }); + } else if TestValidators::get().contains_key(&who) { + >::on_validator_remove(&who); + TestValidators::mutate(|v| v.remove(&who)); + }; +} + +#[derive(Default, Copy, Clone)] +pub struct ExtBuilder { + populate_lists: bool, +} + +impl ExtBuilder { + pub fn populate_lists(mut self) -> Self { + self.populate_lists = true; + self + } + + pub fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + sp_io::TestExternalities::from(storage) + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + sp_tracing::try_init_simple(); + + let mut ext = self.build(); + ext.execute_with(|| { + if self.populate_lists { + populate_lists(); + } + test() + }); + } +} diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs new file mode 100644 index 000000000000..6b8e25a9bf00 --- /dev/null +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -0,0 +1,144 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(test)] + +use crate::mock::*; + +use frame_election_provider_support::SortedListProvider; +use sp_staking::Stake; + +#[test] +fn setup_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(TestNominators::get().is_empty()); + assert_eq!(VoterBagsList::count(), 0); + + assert!(TestValidators::get().is_empty()); + assert_eq!(TargetBagsList::count(), 0); + }); + + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(!TestNominators::get().is_empty()); + assert_eq!(VoterBagsList::count(), 4); // voter list has 2x nominatiors + 2x validators + + assert!(!TestValidators::get().is_empty()); + assert_eq!(TargetBagsList::count(), 2); + }); +} + +#[test] +fn staking_interface_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(TestNominators::get().iter().count(), 0); + assert_eq!(TestValidators::get().iter().count(), 0); + + add_nominator(1, 100); + let n = TestNominators::get(); + assert_eq!(n.get(&1).unwrap().0, Stake { active: 100u64, total: 100u64 }); + + add_validator(2, 200); + let v = TestValidators::get(); + assert_eq!(v.get(&2).copied().unwrap(), Stake { active: 200u64, total: 200u64 }); + }) +} + +#[test] +fn on_add_stakers_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert_eq!(TargetBagsList::count(), 0); + assert_eq!(VoterBagsList::count(), 1); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); + + add_validator(10, 200); + assert_eq!(VoterBagsList::count(), 2); // 1x nominator + 1x validator + assert_eq!(TargetBagsList::count(), 1); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + }) +} + +#[test] +fn on_update_stake_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); + update_stake(1, 200, stake_of(1)); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 200); + + add_validator(10, 100); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); + update_stake(10, 200, stake_of(10)); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + }) +} + +#[test] +fn on_remove_stakers_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert!(VoterBagsList::contains(&1)); + remove_staker(1); + assert!(!VoterBagsList::contains(&1)); + + add_validator(10, 100); + assert!(TargetBagsList::contains(&10)); + remove_staker(10); + assert!(!TargetBagsList::contains(&10)); + }) +} + +#[test] +fn on_remove_stakers_with_nominations_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::get_score(&1), Ok(100)); + assert_eq!(TargetBagsList::get_score(&10), Ok(300)); + + // remove nominator deletes node from voter list and updates the stake of its nominations. + remove_staker(1); + assert!(!VoterBagsList::contains(&1)); + assert_eq!(TargetBagsList::get_score(&10), Ok(200)); + }) +} + +#[test] +fn on_nominator_update_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert_eq!(get_scores::(), vec![(10, 100), (11, 100), (1, 100), (2, 100)]); + assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + + add_validator(20, 50); + // removes nomination from 10 and adds nomination to new validator, 20. + update_nominations_of(2, vec![11, 20]); + + // new voter (validator) 2 with 100 stake. note that the voter score is not updated + // automatically. + assert_eq!( + get_scores::(), + vec![(10, 100), (11, 100), (1, 100), (2, 100), (20, 50)] + ); + + // target list has been updated: + // -100 score for 10 + // +100 score for 11 + // +100 score for 20 + assert_eq!(get_scores::(), vec![(10, 200), (11, 200), (20, 150)]); + }) +} diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 5cd134471ebc..479bd8148e7e 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -42,6 +42,7 @@ sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } +pallet-stake-tracker = { path = "../stake-tracker" } pallet-staking-reward-curve = { path = "reward-curve" } pallet-bags-list = { path = "../bags-list" } substrate-test-utils = { path = "../../test-utils" } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index cf9b4635bf55..7b44fddd5996 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -33,22 +33,29 @@ use frame_support::{ defensive, - traits::{LockableCurrency, WithdrawReasons}, + traits::{Defensive, LockableCurrency, WithdrawReasons}, BoundedVec, }; -use sp_staking::{EraIndex, StakingAccount}; +use sp_staking::{ + EraIndex, OnStakingUpdate, Stake, StakerStatus, StakingAccount, StakingInterface, +}; use sp_std::prelude::*; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, + UntrackedStake, STAKING_ID, }; -#[cfg(any(feature = "runtime-benchmarks", test))] -use sp_runtime::traits::Zero; +impl Into>> for StakingLedger { + fn into(self) -> Stake> { + Stake { total: self.total, active: self.active } + } +} impl StakingLedger { #[cfg(any(feature = "runtime-benchmarks", test))] pub fn default_from(stash: T::AccountId) -> Self { + use sp_runtime::traits::Zero; Self { stash: stash.clone(), total: Zero::zero(), @@ -166,19 +173,29 @@ impl StakingLedger { /// /// Note: To ensure lock consistency, all the [`Ledger`] storage updates should be made through /// this helper function. - pub(crate) fn update(self) -> Result<(), Error> { + pub(crate) fn update(self) -> Result<(), Error> + where + OnUpdate: OnStakingUpdate>, + { if !>::contains_key(&self.stash) { return Err(Error::::NotStash) } + let controller = &self.controller().ok_or_else(|| { + defensive!("update called on a ledger that was not contructed via `StakingLedger` impl. unexpected."); + Error::::NotController + })?; + + // previous stake is the current stake in storage. + let prev_stake: Option> = match Ledger::::get(&controller) { + Some(current_ledger) => Some(current_ledger.into()), + None => None, + }; + T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); - Ledger::::insert( - &self.controller().ok_or_else(|| { - defensive!("update called on a ledger that is not bonded."); - Error::::NotController - })?, - &self, - ); + Ledger::::insert(controller, &self); + + OnUpdate::on_stake_update(&self.stash, prev_stake); Ok(()) } @@ -186,13 +203,19 @@ impl StakingLedger { /// Bonds a ledger. /// /// It sets the reward preferences for the bonded stash. - pub(crate) fn bond(self, payee: RewardDestination) -> Result<(), Error> { + pub(crate) fn bond( + self, + payee: RewardDestination, + ) -> Result<(), Error> + where + OnUpdate: OnStakingUpdate>, + { if >::contains_key(&self.stash) { Err(Error::::AlreadyBonded) } else { >::insert(&self.stash, payee); >::insert(&self.stash, &self.stash); - self.update() + self.update::() } } @@ -208,15 +231,29 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. - pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { + pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> + where + OnUpdate: OnStakingUpdate>, + { let controller = >::get(stash).ok_or(Error::::NotStash)?; + // call on validator remove or on nominator remove. + match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { + StakerStatus::Validator => OnUpdate::on_validator_remove(stash), + StakerStatus::Nominator(_) => { + let nominations = crate::Pallet::::nominations(stash).unwrap_or_default(); + OnUpdate::on_nominator_remove(stash, nominations) + }, + StakerStatus::Idle => (), + }; + >::get(&controller).ok_or(Error::::NotController).map(|ledger| { T::Currency::remove_lock(STAKING_ID, &ledger.stash); Ledger::::remove(controller); >::remove(&stash); >::remove(&stash); + >::remove(&stash); Ok(()) })? diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 227326763a9b..f56d8500d35f 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -326,6 +326,10 @@ pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap}; pub(crate) const STAKING_ID: LockIdentifier = *b"staking "; pub(crate) const LOG_TARGET: &str = "runtime::staking"; +// Marker type to pass as type [`sp_staking::OnStakingUpdate`] that does nothing, i.e. it does not +// propagate the event to any event listener. +pub(crate) type UntrackedEvent = (); + // syntactic sugar for logging. #[macro_export] macro_rules! log { diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 26d05d3a8c87..ea27d2a0ae5f 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -20,7 +20,7 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, - onchain, SequentialPhragmen, VoteWeight, + onchain, SequentialPhragmen, SortedListProvider, VoteWeight, }; use frame_support::{ assert_ok, ord_parameter_types, parameter_types, @@ -101,7 +101,9 @@ frame_support::construct_runtime!( Staking: pallet_staking, Session: pallet_session, Historical: pallet_session::historical, + StakeTracker: pallet_stake_tracker, VoterBagsList: pallet_bags_list::, + TargetBagsList: pallet_bags_list::, } ); @@ -252,6 +254,16 @@ impl pallet_bags_list::Config for Test { type Score = VoteWeight; } +type TargetBagsListInstance = pallet_bags_list::Instance2; +impl pallet_bags_list::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + // Staking is the source of truth for target bags list. + type ScoreProvider = Staking; + type BagThresholds = BagThresholds; + type Score = VoteWeight; +} + pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Test; @@ -275,8 +287,8 @@ parameter_types! { (Zero::zero(), BTreeMap::new()); } -pub struct EventListenerMock; -impl OnStakingUpdate for EventListenerMock { +pub struct SlashListenerMock; +impl OnStakingUpdate for SlashListenerMock { fn on_slash( _pool_account: &AccountId, slashed_bonded: Balance, @@ -287,6 +299,13 @@ impl OnStakingUpdate for EventListenerMock { } } +impl pallet_stake_tracker::Config for Test { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterBagsList; + type TargetList = TargetBagsList; +} + impl crate::pallet::pallet::Config for Test { type Currency = Balances; type CurrencyBalance = ::Balance; @@ -309,11 +328,11 @@ impl crate::pallet::pallet::Config for Test { type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = VoterBagsList; - type TargetList = UseValidatorsMap; + type TargetList = TargetBagsList; type NominationsQuota = WeightedNominationsQuota<16>; type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; - type EventListeners = EventListenerMock; + type EventListeners = (StakeTracker, SlashListenerMock); type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); } @@ -481,6 +500,8 @@ impl ExtBuilder { (71, self.balance_factor * 2000), (80, self.balance_factor), (81, self.balance_factor * 2000), + (90, self.balance_factor), + (91, self.balance_factor * 2000), // This allows us to have a total_payout different from 0. (999, 1_000_000_000_000), ], @@ -577,7 +598,9 @@ impl ExtBuilder { let mut ext = self.build(); ext.execute_with(test); ext.execute_with(|| { - Staking::do_try_state(System::block_number()).unwrap(); + Staking::do_try_state(System::block_number()) + .map_err(|err| println!(" 🕵️‍♂️ try_state failue: {:?}", err)) + .unwrap(); }); } } @@ -841,3 +864,15 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } + +#[allow(dead_code)] +pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(AccountId, VoteWeight)>) { + ( + VoterBagsList::iter() + .map(|v| (v, VoterBagsList::get_score(&v).unwrap())) + .collect::>(), + TargetBagsList::iter() + .map(|t| (t, TargetBagsList::get_score(&t).unwrap())) + .collect::>(), + ) +} diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index ad2de1d59315..10703ec23fe6 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -41,7 +41,7 @@ use sp_runtime::{ use sp_staking::{ currency_to_vote::CurrencyToVote, offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, Stake, + EraIndex, OnStakingUpdate, SessionIndex, Stake, StakingAccount::{self, Controller, Stash}, StakingInterface, }; @@ -51,7 +51,7 @@ use crate::{ election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, - SessionInterface, StakingLedger, ValidatorPrefs, + SessionInterface, StakerStatus, StakingLedger, UntrackedEvent, ValidatorPrefs, }; use super::pallet::*; @@ -117,6 +117,52 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } + /// Registers untracked stake for a given account. + /// + /// Untracked stake is stake that hasn't been propagated to `T::EventListeners` + /// and that may be eventually propagated by calling [`Self::maybe_settled_untracked_stake`]. + /// + /// The stake buffered under [`UntrackedStake`] corresponds to the *latest* up to date stake of + /// a ledger that has untracked stake. + pub(crate) fn add_untracked_stake(who: &T::AccountId, stake: Stake>) { + UntrackedStake::::mutate(who, |maybe_prev_stake| { + // if the stash already has untracked stake, do not update it. Wa want to keep the + // *latest* up to date stake in storage. + if maybe_prev_stake.is_none() { + *maybe_prev_stake = Some(stake); + } + }); + } + + /// Tries to settle untracked rewards buffered in [`UntrackedStake`] by caling into + /// [`sp_staking::OnStakingUpdate::on_stake_update`] to propagate the untracked stake. + /// + /// Returns the untracked rewards that have been setted, if any. + pub(crate) fn maybe_settle_untracked_stake( + who: &T::AccountId, + ) -> Option>> + where + OnUpdate: OnStakingUpdate>, + { + UntrackedStake::::mutate_exists(who, |maybe_prev_stake| { + if let Some(prev_stake) = maybe_prev_stake { + let ledger = Self::ledger(Stash(who.clone())).expect("if the stash has untracked stake, it exists; qed."); + + // we kept track of the latest up to date stake of the ledger. Now we can use it to + // settle the difference. + let prev_stake = prev_stake.clone(); + OnUpdate::on_stake_update(&ledger.stash, Some(prev_stake)); + + // deletes key. + *maybe_prev_stake = None; + + Some(prev_stake) + } else { + None + } + }) + } + pub(super) fn do_withdraw_unbonded( controller: &T::AccountId, num_slashing_spans: u32, @@ -137,8 +183,11 @@ impl Pallet { T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans) } else { - // This was the consequence of a partial unbond. just update the ledger and move on. - ledger.update()?; + // This was the consequence of a partial unbond. just update the ledger and move + // on. But before, try to settle untracked stakes of the controller if they exist. + Self::maybe_settle_untracked_stake::(&ledger.stash); + + ledger.update::()?; // This is only an update, so we use less overall weight. T::WeightInfo::withdraw_unbonded_update(num_slashing_spans) @@ -209,7 +258,7 @@ impl Pallet { // Input data seems good, no errors allowed after this point - ledger.update()?; + ledger.update::()?; // Get Era reward points. It has TOTAL and INDIVIDUAL // Find the fraction of the era reward that belongs to the validator @@ -313,13 +362,26 @@ impl Pallet { RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { + let prev_stake = ledger.clone().into(); + ledger.active += amount; ledger.total += amount; let r = T::Currency::deposit_into_existing(stash, amount).ok(); - let _ = ledger - .update() - .defensive_proof("ledger fetched from storage, so it exists; qed."); + // if it's a nominator, the ledger update event should not be propagated due to + // the complexity of updating the stake of all (potentially) exposed validators + // to this nominator and the cascading effects that may occur. + let _ = match ::status(stash) + .expect("stash is a staker; qed.") + { + StakerStatus::Nominator(_) => { + ledger.update::()?; + Self::add_untracked_stake(&stash, prev_stake); + Ok(()) + }, + StakerStatus::Validator => ledger.update::(), + StakerStatus::Idle => Ok(()), + }; Ok(r) }) @@ -599,6 +661,7 @@ impl Pallet { let mut total_stake: BalanceOf = Zero::zero(); exposures.into_iter().for_each(|(stash, exposure)| { total_stake = total_stake.saturating_add(exposure.total); + >::insert(new_planned_era, &stash, &exposure); let mut exposure_clipped = exposure; @@ -678,13 +741,16 @@ impl Pallet { pub(crate) fn kill_stash(stash: &T::AccountId, num_slashing_spans: u32) -> DispatchResult { slashing::clear_stash_metadata::(&stash, num_slashing_spans)?; - // removes controller from `Bonded` and staking ledger from `Ledger`, as well as reward - // setting of the stash in `Payee`. - StakingLedger::::kill(&stash)?; - + // note: these must be called *before* cleaning up the staking ledger storage with fn kill. Self::do_remove_validator(&stash); Self::do_remove_nominator(&stash); + // and finally, it removes controller from `Bonded` and staking ledger from `Ledger`, as + // well as reward setting of the stash in `Payee`. We use the untracked event type since + // both [`Self::do_remove_validator`] and [`Self::do_remove_nominator`] already propagate + // the events. + StakingLedger::::kill::(&stash)?; + frame_system::Pallet::::dec_consumers(&stash); Ok(()) @@ -945,11 +1011,21 @@ impl Pallet { /// wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { - // maybe update sorted list. - let _ = T::VoterList::on_insert(who.clone(), Self::weight_of(who)) - .defensive_unwrap_or_default(); + // new nominator. + >>::on_nominator_add( + who, + ); + Nominators::::insert(who, nominations); + } else { + // update nominations. + let prev_nominations = Self::nominations(who).unwrap_or_default(); + + >>::on_nominator_update( + who, + prev_nominations, + ); + Nominators::::insert(who, nominations.clone()); } - Nominators::::insert(who, nominations); debug_assert_eq!( Nominators::::count() + Validators::::count(), @@ -967,8 +1043,11 @@ impl Pallet { /// wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { let outcome = if Nominators::::contains_key(who) { + >>::on_nominator_remove( + who, + Self::nominations(who).unwrap_or_default(), + ); Nominators::::remove(who); - let _ = T::VoterList::on_remove(who).defensive(); true } else { false @@ -979,6 +1058,11 @@ impl Pallet { T::VoterList::count() ); + debug_assert_eq!( + Nominators::::count() + Validators::::count(), + T::VoterList::count() + ); + outcome } @@ -991,9 +1075,9 @@ impl Pallet { /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { - // maybe update sorted list. - let _ = T::VoterList::on_insert(who.clone(), Self::weight_of(who)) - .defensive_unwrap_or_default(); + >>::on_validator_add( + who, + ); } Validators::::insert(who, prefs); @@ -1013,7 +1097,9 @@ impl Pallet { pub fn do_remove_validator(who: &T::AccountId) -> bool { let outcome = if Validators::::contains_key(who) { Validators::::remove(who); - let _ = T::VoterList::on_remove(who).defensive(); + >>::on_validator_remove( + who, + ); true } else { false @@ -1717,7 +1803,6 @@ impl StakingInterface for Pallet { let is_validator = Validators::::contains_key(&who); let is_nominator = Nominators::::get(&who); - use sp_staking::StakerStatus; match (is_validator, is_nominator.is_some()) { (false, false) => Ok(StakerStatus::Idle), (true, false) => Ok(StakerStatus::Validator), @@ -1774,11 +1859,11 @@ impl Pallet { ensure!( ::VoterList::count() == Nominators::::count() + Validators::::count(), - "wrong external count" + "wrong external count (VoterList.count != Nominators.count + Validators.count)" ); ensure!( ::TargetList::count() == Validators::::count(), - "wrong external count" + "wrong external count (TargetList.count != Validators.count)" ); ensure!( ValidatorCount::::get() <= diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index f084299be8e1..b179d59fcec5 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -36,7 +36,7 @@ use sp_runtime::{ ArithmeticError, Perbill, Percent, }; use sp_staking::{ - EraIndex, SessionIndex, + EraIndex, SessionIndex, Stake, StakingAccount::{self, Controller, Stash}, }; use sp_std::prelude::*; @@ -102,6 +102,7 @@ pub mod pallet { + From + TypeInfo + MaxEncodedLen; + /// Time used for computing era duration. /// /// It is guaranteed to start being called from the first `on_finalize`. Thus value at @@ -246,7 +247,7 @@ pub mod pallet { /// validators, they can chill at any point, and their approval stakes will still be /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE /// VALIDATOR. - type TargetList: SortedListProvider>; + type TargetList: SortedListProvider; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can /// have. Effectively determines how many unique eras a staker may be @@ -323,6 +324,14 @@ pub mod pallet { #[pallet::storage] pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; + /// Map with the latest tracked stake of accounts with untracked stake. + /// + /// Untracked stake is the ledger stake that hasn't been propagated to the + /// `T::EventListeners`. + #[pallet::storage] + pub type UntrackedStake = + StorageMap<_, Blake2_128Concat, T::AccountId, Stake>>; + /// Where the reward payment should be made. Keyed by stash. /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. @@ -765,6 +774,8 @@ pub mod pallet { CommissionTooLow, /// Some bound is not met. BoundNotMet, + /// No untracked stake found for a given stash. + NoUntrackedStake, } #[pallet::hooks] @@ -874,7 +885,7 @@ pub mod pallet { // You're auto-bonded forever, here. We might improve this by only bonding when // you actually validate/nominate and remove once you unbond __everything__. - ledger.bond(payee)?; + ledger.bond::(payee)?; Ok(()) } @@ -914,12 +925,7 @@ pub mod pallet { Error::::InsufficientBond ); - // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; - // update this staker in the sorted list, if they exist in it. - if T::VoterList::contains(&stash) { - let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); - } + ledger.update::()?; Self::deposit_event(Event::::Bonded { stash, amount: extra }); } @@ -1015,7 +1021,10 @@ pub mod pallet { .map_err(|_| Error::::NoMoreChunks)?; }; // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; + // But before, try to settle untracked stakes of the controller if they exist. + Self::maybe_settle_untracked_stake::(&ledger.stash); + + ledger.update::()?; // update this staker in the sorted list, if they exist in it. if T::VoterList::contains(&stash) { @@ -1174,6 +1183,10 @@ pub mod pallet { suppressed: false, }; + // Try to settle untracked stakes of the stash if they exist, before updating the + // nominator's state. + Self::maybe_settle_untracked_stake::(&stash); + Self::do_remove_validator(stash); Self::do_add_nominator(stash, nominations); Ok(()) @@ -1518,7 +1531,10 @@ pub mod pallet { let final_unlocking = ledger.unlocking.len(); // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; + // But before, try to settle untracked stakes of the controller if they exist. + Self::maybe_settle_untracked_stake::(&ledger.stash); + + ledger.update::()?; if T::VoterList::contains(&stash) { let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); } @@ -1779,6 +1795,22 @@ pub mod pallet { MinCommission::::put(new); Ok(()) } + + /// Settles a untracked stake, if it exists. + #[pallet::call_index(26)] + #[pallet::weight(T::WeightInfo::settle_untracked_stake())] + pub fn settle_untracked_stake( + origin: OriginFor, + stash: T::AccountId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + if Self::maybe_settle_untracked_stake::(&stash).is_none() { + Err(Error::::NoUntrackedStake.into()) + } else { + Ok(Pays::No.into()) + } + } } } diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 0d84d503733e..6fe8cc29727f 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -615,7 +615,7 @@ pub fn do_slash( } let _ = ledger - .update() + .update::() .defensive_proof("ledger fetched from storage so it exists in storage; qed."); // trigger the event diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index cb620f89f12c..f61205d94442 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -198,7 +198,7 @@ fn basic_setup_works() { assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); assert_eq!( - Staking::eras_stakers(active_era(), 11), + Staking::eras_stakers(active_era(), 21), Exposure { total: 1125, own: 1000, @@ -206,7 +206,7 @@ fn basic_setup_works() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), 21), + Staking::eras_stakers(active_era(), 11), Exposure { total: 1375, own: 1000, @@ -232,6 +232,38 @@ fn basic_setup_works() { }); } +#[test] +fn untracked_rewards_works() { + ExtBuilder::default().nominate(true).build_and_execute(|| { + assert_eq!(UntrackedStake::::iter_keys().count(), 0); + + let stake = |active: BalanceOf, total: BalanceOf| sp_staking::Stake::< + BalanceOf, + > { + total, + active, + }; + + Pallet::::add_untracked_stake(&11, stake(10, 10)); + Pallet::::add_untracked_stake(&11, stake(20, 20)); + Pallet::::add_untracked_stake(&21, stake(10, 10)); + + assert_eq!(UntrackedStake::::iter_keys().count(), 2); + // keep inital `previous_stake` after multiple calls to `add_untracked_rewards. + assert_eq!(UntrackedStake::::get(&11), Some(stake(10, 10))); + assert_eq!(UntrackedStake::::get(&21), Some(stake(10, 10))); + + // stash 101 doesn't have untracked rewards. + assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&101), None); + assert_eq!(UntrackedStake::::iter_keys().count(), 2); + + assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&11), Some(stake(10, 10))); + assert_eq!(UntrackedStake::::iter_keys().count(), 1); + assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&21), Some(stake(10, 10))); + assert_eq!(UntrackedStake::::iter_keys().count(), 0); + }) +} + #[test] fn change_controller_works() { ExtBuilder::default().build_and_execute(|| { @@ -1807,7 +1839,8 @@ fn reap_stash_works() { // no easy way to cause an account to go below ED, we tweak their staking ledger // instead. - Ledger::::insert(11, StakingLedger::::new(11, 5, bounded_vec![])); + let ledger = StakingLedger::::new(11, 5, bounded_vec![]); + assert_ok!(ledger.update::<::EventListeners>()); // reap-able assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); @@ -2069,8 +2102,8 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { assert_eq!( supports, vec![ - (21, Support { total: 1800, voters: vec![(21, 1000), (1, 400), (3, 400)] }), - (31, Support { total: 2200, voters: vec![(31, 1000), (1, 600), (3, 600)] }) + (21, Support { total: 2200, voters: vec![(21, 1000), (1, 600), (3, 600)] }), + (31, Support { total: 1800, voters: vec![(31, 1000), (1, 400), (3, 400)] }), ], ); }); @@ -2413,7 +2446,6 @@ fn slash_in_old_span_does_not_deselect() { // this staker is in a new slashing span now, having re-registered after // their prior slash. - on_offence_in_era( &[OffenceDetails { offender: (11, Staking::eras_stakers(active_era(), 11)), @@ -4467,6 +4499,180 @@ fn on_finalize_weight_is_nonzero() { }) } +mod sorted_list_provider_integration { + use super::*; + use frame_election_provider_support::ScoreProvider; + use sp_staking::Stake; + + // helper to fetch ledger's active stake lists and scores. + fn staker_state(who: AccountId) -> (Balance, Balance, Balance) { + ( + StakingLedger::::get(StakingAccount::Stash(who)).unwrap().active, + VoterBagsList::score(&who).into(), + TargetBagsList::score(&who).into(), + ) + } + + #[test] + fn nominator_bond_unbond_chill_works() { + ExtBuilder::default().build_and_execute(|| { + Balances::make_free_balance_be(&42, 100); + + // initial stakers. + assert_eq!(VoterBagsList::iter().count(), 4); + assert_eq!(TargetBagsList::iter().count(), 3); + + assert_eq!(TargetBagsList::score(&11), 1500); + assert_eq!(TargetBagsList::score(&21), 1500); + + // bond and nominate (11, 21) with stash 42. + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, Default::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); + + // stash 42 is now a voter with a score. + assert_eq!(VoterBagsList::iter().count(), 5); + assert_eq!(VoterBagsList::score(&42), 25); + // but not a target. + assert_eq!(TargetBagsList::iter().count(), 3); + + // targets stake approval updated accordingly. + assert_eq!(TargetBagsList::score(&11), 1525); + assert_eq!(TargetBagsList::score(&21), 1525); + + // let's add more bond to stash and check if the scores have been updated. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(42), 25)); + assert_eq!(VoterBagsList::score(&42), 50); + assert_eq!(TargetBagsList::score(&11), 1550); + assert_eq!(TargetBagsList::score(&21), 1550); + + // now, let's unbond partially and check if the scores have been upated. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(42), 30)); + assert_eq!(VoterBagsList::score(&42), 20); + assert_eq!(TargetBagsList::score(&11), 1520); + assert_eq!(TargetBagsList::score(&21), 1520); + + // finally, stash 42 chills and unbond completely. + assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); + assert_eq!(VoterBagsList::contains(&42), false); + assert_eq!(TargetBagsList::score(&11), 1500); + assert_eq!(TargetBagsList::score(&21), 1500); + }) + } + + #[test] + fn validator_validate_chill_works() { + ExtBuilder::default().build_and_execute(|| { + Balances::make_free_balance_be(&42, 100); + + // initial targets. + assert_eq!(TargetBagsList::iter().count(), 3); + assert_eq!(TargetBagsList::contains(&42), false); + + // bond and set intention to validate. stash 42 is both target and voter. + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); + + assert_eq!(TargetBagsList::score(&42), 25); + assert_eq!(VoterBagsList::score(&42), 25); + + // let's add more bond to stash and check if the scores have been updated. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(42), 25)); + assert_eq!(TargetBagsList::score(&42), 50); + assert_eq!(VoterBagsList::score(&42), 50); + + // now, let's unbond partially and check if the scores have been upated. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(42), 30)); + assert_eq!(VoterBagsList::score(&42), 20); + assert_eq!(TargetBagsList::score(&42), 20); + + // finally, stash 42 chills and unbond completely. + assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); + assert_eq!(VoterBagsList::contains(&42), false); + assert_eq!(TargetBagsList::contains(&42), false); + }) + } + + #[test] + fn payouts_with_untracked_stake_work() { + ExtBuilder::default().build_and_execute(|| { + Balances::make_free_balance_be(&42, 100); + + // bond and nominate (11, 21) with stash 42. + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 50, Default::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); + + // nominator 42 compounds rewards. + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(42), RewardDestination::Staked)); + assert_eq!(Balances::free_balance(42), 100); + + let (active, voter_score, _) = staker_state(42); + assert_eq!(active, voter_score); + + mock::start_active_era(1); + // reward validator 11 and its nominators. + Staking::reward_by_ids(vec![(11, 10)]); + + mock::start_active_era(2); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(11), 11, 1)); + + // the rewards have not been propagated to the voter and target lists, although they + // should be reflected in the staking ledger. + let (active, voter_score, _) = staker_state(42); + assert!(active > voter_score); + + assert!(>::get(42).is_some()); + + // from the targets PoV, the rewards earned by the nominator haven't yet been added to + // the score. we buffer the target score of both validators to compare after the + // untracked rewards have been settled. + let (_, _, target_score_11_deficit) = staker_state(11); + + // changing the nominations will trigger the untracked stake to be settled. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11])); + + assert!(>::get(42).is_none()); + + // thus the nominator's active and voter score is now the same. + let (active, voter_score, _) = staker_state(42); + assert_eq!(active, voter_score); + + // target score of validators is larger, after the untracked staked is settled. + let (_, _, target_score_11_settled) = staker_state(11); + assert!(target_score_11_settled > target_score_11_deficit); + }) + } + + #[test] + fn untracked_stake_settle_extrinsic_works() { + ExtBuilder::default().build_and_execute(|| { + Balances::make_free_balance_be(&42, 100); + + // bond and nominate (11, 21) with stash 42. + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 10, Default::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); + + assert!(>::get(42).is_none()); + + let (_, _, target_11) = staker_state(11); + let (_, _, target_21) = staker_state(21); + + // add untracked stake to nominator 42 manually. + >::insert(&42, Stake { total: 5, active: 5 }); + + assert_ok!(Staking::settle_untracked_stake(RuntimeOrigin::signed(42), 42)); + assert!(>::get(42).is_none()); + + let (_, _, target_11_settled) = staker_state(11); + let (_, _, target_21_settled) = staker_state(21); + + // the settled target score of the validatorsis larger by the amount of untracked stake + // of their nominator 42. + assert!(target_11_settled == target_11 + 5); + assert!(target_21_settled == target_21 + 5); + }) + } +} + mod election_data_provider { use super::*; use frame_election_provider_support::ElectionDataProvider; @@ -4785,11 +4991,11 @@ mod election_data_provider { // nominating with targets below the nomination quota works. assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11])); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21])); // nominating with targets above the nomination quota returns error. assert_noop!( - Staking::nominate(RuntimeOrigin::signed(61), vec![11, 12, 13]), + Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 31]), Error::::TooManyTargets ); }); @@ -5450,7 +5656,6 @@ mod sorted_list_provider { ::VoterList::iter().collect::>(), vec![11, 21, 31, 101] ); - // when account 101 renominates assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![41])); @@ -6208,17 +6413,17 @@ mod ledger { let mut ledger: StakingLedger = StakingLedger::default_from(42); let reward_dest = RewardDestination::Account(10); - assert_ok!(ledger.clone().bond(reward_dest)); + assert_ok!(ledger.clone().bond::<()>(reward_dest)); assert!(StakingLedger::::is_bonded(StakingAccount::Stash(42))); assert!(>::get(&42).is_some()); assert_eq!(>::get(&42), reward_dest); // cannot bond again. - assert!(ledger.clone().bond(reward_dest).is_err()); + assert!(ledger.clone().bond::<()>(reward_dest).is_err()); // once bonded, update works as expected. ledger.claimed_rewards = bounded_vec![1]; - assert_ok!(ledger.update()); + assert_ok!(ledger.update::()); }) } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index f2c65e677cac..a284c3b7e586 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -82,6 +82,7 @@ pub trait WeightInfo { fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; + fn settle_untracked_stake() -> Weight; } /// Weights for pallet_staking using the Substrate node and recommended hardware. @@ -793,6 +794,10 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(3_679_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + + fn settle_untracked_stake() -> Weight { + todo!() + } } // For backwards compatibility and tests @@ -1503,4 +1508,9 @@ impl WeightInfo for () { Weight::from_parts(3_679_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + + fn settle_untracked_stake() -> Weight { + todo!() + } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index dfc18987d152..ec249ee24169 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -68,7 +68,18 @@ pub enum StakerStatus { /// A struct that reflects stake that an account has in the staking system. Provides a set of /// methods to operate on it's properties. Aimed at making `StakingInterface` more concise. -#[derive(RuntimeDebug, Clone, Copy, Eq, PartialEq, Default)] +#[derive( + RuntimeDebug, + Clone, + Copy, + Eq, + PartialEq, + Default, + TypeInfo, + sp_core::Encode, + sp_core::Decode, + MaxEncodedLen, +)] pub struct Stake { /// The total stake that `stash` has in the staking system. This includes the /// `active` stake, and any funds currently in the process of unbonding via From c7ad6bf3fe2fc60e074f4b9dfb7384dba3f6baa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 18 Oct 2023 23:19:51 +0200 Subject: [PATCH 002/133] Comments and other nit fixes --- substrate/frame/stake-tracker/src/lib.rs | 9 +++++---- substrate/frame/staking/src/pallet/impls.rs | 14 +++++++------- substrate/frame/staking/src/pallet/mod.rs | 6 +++--- substrate/primitives/staking/src/lib.rs | 13 ++----------- 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index cc651779ac3d..0d3a9995ede4 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -139,7 +139,8 @@ pub mod pallet { where L: SortedListProvider, Score = VoteWeight>, { - // node does not exist, move on. + // there may be nominators who nominate a non-existant validator. if that's the case, + // move on. if !L::contains(who) { return } @@ -154,10 +155,10 @@ pub mod pallet { let current_score = L::get_score(who) .expect("staker exists in the list as per the check above; qed."); - // TODO(gpestana): can we do better? correct assumption? // if decreasing the imbalance makes the score lower than 0, the node will be // removed from the list when calling `L::on_decrease`, which is not expected. - // Instead, we call `L::on_update` to set the score as 0. + // Instead, we call `L::on_update` to set the score as 0. The node will be + // removed when `on_*_removed` is called. if current_score.saturating_sub(imbalance) == 0 { let _ = L::on_update(who, 0).defensive_proof( "staker exists in the list, otherwise returned earlier.", @@ -180,7 +181,7 @@ impl OnStakingUpdate> for Pallet { // Note: it is assumed that who's staking state is updated *before* this method is called. fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { if let Ok(stake) = T::Staking::stake(who) { - let voter_weight = Self::to_vote(stake.active); // TODO(gpestana): or use `active_vote_of`? + let voter_weight = Self::to_vote(stake.active); match T::Staking::status(who).defensive_unwrap_or(StakerStatus::Idle) { StakerStatus::Nominator(nominations) => { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 10703ec23fe6..3997fd7fe1ba 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -122,12 +122,12 @@ impl Pallet { /// Untracked stake is stake that hasn't been propagated to `T::EventListeners` /// and that may be eventually propagated by calling [`Self::maybe_settled_untracked_stake`]. /// - /// The stake buffered under [`UntrackedStake`] corresponds to the *latest* up to date stake of - /// a ledger that has untracked stake. + /// The stake buffered under [`UntrackedStake`] corresponds to the *latest* stake to have been + /// propagated to `T::EventListeners` of a ledger with untracked stake. pub(crate) fn add_untracked_stake(who: &T::AccountId, stake: Stake>) { UntrackedStake::::mutate(who, |maybe_prev_stake| { // if the stash already has untracked stake, do not update it. Wa want to keep the - // *latest* up to date stake in storage. + // *oldest* up to date stake in storage. if maybe_prev_stake.is_none() { *maybe_prev_stake = Some(stake); } @@ -137,7 +137,7 @@ impl Pallet { /// Tries to settle untracked rewards buffered in [`UntrackedStake`] by caling into /// [`sp_staking::OnStakingUpdate::on_stake_update`] to propagate the untracked stake. /// - /// Returns the untracked rewards that have been setted, if any. + /// Returns the untracked rewards that have been settled, if any. pub(crate) fn maybe_settle_untracked_stake( who: &T::AccountId, ) -> Option>> @@ -146,7 +146,8 @@ impl Pallet { { UntrackedStake::::mutate_exists(who, |maybe_prev_stake| { if let Some(prev_stake) = maybe_prev_stake { - let ledger = Self::ledger(Stash(who.clone())).expect("if the stash has untracked stake, it exists; qed."); + let ledger = Self::ledger(Stash(who.clone())) + .expect("if the stash has untracked stake, it exists; qed."); // we kept track of the latest up to date stake of the ledger. Now we can use it to // settle the difference. @@ -661,7 +662,6 @@ impl Pallet { let mut total_stake: BalanceOf = Zero::zero(); exposures.into_iter().for_each(|(stash, exposure)| { total_stake = total_stake.saturating_add(exposure.total); - >::insert(new_planned_era, &stash, &exposure); let mut exposure_clipped = exposure; @@ -748,7 +748,7 @@ impl Pallet { // and finally, it removes controller from `Bonded` and staking ledger from `Ledger`, as // well as reward setting of the stash in `Payee`. We use the untracked event type since // both [`Self::do_remove_validator`] and [`Self::do_remove_nominator`] already propagate - // the events. + // the relevant events. StakingLedger::::kill::(&stash)?; frame_system::Pallet::::dec_consumers(&stash); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index b179d59fcec5..5c6d6daf6112 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -324,10 +324,10 @@ pub mod pallet { #[pallet::storage] pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; - /// Map with the latest tracked stake of accounts with untracked stake. + /// Map from all the stashes with untracked stakes and the latest sync stake between the ledger + /// and the event listeners. /// - /// Untracked stake is the ledger stake that hasn't been propagated to the - /// `T::EventListeners`. + /// Untracked stake is the ledger stake that hasn't been propagated to `T::EventListeners`. #[pallet::storage] pub type UntrackedStake = StorageMap<_, Blake2_128Concat, T::AccountId, Stake>>; diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index ec249ee24169..a6f38f78832c 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -23,7 +23,7 @@ use crate::currency_to_vote::CurrencyToVote; use codec::{FullCodec, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::RuntimeDebug; +use sp_core::{Decode, Encode, RuntimeDebug}; use sp_runtime::{DispatchError, DispatchResult, Saturating}; use sp_std::{collections::btree_map::BTreeMap, ops::Sub, vec::Vec}; @@ -69,16 +69,7 @@ pub enum StakerStatus { /// A struct that reflects stake that an account has in the staking system. Provides a set of /// methods to operate on it's properties. Aimed at making `StakingInterface` more concise. #[derive( - RuntimeDebug, - Clone, - Copy, - Eq, - PartialEq, - Default, - TypeInfo, - sp_core::Encode, - sp_core::Decode, - MaxEncodedLen, + RuntimeDebug, Clone, Copy, Eq, PartialEq, Default, TypeInfo, Encode, Decode, MaxEncodedLen, )] pub struct Stake { /// The total stake that `stash` has in the staking system. This includes the From cb393b9f9c450a9838ecf84be655fbcabf4e7f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 1 Nov 2023 19:03:58 +0000 Subject: [PATCH 003/133] Removes the untracked stake --- substrate/frame/staking/src/ledger.rs | 4 +- substrate/frame/staking/src/pallet/impls.rs | 59 +---------- substrate/frame/staking/src/pallet/mod.rs | 37 +------ substrate/frame/staking/src/tests.rs | 112 -------------------- 4 files changed, 4 insertions(+), 208 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 7b44fddd5996..56484766d5bf 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -42,8 +42,7 @@ use sp_staking::{ use sp_std::prelude::*; use crate::{ - BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, - UntrackedStake, STAKING_ID, + BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, }; impl Into>> for StakingLedger { @@ -253,7 +252,6 @@ impl StakingLedger { >::remove(&stash); >::remove(&stash); - >::remove(&stash); Ok(()) })? diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 3997fd7fe1ba..0367990ce737 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -117,53 +117,6 @@ impl Pallet { Self::slashable_balance_of_vote_weight(who, issuance) } - /// Registers untracked stake for a given account. - /// - /// Untracked stake is stake that hasn't been propagated to `T::EventListeners` - /// and that may be eventually propagated by calling [`Self::maybe_settled_untracked_stake`]. - /// - /// The stake buffered under [`UntrackedStake`] corresponds to the *latest* stake to have been - /// propagated to `T::EventListeners` of a ledger with untracked stake. - pub(crate) fn add_untracked_stake(who: &T::AccountId, stake: Stake>) { - UntrackedStake::::mutate(who, |maybe_prev_stake| { - // if the stash already has untracked stake, do not update it. Wa want to keep the - // *oldest* up to date stake in storage. - if maybe_prev_stake.is_none() { - *maybe_prev_stake = Some(stake); - } - }); - } - - /// Tries to settle untracked rewards buffered in [`UntrackedStake`] by caling into - /// [`sp_staking::OnStakingUpdate::on_stake_update`] to propagate the untracked stake. - /// - /// Returns the untracked rewards that have been settled, if any. - pub(crate) fn maybe_settle_untracked_stake( - who: &T::AccountId, - ) -> Option>> - where - OnUpdate: OnStakingUpdate>, - { - UntrackedStake::::mutate_exists(who, |maybe_prev_stake| { - if let Some(prev_stake) = maybe_prev_stake { - let ledger = Self::ledger(Stash(who.clone())) - .expect("if the stash has untracked stake, it exists; qed."); - - // we kept track of the latest up to date stake of the ledger. Now we can use it to - // settle the difference. - let prev_stake = prev_stake.clone(); - OnUpdate::on_stake_update(&ledger.stash, Some(prev_stake)); - - // deletes key. - *maybe_prev_stake = None; - - Some(prev_stake) - } else { - None - } - }) - } - pub(super) fn do_withdraw_unbonded( controller: &T::AccountId, num_slashing_spans: u32, @@ -185,9 +138,7 @@ impl Pallet { T::WeightInfo::withdraw_unbonded_kill(num_slashing_spans) } else { // This was the consequence of a partial unbond. just update the ledger and move - // on. But before, try to settle untracked stakes of the controller if they exist. - Self::maybe_settle_untracked_stake::(&ledger.stash); - + // on. ledger.update::()?; // This is only an update, so we use less overall weight. @@ -363,8 +314,6 @@ impl Pallet { RewardDestination::Stash => T::Currency::deposit_into_existing(stash, amount).ok(), RewardDestination::Staked => Self::ledger(Stash(stash.clone())) .and_then(|mut ledger| { - let prev_stake = ledger.clone().into(); - ledger.active += amount; ledger.total += amount; let r = T::Currency::deposit_into_existing(stash, amount).ok(); @@ -375,11 +324,7 @@ impl Pallet { let _ = match ::status(stash) .expect("stash is a staker; qed.") { - StakerStatus::Nominator(_) => { - ledger.update::()?; - Self::add_untracked_stake(&stash, prev_stake); - Ok(()) - }, + StakerStatus::Nominator(_) => ledger.update::(), StakerStatus::Validator => ledger.update::(), StakerStatus::Idle => Ok(()), }; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5c6d6daf6112..b282a5cbf75e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -36,7 +36,7 @@ use sp_runtime::{ ArithmeticError, Perbill, Percent, }; use sp_staking::{ - EraIndex, SessionIndex, Stake, + EraIndex, SessionIndex, StakingAccount::{self, Controller, Stash}, }; use sp_std::prelude::*; @@ -324,14 +324,6 @@ pub mod pallet { #[pallet::storage] pub type Ledger = StorageMap<_, Blake2_128Concat, T::AccountId, StakingLedger>; - /// Map from all the stashes with untracked stakes and the latest sync stake between the ledger - /// and the event listeners. - /// - /// Untracked stake is the ledger stake that hasn't been propagated to `T::EventListeners`. - #[pallet::storage] - pub type UntrackedStake = - StorageMap<_, Blake2_128Concat, T::AccountId, Stake>>; - /// Where the reward payment should be made. Keyed by stash. /// /// TWOX-NOTE: SAFE since `AccountId` is a secure hash. @@ -774,8 +766,6 @@ pub mod pallet { CommissionTooLow, /// Some bound is not met. BoundNotMet, - /// No untracked stake found for a given stash. - NoUntrackedStake, } #[pallet::hooks] @@ -1021,8 +1011,6 @@ pub mod pallet { .map_err(|_| Error::::NoMoreChunks)?; }; // NOTE: ledger must be updated prior to calling `Self::weight_of`. - // But before, try to settle untracked stakes of the controller if they exist. - Self::maybe_settle_untracked_stake::(&ledger.stash); ledger.update::()?; @@ -1183,10 +1171,6 @@ pub mod pallet { suppressed: false, }; - // Try to settle untracked stakes of the stash if they exist, before updating the - // nominator's state. - Self::maybe_settle_untracked_stake::(&stash); - Self::do_remove_validator(stash); Self::do_add_nominator(stash, nominations); Ok(()) @@ -1531,9 +1515,6 @@ pub mod pallet { let final_unlocking = ledger.unlocking.len(); // NOTE: ledger must be updated prior to calling `Self::weight_of`. - // But before, try to settle untracked stakes of the controller if they exist. - Self::maybe_settle_untracked_stake::(&ledger.stash); - ledger.update::()?; if T::VoterList::contains(&stash) { let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); @@ -1795,22 +1776,6 @@ pub mod pallet { MinCommission::::put(new); Ok(()) } - - /// Settles a untracked stake, if it exists. - #[pallet::call_index(26)] - #[pallet::weight(T::WeightInfo::settle_untracked_stake())] - pub fn settle_untracked_stake( - origin: OriginFor, - stash: T::AccountId, - ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - - if Self::maybe_settle_untracked_stake::(&stash).is_none() { - Err(Error::::NoUntrackedStake.into()) - } else { - Ok(Pays::No.into()) - } - } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f61205d94442..10d866048ad3 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -232,38 +232,6 @@ fn basic_setup_works() { }); } -#[test] -fn untracked_rewards_works() { - ExtBuilder::default().nominate(true).build_and_execute(|| { - assert_eq!(UntrackedStake::::iter_keys().count(), 0); - - let stake = |active: BalanceOf, total: BalanceOf| sp_staking::Stake::< - BalanceOf, - > { - total, - active, - }; - - Pallet::::add_untracked_stake(&11, stake(10, 10)); - Pallet::::add_untracked_stake(&11, stake(20, 20)); - Pallet::::add_untracked_stake(&21, stake(10, 10)); - - assert_eq!(UntrackedStake::::iter_keys().count(), 2); - // keep inital `previous_stake` after multiple calls to `add_untracked_rewards. - assert_eq!(UntrackedStake::::get(&11), Some(stake(10, 10))); - assert_eq!(UntrackedStake::::get(&21), Some(stake(10, 10))); - - // stash 101 doesn't have untracked rewards. - assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&101), None); - assert_eq!(UntrackedStake::::iter_keys().count(), 2); - - assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&11), Some(stake(10, 10))); - assert_eq!(UntrackedStake::::iter_keys().count(), 1); - assert_eq!(Pallet::::maybe_settle_untracked_stake::<()>(&21), Some(stake(10, 10))); - assert_eq!(UntrackedStake::::iter_keys().count(), 0); - }) -} - #[test] fn change_controller_works() { ExtBuilder::default().build_and_execute(|| { @@ -4591,86 +4559,6 @@ mod sorted_list_provider_integration { assert_eq!(TargetBagsList::contains(&42), false); }) } - - #[test] - fn payouts_with_untracked_stake_work() { - ExtBuilder::default().build_and_execute(|| { - Balances::make_free_balance_be(&42, 100); - - // bond and nominate (11, 21) with stash 42. - assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 50, Default::default())); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); - - // nominator 42 compounds rewards. - assert_ok!(Staking::set_payee(RuntimeOrigin::signed(42), RewardDestination::Staked)); - assert_eq!(Balances::free_balance(42), 100); - - let (active, voter_score, _) = staker_state(42); - assert_eq!(active, voter_score); - - mock::start_active_era(1); - // reward validator 11 and its nominators. - Staking::reward_by_ids(vec![(11, 10)]); - - mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(11), 11, 1)); - - // the rewards have not been propagated to the voter and target lists, although they - // should be reflected in the staking ledger. - let (active, voter_score, _) = staker_state(42); - assert!(active > voter_score); - - assert!(>::get(42).is_some()); - - // from the targets PoV, the rewards earned by the nominator haven't yet been added to - // the score. we buffer the target score of both validators to compare after the - // untracked rewards have been settled. - let (_, _, target_score_11_deficit) = staker_state(11); - - // changing the nominations will trigger the untracked stake to be settled. - assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11])); - - assert!(>::get(42).is_none()); - - // thus the nominator's active and voter score is now the same. - let (active, voter_score, _) = staker_state(42); - assert_eq!(active, voter_score); - - // target score of validators is larger, after the untracked staked is settled. - let (_, _, target_score_11_settled) = staker_state(11); - assert!(target_score_11_settled > target_score_11_deficit); - }) - } - - #[test] - fn untracked_stake_settle_extrinsic_works() { - ExtBuilder::default().build_and_execute(|| { - Balances::make_free_balance_be(&42, 100); - - // bond and nominate (11, 21) with stash 42. - assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 10, Default::default())); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); - - assert!(>::get(42).is_none()); - - let (_, _, target_11) = staker_state(11); - let (_, _, target_21) = staker_state(21); - - // add untracked stake to nominator 42 manually. - >::insert(&42, Stake { total: 5, active: 5 }); - - assert_ok!(Staking::settle_untracked_stake(RuntimeOrigin::signed(42), 42)); - assert!(>::get(42).is_none()); - - let (_, _, target_11_settled) = staker_state(11); - let (_, _, target_21_settled) = staker_state(21); - - // the settled target score of the validatorsis larger by the amount of untracked stake - // of their nominator 42. - assert!(target_11_settled == target_11 + 5); - assert!(target_21_settled == target_21 + 5); - }) - } } mod election_data_provider { From b9d3f64676162f86abf58755864759718c87838f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 7 Nov 2023 14:33:55 +0000 Subject: [PATCH 004/133] Removes completely the untracked stake code --- substrate/frame/stake-tracker/src/lib.rs | 6 ++-- substrate/frame/stake-tracker/src/mock.rs | 1 + substrate/frame/staking/src/ledger.rs | 32 +++++++++------------ substrate/frame/staking/src/lib.rs | 4 --- substrate/frame/staking/src/pallet/impls.rs | 19 ++++-------- substrate/frame/staking/src/pallet/mod.rs | 8 +++--- substrate/frame/staking/src/slashing.rs | 2 +- substrate/frame/staking/src/tests.rs | 8 +++--- 8 files changed, 32 insertions(+), 48 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index 0d3a9995ede4..58a8dc27681d 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -33,7 +33,7 @@ //! //! The [`OnStakingUpdate`] implementation aims at achieving the following goals: //! -//! * The [`Config::TargetList`] keeps a *lazily* sorted list of validators, sorted by approvals +//! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals //! (which include self-vote and nominations). //! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new @@ -100,14 +100,14 @@ pub mod pallet { /// The staking interface. type Staking: StakingInterface; - /// Something that provides a best-effort sorted list of voters. + /// Something that provides a *best-effort* sorted list of voters. /// /// To keep the load off the chain as much as possible, changes made to the staked amount /// via rewards and slashes are dropped and thus need to be manually updated through /// extrinsics. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. type VoterList: SortedListProvider; - /// Something that provides a best-effort sorted list of targets. + /// Something that provides an *always* sorted list of targets. /// /// Note that while at the time of nomination all targets are checked to be real /// validators, they can chill at any point, and their approval stakes will still be diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index 08f940beec35..cdb050f6f506 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -72,6 +72,7 @@ impl pallet_balances::Config for Test { type FreezeIdentifier = (); type MaxHolds = (); type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); type MaxFreezes = (); } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 06f2e936703c..d50b3d1482fc 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -165,10 +165,7 @@ impl StakingLedger { /// /// Note: To ensure lock consistency, all the [`Ledger`] storage updates should be made through /// this helper function. - pub(crate) fn update(self) -> Result<(), Error> - where - OnUpdate: OnStakingUpdate>, - { + pub(crate) fn update(self) -> Result<(), Error> { if !>::contains_key(&self.stash) { return Err(Error::::NotStash) } @@ -187,7 +184,10 @@ impl StakingLedger { T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); Ledger::::insert(controller, &self); - OnUpdate::on_stake_update(&self.stash, prev_stake); + >>::on_stake_update( + &self.stash, + prev_stake, + ); Ok(()) } @@ -195,19 +195,13 @@ impl StakingLedger { /// Bonds a ledger. /// /// It sets the reward preferences for the bonded stash. - pub(crate) fn bond( - self, - payee: RewardDestination, - ) -> Result<(), Error> - where - OnUpdate: OnStakingUpdate>, - { + pub(crate) fn bond(self, payee: RewardDestination) -> Result<(), Error> { if >::contains_key(&self.stash) { Err(Error::::AlreadyBonded) } else { >::insert(&self.stash, payee); >::insert(&self.stash, &self.stash); - self.update::() + self.update() } } @@ -223,18 +217,18 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. - pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> - where - OnUpdate: OnStakingUpdate>, - { + pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; // call on validator remove or on nominator remove. match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { - StakerStatus::Validator => OnUpdate::on_validator_remove(stash), + StakerStatus::Validator => , + >>::on_validator_remove(stash), StakerStatus::Nominator(_) => { let nominations = crate::Pallet::::nominations(stash).unwrap_or_default(); - OnUpdate::on_nominator_remove(stash, nominations) + >>::on_nominator_remove(stash, nominations) }, StakerStatus::Idle => (), }; diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index c638218eef42..9e4697e845b6 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -334,10 +334,6 @@ pub use pallet::{pallet::*, UseNominatorsAndValidatorsMap, UseValidatorsMap}; pub(crate) const STAKING_ID: LockIdentifier = *b"staking "; pub(crate) const LOG_TARGET: &str = "runtime::staking"; -// Marker type to pass as type [`sp_staking::OnStakingUpdate`] that does nothing, i.e. it does not -// propagate the event to any event listener. -pub(crate) type UntrackedEvent = (); - // syntactic sugar for logging. #[macro_export] macro_rules! log { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 516185276c62..c60aec6389c6 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -51,8 +51,7 @@ use crate::{ election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakerStatus, StakingLedger, UntrackedEvent, - ValidatorPrefs, + RewardDestination, SessionInterface, StakerStatus, StakingLedger, ValidatorPrefs, }; use super::pallet::*; @@ -140,7 +139,7 @@ impl Pallet { } else { // This was the consequence of a partial unbond. just update the ledger and move // on. - ledger.update::()?; + ledger.update()?; // This is only an update, so we use less overall weight. T::WeightInfo::withdraw_unbonded_update(num_slashing_spans) @@ -232,7 +231,7 @@ impl Pallet { })?; // Input data seems good, no errors allowed after this point - ledger.update::()?; + ledger.update()?; // Get Era reward points. It has TOTAL and INDIVIDUAL // Find the fraction of the era reward that belongs to the validator @@ -348,14 +347,10 @@ impl Pallet { ledger.total += amount; let r = T::Currency::deposit_into_existing(stash, amount).ok(); - // if it's a nominator, the ledger update event should not be propagated due to - // the complexity of updating the stake of all (potentially) exposed validators - // to this nominator and the cascading effects that may occur. let _ = match ::status(stash) .expect("stash is a staker; qed.") { - StakerStatus::Nominator(_) => ledger.update::(), - StakerStatus::Validator => ledger.update::(), + StakerStatus::Nominator(_) | StakerStatus::Validator => ledger.update(), StakerStatus::Idle => Ok(()), }; @@ -714,10 +709,8 @@ impl Pallet { Self::do_remove_nominator(&stash); // and finally, it removes controller from `Bonded` and staking ledger from `Ledger`, as - // well as reward setting of the stash in `Payee`. We use the untracked event type since - // both [`Self::do_remove_validator`] and [`Self::do_remove_nominator`] already propagate - // the relevant events. - StakingLedger::::kill::(&stash)?; + // well as reward setting of the stash in `Payee`. + StakingLedger::::kill(&stash)?; frame_system::Pallet::::dec_consumers(&stash); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 239d2e73b69a..bdb0be55ed89 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -939,7 +939,7 @@ pub mod pallet { // You're auto-bonded forever, here. We might improve this by only bonding when // you actually validate/nominate and remove once you unbond __everything__. - ledger.bond::(payee)?; + ledger.bond(payee)?; Ok(()) } @@ -979,7 +979,7 @@ pub mod pallet { Error::::InsufficientBond ); - ledger.update::()?; + ledger.update()?; Self::deposit_event(Event::::Bonded { stash, amount: extra }); } @@ -1076,7 +1076,7 @@ pub mod pallet { }; // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update::()?; + ledger.update()?; // update this staker in the sorted list, if they exist in it. if T::VoterList::contains(&stash) { @@ -1579,7 +1579,7 @@ pub mod pallet { let final_unlocking = ledger.unlocking.len(); // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update::()?; + ledger.update()?; if T::VoterList::contains(&stash) { let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); } diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index 6fe8cc29727f..0d84d503733e 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -615,7 +615,7 @@ pub fn do_slash( } let _ = ledger - .update::() + .update() .defensive_proof("ledger fetched from storage so it exists in storage; qed."); // trigger the event diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 92bf1014db2c..6f607cf4dc23 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1817,7 +1817,7 @@ fn reap_stash_works() { // no easy way to cause an account to go below ED, we tweak their staking ledger // instead. let ledger = StakingLedger::::new(11, 5); - assert_ok!(ledger.update::<::EventListeners>()); + assert_ok!(ledger.update()); // reap-able assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); @@ -6932,17 +6932,17 @@ mod ledger { let mut ledger: StakingLedger = StakingLedger::default_from(42); let reward_dest = RewardDestination::Account(10); - assert_ok!(ledger.clone().bond::<()>(reward_dest)); + assert_ok!(ledger.clone().bond(reward_dest)); assert!(StakingLedger::::is_bonded(StakingAccount::Stash(42))); assert!(>::get(&42).is_some()); assert_eq!(>::get(&42), reward_dest); // cannot bond again. - assert!(ledger.clone().bond::<()>(reward_dest).is_err()); + assert!(ledger.clone().bond(reward_dest).is_err()); // once bonded, update works as expected. ledger.legacy_claimed_rewards = bounded_vec![1]; - assert_ok!(ledger.update::()); + assert_ok!(ledger.update()); }) } From b42a160b3e9c3416eabfe7292dd6dd0a5abaf533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 7 Nov 2023 14:57:36 +0000 Subject: [PATCH 005/133] Fixes to review comments --- substrate/frame/stake-tracker/src/lib.rs | 11 ++--------- substrate/frame/stake-tracker/src/mock.rs | 6 ------ substrate/frame/staking/src/pallet/impls.rs | 4 ++-- substrate/frame/staking/src/pallet/mod.rs | 2 -- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index 58a8dc27681d..c09217af0a7e 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -55,7 +55,7 @@ pub use pallet::*; use frame_election_provider_support::SortedListProvider; -use frame_support::traits::{Currency, Defensive}; +use frame_support::traits::{fungible::Inspect as FnInspect, Defensive}; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, StakerStatus, StakingInterface, }; @@ -95,7 +95,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - type Currency: Currency>; + type Currency: FnInspect>; /// The staking interface. type Staking: StakingInterface; @@ -108,11 +108,6 @@ pub mod pallet { type VoterList: SortedListProvider; /// Something that provides an *always* sorted list of targets. - /// - /// Note that while at the time of nomination all targets are checked to be real - /// validators, they can chill at any point, and their approval stakes will still be - /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE - /// VALIDATOR. type TargetList: SortedListProvider; } @@ -341,7 +336,5 @@ impl OnStakingUpdate> for Pallet { _slashed_unlocking: &BTreeMap>, _slashed_total: BalanceOf, ) { - #[cfg(any(std, no_std))] - frame_support::defensive!("unexpected call to OnStakingUpdate::on_slash"); } } diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index cdb050f6f506..812737383138 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -48,13 +48,7 @@ parameter_types! { #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { type Block = Block; - type BaseCallFilter = frame_support::traits::Everything; type BlockHashCount = ConstU32<10>; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type PalletInfo = PalletInfo; - type OnSetCode = (); type AccountData = pallet_balances::AccountData; } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index c60aec6389c6..c9e004aba87b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -985,7 +985,6 @@ impl Pallet { >>::on_nominator_add( who, ); - Nominators::::insert(who, nominations); } else { // update nominations. let prev_nominations = Self::nominations(who).unwrap_or_default(); @@ -994,9 +993,10 @@ impl Pallet { who, prev_nominations, ); - Nominators::::insert(who, nominations.clone()); } + Nominators::::insert(who, nominations); + debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::count() diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index bdb0be55ed89..7d8961498ab8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -272,8 +272,6 @@ pub mod pallet { /// Something that listens to staking updates and performs actions based on the data it /// receives. - /// - /// WARNING: this only reports slashing events for the time being. type EventListeners: sp_staking::OnStakingUpdate>; /// Some parameters of the benchmarking. From 086a1832df068a8319a9146f478859aa0c904932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 7 Nov 2023 23:28:55 +0000 Subject: [PATCH 006/133] more improvements --- substrate/frame/stake-tracker/src/lib.rs | 24 ++++++++++++------------ substrate/frame/staking/src/weights.rs | 10 ---------- substrate/primitives/staking/src/lib.rs | 4 +--- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index c09217af0a7e..e98b644e4353 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -55,7 +55,10 @@ pub use pallet::*; use frame_election_provider_support::SortedListProvider; -use frame_support::traits::{fungible::Inspect as FnInspect, Defensive}; +use frame_support::{ + defensive, + traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, +}; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, StakerStatus, StakingInterface, }; @@ -137,6 +140,7 @@ pub mod pallet { // there may be nominators who nominate a non-existant validator. if that's the case, // move on. if !L::contains(who) { + defensive!("`update_score` on non-existant staker {}", who); return } @@ -154,14 +158,8 @@ pub mod pallet { // removed from the list when calling `L::on_decrease`, which is not expected. // Instead, we call `L::on_update` to set the score as 0. The node will be // removed when `on_*_removed` is called. - if current_score.saturating_sub(imbalance) == 0 { - let _ = L::on_update(who, 0).defensive_proof( - "staker exists in the list, otherwise returned earlier.", - ); - } else { - let _ = L::on_decrease(who, imbalance) - .defensive_proof("staker exists in the list as per the check above."); - } + let _ = L::on_update(who, current_score.defensive_saturating_sub(imbalance)) + .defensive_proof("staker exists in the list as per the check above."); }, } } @@ -175,10 +173,12 @@ impl OnStakingUpdate> for Pallet { // // Note: it is assumed that who's staking state is updated *before* this method is called. fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { - if let Ok(stake) = T::Staking::stake(who) { + if let Ok(stake) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( + "staker should exist when calling on_stake_update and have a valid status", + ) { let voter_weight = Self::to_vote(stake.active); - match T::Staking::status(who).defensive_unwrap_or(StakerStatus::Idle) { + match T::Staking::status(who).expect("status checked above; qed.") { StakerStatus::Nominator(nominations) => { let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( "staker should exist in VoterList, as per the contract \ @@ -238,7 +238,7 @@ impl OnStakingUpdate> for Pallet { // If who is a nominator, update the vote weight of the nominations if they exist. Note: // this will update the score of up to `T::MaxNominations` validators. - match T::Staking::status(who) { + match T::Staking::status(who).defensive() { Ok(StakerStatus::Nominator(nominations)) => for t in nominations { Self::update_score::( diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 2c12d4c2a9d4..ad6dbccde9f8 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -79,7 +79,6 @@ pub trait WeightInfo { fn chill_other() -> Weight; fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; - fn settle_untracked_stake() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -807,10 +806,6 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(3_352_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } - - fn settle_untracked_stake() -> Weight { - todo!() - } } // For backwards compatibility and tests. @@ -1537,9 +1532,4 @@ impl WeightInfo for () { Weight::from_parts(3_352_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - - - fn settle_untracked_stake() -> Weight { - todo!() - } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 49d79d6aa27a..c2ac5ae004b1 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -72,9 +72,7 @@ pub enum StakerStatus { /// A struct that reflects stake that an account has in the staking system. Provides a set of /// methods to operate on it's properties. Aimed at making `StakingInterface` more concise. -#[derive( - RuntimeDebug, Clone, Copy, Eq, PartialEq, Default, TypeInfo, Encode, Decode, MaxEncodedLen, -)] +#[derive(RuntimeDebug, Clone, Copy, Eq, PartialEq, Default)] pub struct Stake { /// The total stake that `stash` has in the staking system. This includes the /// `active` stake, and any funds currently in the process of unbonding via From 7b89e06b4384718d41f7782e8f41da5628ac3a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 7 Nov 2023 23:39:23 +0000 Subject: [PATCH 007/133] fixes comments --- substrate/frame/staking/src/pallet/mod.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7d8961498ab8..7c4851751659 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -235,11 +235,8 @@ pub mod pallet { /// Invariant: what comes out of this list will always be a nominator. type VoterList: SortedListProvider; - /// WIP: This is a noop as of now, the actual business logic that's described below is going - /// to be introduced in a follow-up PR. - /// - /// Something that provides a best-effort sorted list of targets aka electable validators, - /// used for NPoS election. + /// Something that provides a sorted list of targets aka electable validators, used for NPoS + /// election. /// /// The changes to the approval stake of each validator are reported to this. This means any /// change to: @@ -247,14 +244,9 @@ pub mod pallet { /// 2. The targets of any nominator /// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc) /// - /// Unlike `VoterList`, the values in this list are always kept up to date with reward and - /// slash as well, and thus represent the accurate approval stake of all account being + /// Unlike `VoterList`, the values in this list are always kept up to date with rewards, + /// slashes, etc, and thus represent the accurate approval stake of all account being /// nominated by nominators. - /// - /// Note that while at the time of nomination, all targets are checked to be real - /// validators, they can chill at any point, and their approval stakes will still be - /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE - /// VALIDATOR. type TargetList: SortedListProvider; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can From ad1c49d3fb9adada339b9a34d29f91d3017376b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 8 Nov 2023 10:45:32 +0000 Subject: [PATCH 008/133] nits and more tests --- substrate/frame/stake-tracker/src/lib.rs | 6 +- substrate/frame/stake-tracker/src/mock.rs | 5 +- substrate/frame/stake-tracker/src/tests.rs | 217 +++++++++++++-------- 3 files changed, 136 insertions(+), 92 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index e98b644e4353..4a193fc3c57a 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -140,7 +140,7 @@ pub mod pallet { // there may be nominators who nominate a non-existant validator. if that's the case, // move on. if !L::contains(who) { - defensive!("`update_score` on non-existant staker {}", who); + defensive!("`update_score` on non-existant staker", who); return } @@ -157,9 +157,9 @@ pub mod pallet { // if decreasing the imbalance makes the score lower than 0, the node will be // removed from the list when calling `L::on_decrease`, which is not expected. // Instead, we call `L::on_update` to set the score as 0. The node will be - // removed when `on_*_removed` is called. + // removed when `on_*_remove` is called. let _ = L::on_update(who, current_score.defensive_saturating_sub(imbalance)) - .defensive_proof("staker exists in the list as per the check above."); + .expect("staker exists in the list as per the check above; qed."); }, } } diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index 812737383138..6cc00f3b299d 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -275,10 +275,7 @@ pub(crate) fn add_nominator(who: AccountId, stake: Balance) { } pub(crate) fn stake_of(who: AccountId) -> Option> { - match StakingMock::stake(&who) { - Ok(stake) => Some(stake), - Err(_) => None, - } + StakingMock::stake(&who).ok() } pub(crate) fn add_nominator_with_nominations( diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 6b8e25a9bf00..77708fa1fd2e 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -17,7 +17,7 @@ #![cfg(test)] -use crate::mock::*; +use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::SortedListProvider; use sp_staking::Stake; @@ -42,103 +42,150 @@ fn setup_works() { } #[test] -fn staking_interface_works() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(TestNominators::get().iter().count(), 0); - assert_eq!(TestValidators::get().iter().count(), 0); - - add_nominator(1, 100); - let n = TestNominators::get(); - assert_eq!(n.get(&1).unwrap().0, Stake { active: 100u64, total: 100u64 }); - - add_validator(2, 200); - let v = TestValidators::get(); - assert_eq!(v.get(&2).copied().unwrap(), Stake { active: 200u64, total: 200u64 }); - }) -} +fn update_score_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::get_score(&1), Ok(100)); -#[test] -fn on_add_stakers_works() { - ExtBuilder::default().build_and_execute(|| { - add_nominator(1, 100); - assert_eq!(TargetBagsList::count(), 0); - assert_eq!(VoterBagsList::count(), 1); - assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); + crate::Pallet::::update_score::(&1, StakeImbalance::Negative(10)); + assert_eq!(VoterBagsList::get_score(&1), Ok(90)); - add_validator(10, 200); - assert_eq!(VoterBagsList::count(), 2); // 1x nominator + 1x validator - assert_eq!(TargetBagsList::count(), 1); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); - }) -} + crate::Pallet::::update_score::(&1, StakeImbalance::Positive(100)); + assert_eq!(VoterBagsList::get_score(&1), Ok(190)); -#[test] -fn on_update_stake_works() { - ExtBuilder::default().build_and_execute(|| { - add_nominator(1, 100); - assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); - update_stake(1, 200, stake_of(1)); - assert_eq!(VoterBagsList::get_score(&1).unwrap(), 200); - - add_validator(10, 100); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); - update_stake(10, 200, stake_of(10)); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + // when score decreases to 0, the node is not removed automatically and its balance is 0. + let current_score = VoterBagsList::get_score(&1).unwrap(); + crate::Pallet::::update_score::( + &1, + StakeImbalance::Negative(current_score), + ); + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::get_score(&1), Ok(0)); }) } #[test] -fn on_remove_stakers_works() { +#[should_panic] +fn update_score_defensive_cases_work() { ExtBuilder::default().build_and_execute(|| { - add_nominator(1, 100); - assert!(VoterBagsList::contains(&1)); - remove_staker(1); assert!(!VoterBagsList::contains(&1)); + crate::Pallet::::update_score::(&1, StakeImbalance::Positive(100)); + }); - add_validator(10, 100); - assert!(TargetBagsList::contains(&10)); - remove_staker(10); - assert!(!TargetBagsList::contains(&10)); - }) -} - -#[test] -fn on_remove_stakers_with_nominations_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); - assert!(VoterBagsList::contains(&1)); - assert_eq!(VoterBagsList::get_score(&1), Ok(100)); - assert_eq!(TargetBagsList::get_score(&10), Ok(300)); - - // remove nominator deletes node from voter list and updates the stake of its nominations. - remove_staker(1); - assert!(!VoterBagsList::contains(&1)); - assert_eq!(TargetBagsList::get_score(&10), Ok(200)); + // if updating makes the score falling below 0, final node's score is saturated to 0. + crate::Pallet::::update_score::(&1, StakeImbalance::Negative(100)); + assert_eq!(VoterBagsList::get_score(&1), Ok(0)); }) } -#[test] -fn on_nominator_update_works() { - ExtBuilder::default().populate_lists().build_and_execute(|| { - assert_eq!(get_scores::(), vec![(10, 100), (11, 100), (1, 100), (2, 100)]); - assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); - - add_validator(20, 50); - // removes nomination from 10 and adds nomination to new validator, 20. - update_nominations_of(2, vec![11, 20]); - - // new voter (validator) 2 with 100 stake. note that the voter score is not updated - // automatically. - assert_eq!( - get_scores::(), - vec![(10, 100), (11, 100), (1, 100), (2, 100), (20, 50)] - ); - - // target list has been updated: - // -100 score for 10 - // +100 score for 11 - // +100 score for 20 - assert_eq!(get_scores::(), vec![(10, 200), (11, 200), (20, 150)]); - }) +mod staking_integration { + use super::*; + + #[test] + fn staking_interface_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(TestNominators::get().iter().count(), 0); + assert_eq!(TestValidators::get().iter().count(), 0); + + add_nominator(1, 100); + let n = TestNominators::get(); + assert_eq!(n.get(&1).unwrap().0, Stake { active: 100u64, total: 100u64 }); + + add_validator(2, 200); + let v = TestValidators::get(); + assert_eq!(v.get(&2).copied().unwrap(), Stake { active: 200u64, total: 200u64 }); + }) + } + + #[test] + fn on_add_stakers_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert_eq!(TargetBagsList::count(), 0); + assert_eq!(VoterBagsList::count(), 1); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); + + add_validator(10, 200); + assert_eq!(VoterBagsList::count(), 2); // 1x nominator + 1x validator + assert_eq!(TargetBagsList::count(), 1); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + }) + } + + #[test] + fn on_update_stake_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 100); + update_stake(1, 200, stake_of(1)); + assert_eq!(VoterBagsList::get_score(&1).unwrap(), 200); + + add_validator(10, 100); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); + update_stake(10, 200, stake_of(10)); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + }) + } + + #[test] + fn on_remove_stakers_works() { + ExtBuilder::default().build_and_execute(|| { + add_nominator(1, 100); + assert!(VoterBagsList::contains(&1)); + remove_staker(1); + assert!(!VoterBagsList::contains(&1)); + + add_validator(10, 100); + assert!(TargetBagsList::contains(&10)); + remove_staker(10); + assert!(!TargetBagsList::contains(&10)); + }) + } + + #[test] + fn on_remove_stakers_with_nominations_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::get_score(&1), Ok(100)); + assert_eq!(TargetBagsList::get_score(&10), Ok(300)); + + // remove nominator deletes node from voter list and updates the stake of its + // nominations. + remove_staker(1); + assert!(!VoterBagsList::contains(&1)); + assert_eq!(TargetBagsList::get_score(&10), Ok(200)); + }) + } + + #[test] + fn on_nominator_update_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert_eq!( + get_scores::(), + vec![(10, 100), (11, 100), (1, 100), (2, 100)] + ); + assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + + add_validator(20, 50); + // removes nomination from 10 and adds nomination to new validator, 20. + update_nominations_of(2, vec![11, 20]); + + // new voter (validator) 2 with 100 stake. note that the voter score is not updated + // automatically. + assert_eq!( + get_scores::(), + vec![(10, 100), (11, 100), (1, 100), (2, 100), (20, 50)] + ); + + // target list has been updated: + // -100 score for 10 + // +100 score for 11 + // +100 score for 20 + assert_eq!(get_scores::(), vec![(10, 200), (11, 200), (20, 150)]); + }) + } } From 2c2256dd4b33bcc0f96e45305408fa76ac79f8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 8 Nov 2023 12:25:52 +0000 Subject: [PATCH 009/133] nits and more tests --- substrate/frame/stake-tracker/src/lib.rs | 23 ++++--- substrate/frame/stake-tracker/src/tests.rs | 77 ++++++++++++++++++++-- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index 4a193fc3c57a..3b9866363844 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -151,15 +151,20 @@ pub mod pallet { ); }, StakeImbalance::Negative(imbalance) => { - let current_score = L::get_score(who) - .expect("staker exists in the list as per the check above; qed."); - - // if decreasing the imbalance makes the score lower than 0, the node will be - // removed from the list when calling `L::on_decrease`, which is not expected. - // Instead, we call `L::on_update` to set the score as 0. The node will be - // removed when `on_*_remove` is called. - let _ = L::on_update(who, current_score.defensive_saturating_sub(imbalance)) - .expect("staker exists in the list as per the check above; qed."); + if let Ok(current_score) = L::get_score(who) { + // if decreasing the imbalance makes the score lower than 0, the node will + // be removed from the list when calling `L::on_decrease`, which is not + // expected. Instead, we call `L::on_update` to set the new score that + // defensively saturates to 0. The node will be removed when `on_*_remove` + // is called. + let _ = + L::on_update(who, current_score.defensive_saturating_sub(imbalance)) + .defensive_proof( + "staker exists in the list as per the check above; qed.", + ); + } else { + defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); + } }, } } diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 77708fa1fd2e..5a527ca35e3b 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -20,7 +20,11 @@ use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::SortedListProvider; -use sp_staking::Stake; +use sp_staking::{OnStakingUpdate, Stake}; + +// keeping tests clean. +type A = AccountId; +type B = Balance; #[test] fn setup_works() { @@ -65,21 +69,84 @@ fn update_score_works() { } #[test] -#[should_panic] -fn update_score_defensive_cases_work() { +#[should_panic = "Defensive failure has been triggered!: \"`update_score` on non-existant staker\": 1"] +fn update_score_non_existing_defensive_work() { ExtBuilder::default().build_and_execute(|| { assert!(!VoterBagsList::contains(&1)); + // not expected to update score of a non-existing staker. crate::Pallet::::update_score::(&1, StakeImbalance::Positive(100)); }); +} +#[test] +#[should_panic] +fn update_score_below_zero_defensive_work() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(VoterBagsList::contains(&1)); - // if updating makes the score falling below 0, final node's score is saturated to 0. - crate::Pallet::::update_score::(&1, StakeImbalance::Negative(100)); + assert_eq!(VoterBagsList::get_score(&1), Ok(100)); + // updating the score below 0 is unexpected and saturates to 0. + crate::Pallet::::update_score::(&1, StakeImbalance::Negative(500)); + // TODO(gpestana): how to assert invariant after defensive fail. assert_eq!(VoterBagsList::get_score(&1), Ok(0)); }) } +#[test] +fn on_nominator_add_works() { + ExtBuilder::default().build_and_execute(|| { + let n = TestNominators::get(); + assert!(!VoterBagsList::contains(&5)); + assert_eq!(n.get(&5), None); + + // add 5 as staker. + TestNominators::mutate(|n| { + n.insert(5, Default::default()); + }); + + >::on_nominator_add(&5); + assert!(VoterBagsList::contains(&5)); + }) +} + +#[test] +fn on_validator_add_works() { + ExtBuilder::default().build_and_execute(|| { + let n = TestNominators::get(); + let v = TestValidators::get(); + assert!(!VoterBagsList::contains(&5)); + assert!(!TargetBagsList::contains(&5)); + assert!(n.get(&5).is_none() && v.get(&5).is_none()); + + // add 5 as staker (target and voter). + TestNominators::mutate(|n| { + n.insert(5, Default::default()); + }); + TestValidators::mutate(|n| { + n.insert(5, Default::default()); + }); + }) +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: Duplicate: \"staker should not exist in VoterList, as per the contract with staking.\""] +fn on_nominator_add_already_exists_defensive_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + // voter already exists in the list, trying to emit `on_add_nominator` again will fail. + assert!(VoterBagsList::contains(&1)); + >::on_nominator_add(&1); + }); +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: Duplicate: \"staker should not exist in TargetList, as per the contract with staking.\""] +fn on_validator_add_already_exists_defensive_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + // validator already exists in the list, trying to emit `on_add_validator` again will fail. + assert!(TargetBagsList::contains(&10)); + >::on_validator_add(&10); + }); +} + mod staking_integration { use super::*; From e2babf5e5bddf76d72e1aec992e308d1144c91ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 8 Nov 2023 13:23:48 +0000 Subject: [PATCH 010/133] Adds more tests --- substrate/frame/stake-tracker/src/tests.rs | 80 ++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 5a527ca35e3b..d4864375e214 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -20,7 +20,8 @@ use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::SortedListProvider; -use sp_staking::{OnStakingUpdate, Stake}; +use frame_support::assert_ok; +use sp_staking::{OnStakingUpdate, Stake, StakingInterface}; // keeping tests clean. type A = AccountId; @@ -70,7 +71,7 @@ fn update_score_works() { #[test] #[should_panic = "Defensive failure has been triggered!: \"`update_score` on non-existant staker\": 1"] -fn update_score_non_existing_defensive_work() { +fn update_score_non_existing_defensive_works() { ExtBuilder::default().build_and_execute(|| { assert!(!VoterBagsList::contains(&1)); // not expected to update score of a non-existing staker. @@ -80,17 +81,37 @@ fn update_score_non_existing_defensive_work() { #[test] #[should_panic] -fn update_score_below_zero_defensive_work() { +fn update_score_below_zero_defensive_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::get_score(&1), Ok(100)); + // updating the score below 0 is unexpected. + crate::Pallet::::update_score::(&1, StakeImbalance::Negative(500)); + }) +} + +// same as test above but does not panic after defensive so we can test invariants. +#[test] +#[cfg(not(debug_assertions))] +fn update_score_below_zero_defensive_no_panic_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::get_score(&1), Ok(100)); // updating the score below 0 is unexpected and saturates to 0. crate::Pallet::::update_score::(&1, StakeImbalance::Negative(500)); - // TODO(gpestana): how to assert invariant after defensive fail. + assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::get_score(&1), Ok(0)); + + let n = TestNominators::get(); + assert!(n.get(&1).is_some()); }) } +#[test] +fn on_stake_update_works() { + //TODO(gpestana) +} + #[test] fn on_nominator_add_works() { ExtBuilder::default().build_and_execute(|| { @@ -147,6 +168,57 @@ fn on_validator_add_already_exists_defensive_works() { }); } +#[test] +fn on_nominator_remove_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + let nominator_score = VoterBagsList::get_score(&1).unwrap(); + + let nominations = ::nominations(&1).unwrap(); + assert!(nominations.len() == 1); + let nomination_score_before = TargetBagsList::get_score(&nominations[0]).unwrap(); + + >::on_nominator_remove(&1, nominations.clone()); + + // the nominator was removed from the voter list. + assert!(!VoterBagsList::contains(&1)); + + // now, the score of the nominated by 1 has less `nominator_score` stake than before the + // nominator was removed. + let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); + assert!(nomination_score_after == nomination_score_before - nominator_score); + }) +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the nominator exists in the list as per the contract with staking; qed.\""] +fn on_nominator_remove_defensive_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + + // remove 1 from the voter list to check if the defensive is triggered in the next call, + // while maintaining it as a staker so it does not early exist at the staking mock + // implementation. + assert_ok!(VoterBagsList::on_remove(&1)); + + >::on_nominator_remove(&1, vec![]); + }) +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the validator exists in the list as per the contract with staking; qed.\""] +fn on_validator_remove_defensive_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(!TargetBagsList::contains(&1)); + >::on_validator_remove(&1); + }) +} + +#[test] +fn on_nominator_update_works() { + // TODO(gpestana) +} + mod staking_integration { use super::*; From cab35689503ec68592ba51fca4039f80e2b57ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 8 Nov 2023 15:47:35 +0000 Subject: [PATCH 011/133] Adds more testing --- substrate/frame/stake-tracker/src/mock.rs | 19 ++--- substrate/frame/stake-tracker/src/tests.rs | 83 +++++++++++++++++++++- 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index 6cc00f3b299d..4b0c41ba048a 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -137,14 +137,13 @@ impl StakingInterface for StakingMock { fn status( who: &Self::AccountId, ) -> Result, sp_runtime::DispatchError> { - let n = TestNominators::get(); + let nominators = TestNominators::get(); - if n.contains_key(who) { - Ok(StakerStatus::Nominator(n.get(&who).expect("exists").1.clone())) - } else if TestValidators::get().contains_key(who) { - Ok(StakerStatus::Validator) - } else { - Err("not a staker".into()) + match (TestValidators::get().contains_key(who), nominators.contains_key(who)) { + (true, true) => Ok(StakerStatus::Validator), + (false, true) => + Ok(StakerStatus::Nominator(nominators.get(&who).expect("exists").1.clone())), + _ => Err("mock: not a staker or inconsistent data".into()), } } @@ -313,6 +312,10 @@ pub(crate) fn add_validator(who: AccountId, stake: Balance) { TestValidators::mutate(|v| { v.insert(who, Stake:: { active: stake, total: stake }); }); + // validator is a nominator too. + TestNominators::mutate(|v| { + v.insert(who, (Stake:: { active: stake, total: stake }, vec![])); + }); >::on_validator_add(&who); } @@ -336,7 +339,7 @@ pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option::nominations(&who).unwrap(); >::on_nominator_remove( diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index d4864375e214..783e899bbc28 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -109,7 +109,88 @@ fn update_score_below_zero_defensive_no_panic_works() { #[test] fn on_stake_update_works() { - //TODO(gpestana) + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + let stake_before = stake_of(1); + + let nominations = ::nominations(&1).unwrap(); + assert!(nominations.len() == 1); + let nomination_score_before = TargetBagsList::get_score(&nominations[0]).unwrap(); + + // manually change the stake of the voter. + let new_stake = Stake { total: 10, active: 10 }; + // assert imbalance of the operation is negative. + assert!(stake_before.unwrap().active > new_stake.active); + + TestNominators::mutate(|n| { + n.insert(1, (new_stake, nominations.clone())); + }); + + >::on_stake_update(&1, stake_before); + + assert_eq!(VoterBagsList::get_score(&1).unwrap(), new_stake.active); + + // now, the score of the nominated by 1 has `stake_score` less stake than before the + // nominator's stake was updated. + let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); + assert_eq!( + nomination_score_after, + nomination_score_before - (stake_before.unwrap().active - new_stake.active) + ); + }); + + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(TargetBagsList::contains(&10)); + assert!(VoterBagsList::contains(&10)); + let stake_before = stake_of(10); + let target_score_before = TargetBagsList::get_score(&10).unwrap(); + + // validator has no nominations, as expected. + assert!(::nominations(&10).unwrap().len() == 0); + + // manually change the self stake. + let new_stake = Stake { total: 10, active: 10 }; + // assert imbalance of the operation is negative. + assert!(stake_before.unwrap().active > new_stake.active); + TestNominators::mutate(|n| { + n.insert(10, (new_stake, vec![])); + }); + + >::on_stake_update(&10, stake_before); + + assert_eq!(VoterBagsList::get_score(&10).unwrap(), new_stake.active); + + // target bags list was updated as expected. + let target_score_after = TargetBagsList::get_score(&10).unwrap(); + + println!("t_score 1: {:?}, t_score 2: {:?}", target_score_before, target_score_after); + println!("self_stake_1: {:?}", stake_before); + println!("self_stake_2: {:?}", stake_of(10)); + + assert_eq!(target_score_after, new_stake.active); + }) +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"staker should exist in VoterList, as per the contract with staking.\""] +fn on_stake_update_defensive_not_in_list_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + // removes 1 from nominator's list manually, while keeping it as staker. + assert_ok!(VoterBagsList::on_remove(&1)); + + >::on_stake_update(&1, None); + }) +} + +#[test] +#[should_panic = "Defensive failure has been triggered!: Other(\"mock: not a staker or inconsistent data\"): \"staker should exist when calling on_stake_update and have a valid status\""] +fn on_stake_update_defensive_not_staker_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(!VoterBagsList::contains(&1)); + + >::on_stake_update(&1, None); + }) } #[test] From 0152b34b456edec4306f1d10d4f37d11bc6d097b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 9 Nov 2023 17:56:42 +0000 Subject: [PATCH 012/133] improves testing --- substrate/frame/stake-tracker/src/mock.rs | 27 +++++++-- substrate/frame/stake-tracker/src/tests.rs | 66 ++++++++++++++++++---- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index 4b0c41ba048a..e0037aacf3f7 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -71,7 +71,7 @@ impl pallet_balances::Config for Test { } const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = - [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + [100, 200, 300, 400, 500, 600, 700, 800, 900]; parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &THRESHOLDS; @@ -108,8 +108,17 @@ pub struct StakingMock {} impl ScoreProvider for StakingMock { type Score = VoteWeight; - fn score(_id: &AccountId) -> Self::Score { - todo!(); + fn score(id: &AccountId) -> Self::Score { + // for testing, score is the sum of self stake and nominated active stake. + let nominators = TestNominators::get(); + let mut sum = nominators.get(id).unwrap().0.active; + + for (_, v) in nominators.iter() { + if v.1.contains(id) { + sum += v.0.active; + } + } + sum } fn set_score_of(_: &AccountId, _: Self::Score) { @@ -277,6 +286,10 @@ pub(crate) fn stake_of(who: AccountId) -> Option> { StakingMock::stake(&who).ok() } +pub(crate) fn score_of(who: AccountId) -> VoteWeight { + >::score(&who) +} + pub(crate) fn add_nominator_with_nominations( who: AccountId, stake: Balance, @@ -328,9 +341,13 @@ pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option { - TestValidators::mutate(|n| { - n.insert(who, Stake { active: new, total: new }); + TestValidators::mutate(|v| { + v.insert(who, Stake { active: new, total: new }); }); + TestNominators::mutate(|n| { + let nominations = n.get(&who).expect("exists").1.clone(); + n.insert(who, (Stake { active: new, total: new }, nominations)); + }) }, Ok(StakerStatus::Idle) | Err(_) => panic!("not a staker"), } diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 783e899bbc28..72d804960cb9 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -143,7 +143,6 @@ fn on_stake_update_works() { assert!(TargetBagsList::contains(&10)); assert!(VoterBagsList::contains(&10)); let stake_before = stake_of(10); - let target_score_before = TargetBagsList::get_score(&10).unwrap(); // validator has no nominations, as expected. assert!(::nominations(&10).unwrap().len() == 0); @@ -162,15 +161,63 @@ fn on_stake_update_works() { // target bags list was updated as expected. let target_score_after = TargetBagsList::get_score(&10).unwrap(); - - println!("t_score 1: {:?}, t_score 2: {:?}", target_score_before, target_score_after); - println!("self_stake_1: {:?}", stake_before); - println!("self_stake_2: {:?}", stake_of(10)); - assert_eq!(target_score_after, new_stake.active); }) } +#[test] +fn on_stake_update_sorting_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + let initial_sort = TargetBagsList::iter().collect::>(); + // 10 starts with more score than 11. + assert_eq!(score_of(11), 200); + assert!(score_of(10) > score_of(11)); + assert_eq!(initial_sort, [10, 11]); + + // add new nominator that add +200 score to 11, which reverts the target list order. + add_nominator_with_nominations(5, 200, vec![11]); + assert_eq!(score_of(11), 400); + assert!(score_of(10) < score_of(11)); + assert_eq!( + TargetBagsList::iter().collect::>(), + initial_sort.iter().rev().cloned().collect::>() + ); + + // now we remove the stake 5 to get back to the initial state. + remove_staker(5); + assert_eq!(score_of(11), 200); + assert!(score_of(10) > score_of(11)); + assert_eq!(TargetBagsList::iter().collect::>(), initial_sort); + }); + + ExtBuilder::default().populate_lists().build_and_execute(|| { + // [(10, 100), (11, 100), (1, 100), (2, 100)] + let voter_scores_before = get_scores::(); + assert_eq!(voter_scores_before, [(10, 100), (11, 100), (1, 100), (2, 100)]); + + // nothing changes. + >::on_stake_update(&11, stake_of(11)); + assert_eq!(voter_scores_before, get_scores::()); + + let nominations = ::nominations(&11).unwrap(); + let new_stake = Stake { total: 1, active: 1 }; + TestNominators::mutate(|n| { + n.insert(11, (new_stake, nominations.clone())); + }); + + >::on_stake_update(&11, stake_of(11)); + + // although the voter score of 11 is 1, the voter list sorting has not been updated + // automatically. + assert_eq!(VoterBagsList::get_score(&11), Ok(1)); + // [(10, 100), (11, 1), (1, 100), (2, 100)] + assert_eq!( + voter_scores_before.iter().cloned().map(|(v, _)| v).collect::>(), + VoterBagsList::iter().collect::>() + ); + }); +} + #[test] #[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"staker should exist in VoterList, as per the contract with staking.\""] fn on_stake_update_defensive_not_in_list_works() { @@ -295,11 +342,6 @@ fn on_validator_remove_defensive_works() { }) } -#[test] -fn on_nominator_update_works() { - // TODO(gpestana) -} - mod staking_integration { use super::*; @@ -405,7 +447,7 @@ mod staking_integration { // -100 score for 10 // +100 score for 11 // +100 score for 20 - assert_eq!(get_scores::(), vec![(10, 200), (11, 200), (20, 150)]); + assert_eq!(get_scores::(), vec![(11, 200), (20, 150), (10, 200)]); }) } } From ae98ed95d16976fbba14ef2887dc9c846f9a9f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 Nov 2023 17:04:11 +0000 Subject: [PATCH 013/133] Change score typ of target list from voteweight to balance --- substrate/frame/stake-tracker/src/lib.rs | 84 +++++++++++++++------- substrate/frame/stake-tracker/src/mock.rs | 23 +++--- substrate/frame/stake-tracker/src/tests.rs | 15 ++-- substrate/frame/staking/src/mock.rs | 18 ++--- substrate/frame/staking/src/pallet/mod.rs | 2 +- 5 files changed, 87 insertions(+), 55 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index 3b9866363844..b052757557f3 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -59,6 +59,7 @@ use frame_support::{ defensive, traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; +use sp_npos_elections::ExtendedBalance; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, StakerStatus, StakingInterface, }; @@ -86,7 +87,7 @@ pub enum StakeImbalance { #[frame_support::pallet] pub mod pallet { use crate::*; - use frame_election_provider_support::VoteWeight; + use frame_election_provider_support::{ExtendedBalance, VoteWeight}; use frame_support::pallet_prelude::*; /// The current storage version. @@ -111,31 +112,53 @@ pub mod pallet { type VoterList: SortedListProvider; /// Something that provides an *always* sorted list of targets. - type TargetList: SortedListProvider; + type TargetList: SortedListProvider< + Self::AccountId, + Score = ::Balance, + >; } impl Pallet { /// Returns the vote weight of a staker based on its current *active* stake, as returned by /// the staking interface. - pub(crate) fn active_vote_of(who: &T::AccountId) -> VoteWeight { - T::Staking::stake(who) - .map(|s| Self::to_vote(s.active)) - .defensive_unwrap_or_default() + pub(crate) fn active_vote_of(who: &T::AccountId) -> BalanceOf { + T::Staking::stake(who).map(|s| s.active).defensive_unwrap_or_default() } - /// Converts a staker's balance to its vote weight. - pub(crate) fn to_vote(balance: BalanceOf) -> VoteWeight { + pub(crate) fn weight_of(balance: BalanceOf) -> VoteWeight { ::CurrencyToVote::to_vote( balance, T::Currency::total_issuance(), ) } + /// Fetches and converts a voter's weight into the `ExtendedBalance` type for safe + /// computation. + pub(crate) fn to_vote_extended(balance: BalanceOf) -> ExtendedBalance { + ::CurrencyToVote::to_vote( + balance, + T::Currency::total_issuance(), + ) + .into() + } + + /// Converts an `ExtendedBalance` back to the staking interface's balance. + pub(crate) fn to_currency( + extended: ExtendedBalance, + ) -> ::Balance { + ::CurrencyToVote::to_currency( + extended, + T::Currency::total_issuance(), + ) + } + /// Updates a staker's score by increasing/decreasing an imbalance of the current score in /// the list. - pub(crate) fn update_score(who: &T::AccountId, imbalance: StakeImbalance) - where - L: SortedListProvider, Score = VoteWeight>, + pub(crate) fn update_score( + who: &T::AccountId, + imbalance: StakeImbalance, + ) where + L: SortedListProvider, Score = BalanceOf>, { // there may be nominators who nominate a non-existant validator. if that's the case, // move on. @@ -146,7 +169,7 @@ pub mod pallet { match imbalance { StakeImbalance::Positive(imbalance) => { - let _ = L::on_increase(who, imbalance).defensive_proof( + let _ = L::on_increase(who, Self::to_currency(imbalance)).defensive_proof( "staker should exist in the list, otherwise returned earlier.", ); }, @@ -157,11 +180,13 @@ pub mod pallet { // expected. Instead, we call `L::on_update` to set the new score that // defensively saturates to 0. The node will be removed when `on_*_remove` // is called. - let _ = - L::on_update(who, current_score.defensive_saturating_sub(imbalance)) - .defensive_proof( - "staker exists in the list as per the check above; qed.", - ); + + let balance = Self::to_vote_extended(current_score) + .defensive_saturating_sub(imbalance); + + let _ = L::on_update(who, Self::to_currency(balance)).defensive_proof( + "staker exists in the list as per the check above; qed.", + ); } else { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); } @@ -181,7 +206,7 @@ impl OnStakingUpdate> for Pallet { if let Ok(stake) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( "staker should exist when calling on_stake_update and have a valid status", ) { - let voter_weight = Self::to_vote(stake.active); + let voter_weight = Self::weight_of(Self::active_vote_of(who)); match T::Staking::status(who).expect("status checked above; qed.") { StakerStatus::Nominator(nominations) => { @@ -190,9 +215,13 @@ impl OnStakingUpdate> for Pallet { with staking.", ); + // convert to extended balance to peform operations with voter's weight. + let voter_weight: ExtendedBalance = voter_weight.into(); + // calculate imbalace to update the score of nominated targets. let stake_imbalance = if let Some(prev_stake) = prev_stake { - let prev_voter_weight = Self::to_vote(prev_stake.active); + let prev_voter_weight = Self::to_vote_extended(prev_stake.active); + //let prev_voter_weight = Self::to_vote_extended(prev_stake.active); if prev_voter_weight > voter_weight { StakeImbalance::Negative(prev_voter_weight - voter_weight) @@ -217,7 +246,7 @@ impl OnStakingUpdate> for Pallet { }, StakerStatus::Validator => { // validator is both a target and a voter. - let _ = T::TargetList::on_update(who, voter_weight).defensive_proof( + let _ = T::TargetList::on_update(who, stake.active).defensive_proof( "staker should exist in TargetList, as per the contract \ with staking.", ); @@ -235,7 +264,7 @@ impl OnStakingUpdate> for Pallet { // // Note: it is assumed that who's staking state is updated *before* this method is called. fn on_nominator_add(who: &T::AccountId) { - let nominator_vote = Self::active_vote_of(who); + let nominator_vote = Self::weight_of(Self::active_vote_of(who)); let _ = T::VoterList::on_insert(who.clone(), nominator_vote).defensive_proof( "staker should not exist in VoterList, as per the contract with staking.", @@ -248,7 +277,7 @@ impl OnStakingUpdate> for Pallet { for t in nominations { Self::update_score::( &t, - StakeImbalance::Positive(nominator_vote), + StakeImbalance::Positive(nominator_vote.into()), ) }, Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) | Err(_) => (), // nada. @@ -276,12 +305,12 @@ impl OnStakingUpdate> for Pallet { // this method. Thus, the nominations before the nominator has been removed from staking are // passed in, so that the target list can be updated accordingly. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { - let nominator_vote = Self::active_vote_of(who); + let nominator_vote = Self::weight_of(Self::active_vote_of(who)); // updates the nominated target's score. Note: this may update the score of up to // `T::MaxNominations` validators. for t in nominations.iter() { - Self::update_score::(&t, StakeImbalance::Negative(nominator_vote)) + Self::update_score::(&t, StakeImbalance::Negative(nominator_vote.into())) } let _ = T::VoterList::on_remove(&who).defensive_proof( @@ -307,7 +336,8 @@ impl OnStakingUpdate> for Pallet { // // Note: it is assumed that who's staking state is updated *before* calling this method. fn on_nominator_update(who: &T::AccountId, prev_nominations: Vec) { - let nominator_vote = Self::active_vote_of(who); + let nominator_vote = Self::weight_of(Self::active_vote_of(who)); + let curr_nominations = ::nominations(&who).unwrap_or_default(); @@ -316,7 +346,7 @@ impl OnStakingUpdate> for Pallet { if !prev_nominations.contains(target) { Self::update_score::( &target, - StakeImbalance::Positive(nominator_vote), + StakeImbalance::Positive(nominator_vote.into()), ); } } @@ -325,7 +355,7 @@ impl OnStakingUpdate> for Pallet { if !curr_nominations.contains(target) { Self::update_score::( &target, - StakeImbalance::Negative(nominator_vote), + StakeImbalance::Negative(nominator_vote.into()), ); } } diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index e0037aacf3f7..4d81e63d123f 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -90,9 +90,9 @@ type TargetBagsListInstance = pallet_bags_list::Instance2; impl pallet_bags_list::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - type ScoreProvider = StakingMock; + type ScoreProvider = pallet_bags_list::Pallet; type BagThresholds = BagThresholds; - type Score = VoteWeight; + type Score = ::Balance; } impl pallet_stake_tracker::Config for Test { @@ -109,16 +109,8 @@ impl ScoreProvider for StakingMock { type Score = VoteWeight; fn score(id: &AccountId) -> Self::Score { - // for testing, score is the sum of self stake and nominated active stake. let nominators = TestNominators::get(); - let mut sum = nominators.get(id).unwrap().0.active; - - for (_, v) in nominators.iter() { - if v.1.contains(id) { - sum += v.0.active; - } - } - sum + nominators.get(id).unwrap().0.active } fn set_score_of(_: &AccountId, _: Self::Score) { @@ -286,10 +278,17 @@ pub(crate) fn stake_of(who: AccountId) -> Option> { StakingMock::stake(&who).ok() } -pub(crate) fn score_of(who: AccountId) -> VoteWeight { +#[allow(dead_code)] +pub(crate) fn score_of_voter(who: AccountId) -> VoteWeight { >::score(&who) } +pub(crate) fn score_of_target(who: AccountId) -> Balance { + as ScoreProvider>::score( + &who, + ) +} + pub(crate) fn add_nominator_with_nominations( who: AccountId, stake: Balance, diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 72d804960cb9..1d2c985f03bb 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -62,7 +62,7 @@ fn update_score_works() { let current_score = VoterBagsList::get_score(&1).unwrap(); crate::Pallet::::update_score::( &1, - StakeImbalance::Negative(current_score), + StakeImbalance::Negative(current_score.into()), ); assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::get_score(&1), Ok(0)); @@ -169,15 +169,16 @@ fn on_stake_update_works() { fn on_stake_update_sorting_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { let initial_sort = TargetBagsList::iter().collect::>(); + // 10 starts with more score than 11. - assert_eq!(score_of(11), 200); - assert!(score_of(10) > score_of(11)); + assert_eq!(score_of_target(11), 200); + assert!(score_of_target(10) > score_of_target(11)); assert_eq!(initial_sort, [10, 11]); // add new nominator that add +200 score to 11, which reverts the target list order. add_nominator_with_nominations(5, 200, vec![11]); - assert_eq!(score_of(11), 400); - assert!(score_of(10) < score_of(11)); + assert_eq!(score_of_target(11), 400); + assert!(score_of_target(10) < score_of_target(11)); assert_eq!( TargetBagsList::iter().collect::>(), initial_sort.iter().rev().cloned().collect::>() @@ -185,8 +186,8 @@ fn on_stake_update_sorting_works() { // now we remove the stake 5 to get back to the initial state. remove_staker(5); - assert_eq!(score_of(11), 200); - assert!(score_of(10) > score_of(11)); + assert_eq!(score_of_target(11), 200); + assert!(score_of_target(10) > score_of_target(11)); assert_eq!(TargetBagsList::iter().collect::>(), initial_sort); }); diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index dfa271d0754f..6ec4be3b1a93 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -232,11 +232,14 @@ impl OnUnbalanced> for RewardRemainderMock { } } -const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = +const VOTER_THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +const TARGET_THRESHOLDS: [Balance; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + parameter_types! { - pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; + pub static VoterBagThresholds: &'static [sp_npos_elections::VoteWeight] = &VOTER_THRESHOLDS; + pub static TargetBagThresholds: &'static [Balance] = &TARGET_THRESHOLDS; pub static HistoryDepth: u32 = 80; pub static MaxExposurePageSize: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; @@ -252,7 +255,7 @@ impl pallet_bags_list::Config for Test { type WeightInfo = (); // Staking is the source of truth for voter bags list, since they are not kept up to date. type ScoreProvider = Staking; - type BagThresholds = BagThresholds; + type BagThresholds = VoterBagThresholds; type Score = VoteWeight; } @@ -260,10 +263,9 @@ type TargetBagsListInstance = pallet_bags_list::Instance2; impl pallet_bags_list::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - // Staking is the source of truth for target bags list. - type ScoreProvider = Staking; - type BagThresholds = BagThresholds; - type Score = VoteWeight; + type ScoreProvider = pallet_bags_list::Pallet; + type BagThresholds = TargetBagThresholds; + type Score = Balance; } pub struct OnChainSeqPhragmen; @@ -875,7 +877,7 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { } #[allow(dead_code)] -pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(AccountId, VoteWeight)>) { +pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(AccountId, Balance)>) { ( VoterBagsList::iter() .map(|v| (v, VoterBagsList::get_score(&v).unwrap())) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 7c4851751659..73aa98db9d8d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -247,7 +247,7 @@ pub mod pallet { /// Unlike `VoterList`, the values in this list are always kept up to date with rewards, /// slashes, etc, and thus represent the accurate approval stake of all account being /// nominated by nominators. - type TargetList: SortedListProvider; + type TargetList: SortedListProvider>; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can /// have. Effectively determines how many unique eras a staker may be From ac4a7af9c65efb12a67229549eafd5b322646ba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 Nov 2023 17:30:56 +0000 Subject: [PATCH 014/133] adds more rebagging and sorting tests to stake-tracker --- substrate/frame/stake-tracker/src/mock.rs | 21 +++++++++++++++++++++ substrate/frame/stake-tracker/src/tests.rs | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/stake-tracker/src/mock.rs index 4d81e63d123f..6e20f3511f10 100644 --- a/substrate/frame/stake-tracker/src/mock.rs +++ b/substrate/frame/stake-tracker/src/mock.rs @@ -371,6 +371,24 @@ pub(crate) fn remove_staker(who: AccountId) { }; } +pub(crate) fn target_bags_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let RuntimeEvent::TargetBagsList(inner) = e { Some(inner) } else { None }, + ) + .collect::>() +} + +pub(crate) fn voter_bags_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::VoterBagsList(inner) = e { Some(inner) } else { None }) + .collect::>() +} + #[derive(Default, Copy, Clone)] pub struct ExtBuilder { populate_lists: bool, @@ -397,6 +415,9 @@ impl ExtBuilder { if self.populate_lists { populate_lists(); } + // move pass genesis to register events. + System::set_block_number(1); + test() }); } diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 1d2c985f03bb..80b0d6424e81 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -189,6 +189,17 @@ fn on_stake_update_sorting_works() { assert_eq!(score_of_target(11), 200); assert!(score_of_target(10) > score_of_target(11)); assert_eq!(TargetBagsList::iter().collect::>(), initial_sort); + + // double-check, events from target bags list: scores being updated and rebag. + assert_eq!( + target_bags_events(), + [ + pallet_bags_list::Event::Rebagged { who: 11, from: 200, to: 400 }, + pallet_bags_list::Event::ScoreUpdated { who: 11, new_score: 400 }, + pallet_bags_list::Event::Rebagged { who: 11, from: 400, to: 200 }, + pallet_bags_list::Event::ScoreUpdated { who: 11, new_score: 200 }, + ], + ); }); ExtBuilder::default().populate_lists().build_and_execute(|| { @@ -216,6 +227,15 @@ fn on_stake_update_sorting_works() { voter_scores_before.iter().cloned().map(|(v, _)| v).collect::>(), VoterBagsList::iter().collect::>() ); + + // double-check, events from voter bags list: scores being updated but no rebag. + assert_eq!( + voter_bags_events(), + [ + pallet_bags_list::Event::ScoreUpdated { who: 11, new_score: 100 }, + pallet_bags_list::Event::ScoreUpdated { who: 11, new_score: 1 } + ], + ); }); } From c2d681dcc6c6448c9ee8b1814753e4b04f594a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 14 Nov 2023 15:03:09 +0100 Subject: [PATCH 015/133] More tests --- Cargo.lock | 1 + substrate/frame/stake-tracker/Cargo.toml | 2 + substrate/frame/stake-tracker/src/lib.rs | 54 ++++++- substrate/frame/stake-tracker/src/tests.rs | 21 +-- substrate/frame/staking/src/mock.rs | 62 +++++++- substrate/frame/staking/src/pallet/impls.rs | 9 +- substrate/frame/staking/src/pallet/mod.rs | 1 + substrate/frame/staking/src/tests.rs | 150 +++++++++++++++++--- 8 files changed, 251 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ca716a08aa29..a77d05d11773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10732,6 +10732,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", + "log", "pallet-bags-list", "pallet-balances", "parity-scale-codec", diff --git a/substrate/frame/stake-tracker/Cargo.toml b/substrate/frame/stake-tracker/Cargo.toml index f41a0cbc6016..f1716aaf07f2 100644 --- a/substrate/frame/stake-tracker/Cargo.toml +++ b/substrate/frame/stake-tracker/Cargo.toml @@ -25,6 +25,8 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional frame-support = { version = "4.0.0-dev", default-features = false, path = "../support"} frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +log = { version = "0.4.17", default-features = false } + [dev-dependencies] sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } sp-core = { version = "21.0.0", path = "../../primitives/core" } diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index b052757557f3..51128b814cd6 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -70,6 +70,19 @@ mod mock; #[cfg(test)] mod tests; +pub(crate) const LOG_TARGET: &str = "runtime::stake-tracker"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 📚 ", $patter), >::block_number() $(, $values)* + ) + }; +} + /// The balance type of this pallet. pub type BalanceOf = <::Staking as StakingInterface>::Balance; /// The account ID of this pallet. @@ -161,9 +174,9 @@ pub mod pallet { L: SortedListProvider, Score = BalanceOf>, { // there may be nominators who nominate a non-existant validator. if that's the case, - // move on. + // move on. This is an expected behaviour, so no defensive. if !L::contains(who) { - defensive!("`update_score` on non-existant staker", who); + log!(debug, "update_score of {:?}, which is not a target", who); return } @@ -180,7 +193,6 @@ pub mod pallet { // expected. Instead, we call `L::on_update` to set the new score that // defensively saturates to 0. The node will be removed when `on_*_remove` // is called. - let balance = Self::to_vote_extended(current_score) .defensive_saturating_sub(imbalance); @@ -224,9 +236,13 @@ impl OnStakingUpdate> for Pallet { //let prev_voter_weight = Self::to_vote_extended(prev_stake.active); if prev_voter_weight > voter_weight { - StakeImbalance::Negative(prev_voter_weight - voter_weight) + StakeImbalance::Negative( + prev_voter_weight.defensive_saturating_sub(voter_weight), + ) } else { - StakeImbalance::Positive(voter_weight - prev_voter_weight) + StakeImbalance::Positive( + voter_weight.defensive_saturating_sub(prev_voter_weight), + ) } } else { // if nominator had no stake before update, then add all the voter weight @@ -234,6 +250,14 @@ impl OnStakingUpdate> for Pallet { StakeImbalance::Positive(voter_weight) }; + log!( + debug, + "on_stake_update: {:?} with {:?}. impacting nominations {:?}", + who, + stake_imbalance, + nominations, + ); + // updates vote weight of nominated targets accordingly. Note: this will update // the score of up to `T::MaxNominations` validators. for target in nominations.into_iter() { @@ -282,6 +306,8 @@ impl OnStakingUpdate> for Pallet { }, Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) | Err(_) => (), // nada. }; + + log!(debug, "on_nominator_add: {:?}. role: {:?}", who, T::Staking::status(who),); } // Fired when someone sets their intention to validate. @@ -295,6 +321,8 @@ impl OnStakingUpdate> for Pallet { "staker should not exist in TargetList, as per the contract with staking.", ); + log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); + // a validator is also a nominator. Self::on_nominator_add(who) } @@ -307,6 +335,14 @@ impl OnStakingUpdate> for Pallet { fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); + log!( + debug, + "on_nominator_remove: {:?} with {:?}. impacting {:?}", + who, + nominator_vote, + nominations, + ); + // updates the nominated target's score. Note: this may update the score of up to // `T::MaxNominations` validators. for t in nominations.iter() { @@ -320,6 +356,8 @@ impl OnStakingUpdate> for Pallet { // Fired when someone removes their intention to validate, either due to chill or nominating. fn on_validator_remove(who: &T::AccountId) { + log!(debug, "on_validator_remove: {:?}", who,); + let _ = T::TargetList::on_remove(&who).defensive_proof( "the validator exists in the list as per the contract with staking; qed.", ); @@ -341,6 +379,12 @@ impl OnStakingUpdate> for Pallet { let curr_nominations = ::nominations(&who).unwrap_or_default(); + log!( + debug, + "on_nominator_update: {:?}, with {:?}. previous nominations: {:?} -> new nominations {:?}", + who, nominator_vote, prev_nominations, curr_nominations, + ); + // new nominations for target in curr_nominations.iter() { if !prev_nominations.contains(target) { diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 80b0d6424e81..3649e32f18e2 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -69,16 +69,6 @@ fn update_score_works() { }) } -#[test] -#[should_panic = "Defensive failure has been triggered!: \"`update_score` on non-existant staker\": 1"] -fn update_score_non_existing_defensive_works() { - ExtBuilder::default().build_and_execute(|| { - assert!(!VoterBagsList::contains(&1)); - // not expected to update score of a non-existing staker. - crate::Pallet::::update_score::(&1, StakeImbalance::Positive(100)); - }); -} - #[test] #[should_panic] fn update_score_below_zero_defensive_works() { @@ -453,22 +443,17 @@ mod staking_integration { ); assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); - add_validator(20, 50); + add_validator(20, 500); // removes nomination from 10 and adds nomination to new validator, 20. update_nominations_of(2, vec![11, 20]); - // new voter (validator) 2 with 100 stake. note that the voter score is not updated - // automatically. assert_eq!( get_scores::(), - vec![(10, 100), (11, 100), (1, 100), (2, 100), (20, 50)] + [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)] ); // target list has been updated: - // -100 score for 10 - // +100 score for 11 - // +100 score for 20 - assert_eq!(get_scores::(), vec![(11, 200), (20, 150), (10, 200)]); + assert_eq!(get_scores::(), vec![(20, 600), (11, 200), (10, 200)]); }) } } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 6ec4be3b1a93..3500d4043820 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -235,7 +235,7 @@ impl OnUnbalanced> for RewardRemainderMock { const VOTER_THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; -const TARGET_THRESHOLDS: [Balance; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +const TARGET_THRESHOLDS: [Balance; 9] = [100, 200, 300, 400, 500, 600, 1_000, 2_000, 10_000]; parameter_types! { pub static VoterBagThresholds: &'static [sp_npos_elections::VoteWeight] = &VOTER_THRESHOLDS; @@ -876,7 +876,55 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } -#[allow(dead_code)] +pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { + use sp_staking::StakingInterface; + + assert_eq!(Nominators::::count() + Validators::::count(), VoterBagsList::count()); + + // recalculate the target's stake based on voter's nominations and compare with the score in the + // target list. + let mut map: BTreeMap = BTreeMap::new(); + for nominator in VoterBagsList::iter() { + if let Some(nominations) = ::nominations(&nominator) { + let score = >::get_score(&nominator) + .map_err(|_| "nominator score must exist in voter bags list")?; + + for nomination in nominations { + if let Some(stake) = map.get_mut(&nomination) { + *stake += score as u128; + } else { + map.insert(nomination, score.into()); + } + } + } + } + for target in TargetBagsList::iter() { + let score = >::get_score(&target) + .map_err(|_| "target score must exist in voter bags list")?; + if let Some(stake) = map.get_mut(&target) { + *stake += score as u128; + } else { + map.insert(target, score.into()); + } + } + + // compare final result with target list. + assert_eq!(map.keys().len(), TargetBagsList::count() as usize); + for (target, stake) in map.into_iter() { + let stake_in_list = TargetBagsList::get_score(&target).unwrap(); + assert_eq!( + stake, stake_in_list, + "target list score of {:?} is not correct. expected {:?}, got {:?}", + target, stake, stake_in_list + ); + } + Ok(()) +} + +pub(crate) fn some_existing_validator() -> Option { + TargetBagsList::iter().last() +} + pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(AccountId, Balance)>) { ( VoterBagsList::iter() @@ -887,3 +935,13 @@ pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(Accoun .collect::>(), ) } + +pub(crate) fn target_bags_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let RuntimeEvent::TargetBagsList(inner) = e { Some(inner) } else { None }, + ) + .collect::>() +} diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index c9e004aba87b..3121f9f1c6c5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -982,21 +982,20 @@ impl Pallet { pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { if !Nominators::::contains_key(who) { // new nominator. + Nominators::::insert(who, nominations); >>::on_nominator_add( who, ); } else { // update nominations. let prev_nominations = Self::nominations(who).unwrap_or_default(); - + Nominators::::insert(who, nominations); >>::on_nominator_update( who, prev_nominations, ); } - Nominators::::insert(who, nominations); - debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::count() @@ -1045,11 +1044,13 @@ impl Pallet { /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { + Validators::::insert(who, prefs); >>::on_validator_add( who, ); + } else { + Validators::::insert(who, prefs); } - Validators::::insert(who, prefs); debug_assert_eq!( Nominators::::count() + Validators::::count(), diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 73aa98db9d8d..8451ff4b108e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1227,6 +1227,7 @@ pub mod pallet { Self::do_remove_validator(stash); Self::do_add_nominator(stash, nominations); + Ok(()) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6f607cf4dc23..18d3e290d978 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -201,17 +201,17 @@ fn basic_setup_works() { assert_eq!( Staking::eras_stakers(active_era(), &11), Exposure { - total: 1125, + total: 1375, own: 1000, - others: vec![IndividualExposure { who: 101, value: 125 }] + others: vec![IndividualExposure { who: 101, value: 375 }] }, ); assert_eq!( Staking::eras_stakers(active_era(), &21), Exposure { - total: 1375, + total: 1125, own: 1000, - others: vec![IndividualExposure { who: 101, value: 375 }] + others: vec![IndividualExposure { who: 101, value: 125 }] }, ); @@ -444,14 +444,14 @@ fn staking_should_work() { // --- Block 6: the validators will now be changed. start_session(6); - assert_eq_uvec!(validator_controllers(), vec![21, 3]); + assert_eq_uvec!(validator_controllers(), vec![3, 11]); // --- Block 6: Unstake 4 as a validator, freeing up the balance stashed in 3 // 4 will chill Staking::chill(RuntimeOrigin::signed(3)).unwrap(); // --- Block 7: nothing. 3 is still there. start_session(7); - assert_eq_uvec!(validator_controllers(), vec![21, 3]); + assert_eq_uvec!(validator_controllers(), vec![3, 11]); // --- Block 8: start_session(8); @@ -1850,13 +1850,6 @@ fn switching_roles() { let _ = Balances::deposit_creating(&i, 5000); } - // add 2 nominators - assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 5])); - - assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Controller)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 1])); - // add a new validator candidate assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1000, RewardDestination::Controller)); assert_ok!(Staking::validate(RuntimeOrigin::signed(5), ValidatorPrefs::default())); @@ -1866,18 +1859,28 @@ fn switching_roles() { vec![] )); + // add 2 nominators + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 5])); + + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21])); + mock::start_active_era(1); // with current nominators 11 and 5 have the most stake assert_eq_uvec!(validator_controllers(), vec![5, 11]); - // 2 decides to be a validator. Consequences: + // 1 decides to be a validator. Consequences: assert_ok!(Staking::validate(RuntimeOrigin::signed(1), ValidatorPrefs::default())); assert_ok!(Session::set_keys( RuntimeOrigin::signed(1), SessionKeys { other: 2.into() }, vec![] )); + + // now that 1 is a validator, 3 updates its nominations. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 1])); // new stakes: // 11: 1000 self vote // 21: 1000 self vote + 250 vote @@ -2466,6 +2469,7 @@ fn reporters_receive_their_slice() { ExtBuilder::default().build_and_execute(|| { // The reporters' reward is calculated from the total exposure. let initial_balance = 1125; + assert_ok!(stake_tracker_sanity_tests()); assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); @@ -5613,7 +5617,10 @@ fn chill_other_works() { 1000, RewardDestination::Controller )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![1])); + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(a), + vec![some_existing_validator().unwrap()] + )); // Validator assert_ok!(Staking::bond( @@ -5728,13 +5735,13 @@ fn chill_other_works() { assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), b)); assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), d)); } - // chill a nominator. Limit is not reached, not chill-able assert_eq!(Nominators::::count(), 7); assert_noop!( Staking::chill_other(RuntimeOrigin::signed(1337), 0), Error::::CannotChillOther ); + // chill a validator. Limit is reached, chill-able. assert_eq!(Validators::::count(), 9); assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), 2)); @@ -5799,7 +5806,11 @@ fn capped_stakers_works() { RewardDestination::Controller, ) .unwrap(); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1])); + + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(controller), + vec![some_existing_validator] + )); some_existing_nominator = controller; } @@ -5811,12 +5822,15 @@ fn capped_stakers_works() { ) .unwrap(); assert_noop!( - Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]), + Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![some_existing_validator]), Error::::TooManyNominators ); // Re-nominate works fine - assert_ok!(Staking::nominate(RuntimeOrigin::signed(some_existing_nominator), vec![1])); + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(some_existing_nominator), + vec![some_existing_validator] + )); // Re-validate works fine assert_ok!(Staking::validate( RuntimeOrigin::signed(some_existing_validator), @@ -5833,7 +5847,10 @@ fn capped_stakers_works() { ConfigOp::Noop, ConfigOp::Noop, )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1])); + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(last_nominator), + vec![some_existing_validator] + )); assert_ok!(Staking::validate( RuntimeOrigin::signed(last_validator), ValidatorPrefs::default() @@ -6964,3 +6981,96 @@ mod ledger { }) } } + +mod stake_tracker { + use super::*; + use pallet_bags_list::Event as BagsEvent; + + #[test] + fn add_remove_nomination_works() { + // Test case: a new nomination affects the stake behind the target in the target list and + // the sorting of the target list is also updated. Chilling the nomination will update the + // target list scores and rebag back to the original state. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::chill() + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + use sp_staking::StakingInterface; + + // add validator 12. + let _ = Balances::deposit_creating(&12, 150); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(12), + 150, + RewardDestination::Controller + )); + assert_ok!(Staking::validate(RuntimeOrigin::signed(12), Default::default())); + + // 12 is a validator and has 150 self-vote. + assert_eq!(::status(&12), Ok(StakerStatus::Validator)); + assert_eq!(>::get_score(&12), Ok(150)); + + // add validator 11. + let _ = Balances::deposit_creating(&11, 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(11), + 100, + RewardDestination::Controller + )); + assert_ok!(Staking::validate(RuntimeOrigin::signed(11), Default::default())); + + // 11 is a validator and has 100 self-vote. + assert_eq!(::status(&11), Ok(StakerStatus::Validator)); + assert_eq!(>::get_score(&11), Ok(100)); + + // the target list is sorted by stake: [(12, 150), (11, 100)] + assert_eq!(voters_and_targets().1, [(12, 150), (11, 100)]); + + // no rebags in the target list so far. + assert!(target_bags_events().is_empty()); + + // add nominator 1, which nominates 11. + let _ = Balances::deposit_creating(&1, 300); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 300, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11])); + + // 1 is a nominator and nominates 11 with 300 stake. + assert_eq!( + ::status(&1), + Ok(StakerStatus::Nominator(vec![11])) + ); + assert_eq!(>::get_score(&1), Ok(300)); + + // 11 has self-stake and nominated stake from 1, so total score is 400. + assert_ok!(stake_tracker_sanity_tests()); + + // rebag in the target list happened as expected. + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 11, from: 100, to: 400 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 400 } + ] + ); + assert_eq!(voters_and_targets().1, [(11, 400), (12, 150)]); + + System::reset_events(); + + // chill nominator 1. + assert_ok!(Staking::chill(RuntimeOrigin::signed(1))); + + assert_ok!(stake_tracker_sanity_tests()); + // the target list is sorted by stake, similar to before nomination: [(12, 150), (11, + // 100)] + assert_eq!(voters_and_targets().1, [(12, 150), (11, 100)]); + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 11, from: 400, to: 100 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 100 } + ] + ); + }) + } +} From 4e06d6052182c2e5a120ac4b2167c8dd976b64c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 14 Nov 2023 23:04:55 +0100 Subject: [PATCH 016/133] test fixing due to new target list ordering --- substrate/frame/staking/src/tests.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 18d3e290d978..f458de689f20 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2468,7 +2468,7 @@ fn reporters_receive_their_slice() { // amount. ExtBuilder::default().build_and_execute(|| { // The reporters' reward is calculated from the total exposure. - let initial_balance = 1125; + let initial_balance = 1375; assert_ok!(stake_tracker_sanity_tests()); assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); @@ -2726,6 +2726,7 @@ fn garbage_collection_on_window_pruning() { }) } +// TODO(gpestana): double check #[test] fn slashing_nominators_by_span_max() { ExtBuilder::default().build_and_execute(|| { @@ -2923,7 +2924,7 @@ fn deferred_slashes_are_deferred() { Event::ForceEra { mode: Forcing::NotForcing }, .., Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 } + Event::Slashed { staker: 101, amount: 37 } ] )); }) @@ -2959,7 +2960,7 @@ fn retroactive_deferred_slashes_two_eras_before() { Event::SlashReported { validator: 11, slash_era: 1, .. }, .., Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 } + Event::Slashed { staker: 101, amount: 37 } ] )); }) @@ -2999,7 +3000,7 @@ fn retroactive_deferred_slashes_one_before() { Event::SlashReported { validator: 11, slash_era: 2, .. }, .., Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 } + Event::Slashed { staker: 101, amount: 37 } ] )); @@ -3145,7 +3146,7 @@ fn remove_deferred() { Event::SlashReported { validator: 11, slash_era: 1, .. }, .., Event::Slashed { staker: 11, amount: 50 }, - Event::Slashed { staker: 101, amount: 7 } + Event::Slashed { staker: 101, amount: 19 } ] )); @@ -3244,8 +3245,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); - assert_eq!(exposure_11.total, 1000 + 125); - assert_eq!(exposure_21.total, 1000 + 375); + assert_eq!(exposure_21.total, 1000 + 125); + assert_eq!(exposure_11.total, 1000 + 375); on_offence_now( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], @@ -3265,12 +3266,12 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid slash_era: 1 }, Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 }, + Event::Slashed { staker: 101, amount: 37 }, ] ); // post-slash balance - let nominator_slash_amount_11 = 125 / 10; + let nominator_slash_amount_11 = 375 / 10; assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); @@ -3284,6 +3285,9 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); + // TODO(gpestana): re-do calculations + println!("{:?}", exposure_11); + println!("{:?}", exposure_21); // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 // 900 + 146 assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); @@ -3339,7 +3343,7 @@ fn non_slashable_offence_doesnt_disable_validator() { slash_era: 1 }, Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } + Event::Slashed { staker: 101, amount: 31 } ] ); @@ -3402,7 +3406,7 @@ fn slashing_independent_of_disabling_validator() { slash_era: 1 }, Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } + Event::Slashed { staker: 101, amount: 31 } ] ); From bbc59a592e18834f6f4e222bde8575a9f29c9de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 15 Nov 2023 20:49:43 +0100 Subject: [PATCH 017/133] Adds more staking tests for the stake-tracker integration --- substrate/frame/stake-tracker/src/lib.rs | 66 ++-- substrate/frame/stake-tracker/src/tests.rs | 21 +- substrate/frame/staking/src/tests.rs | 355 ++++++++++++++++++++- 3 files changed, 394 insertions(+), 48 deletions(-) diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/stake-tracker/src/lib.rs index 51128b814cd6..8e9c3212599e 100644 --- a/substrate/frame/stake-tracker/src/lib.rs +++ b/substrate/frame/stake-tracker/src/lib.rs @@ -61,7 +61,7 @@ use frame_support::{ }; use sp_npos_elections::ExtendedBalance; use sp_staking::{ - currency_to_vote::CurrencyToVote, OnStakingUpdate, StakerStatus, StakingInterface, + currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; use sp_std::collections::btree_map::BTreeMap; @@ -193,8 +193,8 @@ pub mod pallet { // expected. Instead, we call `L::on_update` to set the new score that // defensively saturates to 0. The node will be removed when `on_*_remove` // is called. - let balance = Self::to_vote_extended(current_score) - .defensive_saturating_sub(imbalance); + let balance = + Self::to_vote_extended(current_score).saturating_sub(imbalance); let _ = L::on_update(who, Self::to_currency(balance)).defensive_proof( "staker exists in the list as per the check above; qed.", @@ -214,8 +214,30 @@ impl OnStakingUpdate> for Pallet { // When a nominator's stake is updated, all the nominated targets must be updated accordingly. // // Note: it is assumed that who's staking state is updated *before* this method is called. - fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { - if let Ok(stake) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( + fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { + // closure to calculate the stake imbalance of a staker. + let stake_imbalance_of = |prev_stake: Option>>, + voter_weight: ExtendedBalance| { + if let Some(prev_stake) = prev_stake { + let prev_voter_weight = Self::to_vote_extended(prev_stake.active); + + if prev_voter_weight > voter_weight { + StakeImbalance::Negative( + prev_voter_weight.defensive_saturating_sub(voter_weight), + ) + } else { + StakeImbalance::Positive( + voter_weight.defensive_saturating_sub(prev_voter_weight), + ) + } + } else { + // if staker had no stake before update, then add all the voter weight + // to the target's score. + StakeImbalance::Positive(voter_weight) + } + }; + + if let Ok(_) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( "staker should exist when calling on_stake_update and have a valid status", ) { let voter_weight = Self::weight_of(Self::active_vote_of(who)); @@ -227,28 +249,7 @@ impl OnStakingUpdate> for Pallet { with staking.", ); - // convert to extended balance to peform operations with voter's weight. - let voter_weight: ExtendedBalance = voter_weight.into(); - - // calculate imbalace to update the score of nominated targets. - let stake_imbalance = if let Some(prev_stake) = prev_stake { - let prev_voter_weight = Self::to_vote_extended(prev_stake.active); - //let prev_voter_weight = Self::to_vote_extended(prev_stake.active); - - if prev_voter_weight > voter_weight { - StakeImbalance::Negative( - prev_voter_weight.defensive_saturating_sub(voter_weight), - ) - } else { - StakeImbalance::Positive( - voter_weight.defensive_saturating_sub(prev_voter_weight), - ) - } - } else { - // if nominator had no stake before update, then add all the voter weight - // to the target's score. - StakeImbalance::Positive(voter_weight) - }; + let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); log!( debug, @@ -270,10 +271,9 @@ impl OnStakingUpdate> for Pallet { }, StakerStatus::Validator => { // validator is both a target and a voter. - let _ = T::TargetList::on_update(who, stake.active).defensive_proof( - "staker should exist in TargetList, as per the contract \ - with staking.", - ); + let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); + Self::update_score::(&who, stake_imbalance); + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( "the staker should exit in VoterList, as per the \ contract with staking.", @@ -407,8 +407,8 @@ impl OnStakingUpdate> for Pallet { // noop: the updates to target and voter lists when applying a slash are performed // through [`Self::on_nominator_remove`] and [`Self::on_validator_remove`] when the stakers are - // chilled. When the slash is applied, the ledger is updated, thus the stake is propagated - // through the `[Self::update::]`. + // chilled. When the slash is applied, the ledger is updated of the affected stashes is, thus + // the stake is propagated through the `[Self::update::]`. fn on_slash( _stash: &T::AccountId, _slashed_active: BalanceOf, diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/stake-tracker/src/tests.rs index 3649e32f18e2..14d990c1cde6 100644 --- a/substrate/frame/stake-tracker/src/tests.rs +++ b/substrate/frame/stake-tracker/src/tests.rs @@ -69,17 +69,6 @@ fn update_score_works() { }) } -#[test] -#[should_panic] -fn update_score_below_zero_defensive_works() { - ExtBuilder::default().populate_lists().build_and_execute(|| { - assert!(VoterBagsList::contains(&1)); - assert_eq!(VoterBagsList::get_score(&1), Ok(100)); - // updating the score below 0 is unexpected. - crate::Pallet::::update_score::(&1, StakeImbalance::Negative(500)); - }) -} - // same as test above but does not panic after defensive so we can test invariants. #[test] #[cfg(not(debug_assertions))] @@ -133,6 +122,7 @@ fn on_stake_update_works() { assert!(TargetBagsList::contains(&10)); assert!(VoterBagsList::contains(&10)); let stake_before = stake_of(10); + let target_score_before = TargetBagsList::get_score(&10).unwrap(); // validator has no nominations, as expected. assert!(::nominations(&10).unwrap().len() == 0); @@ -145,13 +135,18 @@ fn on_stake_update_works() { n.insert(10, (new_stake, vec![])); }); + let stake_imbalance = stake_before.unwrap().active - new_stake.total; + >::on_stake_update(&10, stake_before); assert_eq!(VoterBagsList::get_score(&10).unwrap(), new_stake.active); + assert_eq!(StakingMock::stake(&10), Ok(new_stake)); - // target bags list was updated as expected. + // target bags list was updated as expected (new score is difference between previous and + // the stake imbalance of previous and the new stake, in order to not touch the nomination's + // weight in the total target score). let target_score_after = TargetBagsList::get_score(&10).unwrap(); - assert_eq!(target_score_after, new_stake.active); + assert_eq!(target_score_after, target_score_before - stake_imbalance); }) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f458de689f20..4c78a9f56e8d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6988,7 +6988,12 @@ mod ledger { mod stake_tracker { use super::*; + use frame_election_provider_support::ScoreProvider; use pallet_bags_list::Event as BagsEvent; + use sp_staking::{StakingAccount::*, StakingInterface}; + + // keep tests clean; + type A = AccountId; #[test] fn add_remove_nomination_works() { @@ -7000,8 +7005,6 @@ mod stake_tracker { // * Call::nominate() // * Call::chill() ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { - use sp_staking::StakingInterface; - // add validator 12. let _ = Balances::deposit_creating(&12, 150); assert_ok!(Staking::bond( @@ -7077,4 +7080,352 @@ mod stake_tracker { ); }) } + + #[test] + fn bond_extra_works() { + // Test case: bonding extra on validator and nominator affects the target list score + // accordingly and rebagging may happen. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::bond_extra() + ExtBuilder::default() + .add_staker(100, 100, 100, StakerStatus::Nominator(vec![31])) + .build_and_execute(|| { + // target score of 31 is the sum of own stake and nominations stake. + let own_stake = Staking::ledger(Stash(31)).unwrap().active; + let other_stake = Staking::ledger(Stash(100)).unwrap().active; + assert_eq!( + >::get_score(&31), + Ok(own_stake + other_stake) + ); + + // target list is sorted by score. + assert_ok!(stake_tracker_sanity_tests()); + assert_eq!( + voters_and_targets().1, + [(11, 1500), (21, 1500), (31, own_stake + other_stake)] + ); + + // 100, which nominates 31, bonds 1500 extra. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(100), 1500)); + assert_eq!(Staking::ledger(Stash(100)).unwrap().active, 1600); + + // target score of 31 has increased by 1500, although own stake remained the same. + assert_eq!(own_stake, Staking::ledger(Stash(31)).unwrap().active); + assert_eq!( + >::get_score(&31), + Ok(own_stake + other_stake + 1500) + ); + + // target score of 31 is higher than the remaining of the targets, rebagging + // happened. + assert_eq!( + voters_and_targets().1, + [(31, own_stake + other_stake + 1500), (11, 1500), (21, 1500)] + ); + + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 31, from: 600, to: 10000 }, + BagsEvent::ScoreUpdated { + who: 31, + new_score: own_stake + other_stake + 1500 + } + ] + ); + System::reset_events(); + + // and now, validator 21 (nominated by 101) also bonds extra self-stake. + let own_stake = Staking::ledger(Stash(21)).unwrap().active; + let other_stake = Staking::ledger(Stash(101)).unwrap().active; + + assert_eq!( + >::get_score(&21), + Ok(own_stake + other_stake) // 1500 + ); + + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(21), 300)); + + // updates to 21 target score are as expected. + assert_eq!(Staking::ledger(Stash(21)).unwrap().active, own_stake + 300); + assert_eq!( + >::get_score(&21), + Ok(own_stake + other_stake + 300) + ); + + // although 21 increased in target score, there was no rebagging due to the new + // score not being high enough to move the the next bag, given thresholds (1_000 + // -> 2_000)). + assert_eq!(voters_and_targets().1, [(31, 2100), (11, 1500), (21, 1800)]); + + assert_eq!( + target_bags_events(), + [BagsEvent::ScoreUpdated { who: 21, new_score: own_stake + other_stake + 300 }] + ); + }) + } + + #[test] + fn chill_works() { + // Test case: kicking and chilling nominators and validators affects the target list score + // and rebagging may happen. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::chill() + // * Call::kick() + ExtBuilder::default().build_and_execute(|| { + // bond extra to rebag nominated validator. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(101), 600)); + System::reset_events(); + + // 101 nominates both 11 and 21. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec!(11, 21)))); + // with score + let nominated_score = Staking::active_stake(&101); + assert_eq!(nominated_score, Ok(1100)); + + let score_11_before = >::score(&11); + let score_21_before = >::score(&21); + + assert_eq!(voters_and_targets().1, [(11, 2100), (21, 2100), (31, 500)]); + + // now chill 101. + assert_ok!(Staking::chill(RuntimeOrigin::signed(101))); + assert_eq!(Staking::status(&101), Ok(StakerStatus::Idle)); + + // the target scores of 11 and 21 are the previous score - the nominated score of the + // chilled nominator. + let score_11_after = >::score(&11); + let score_21_after = >::score(&21); + assert_eq!(score_11_after, score_11_before - nominated_score.unwrap()); + assert_eq!(score_21_after, score_21_before - nominated_score.unwrap()); + + // now the target score of 11 and 21 is only the self-stake. + assert_eq!(voters_and_targets().1, [(11, 1000), (21, 1000), (31, 500)]); + assert_eq!(score_11_after, Staking::ledger(Stash(11)).unwrap().active); + assert_eq!(score_21_after, Staking::ledger(Stash(11)).unwrap().active); + + // and we confirm the rebag happened as expected. + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 11, from: 10000, to: 1000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1000 }, + BagsEvent::Rebagged { who: 21, from: 10000, to: 1000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1000 } + ] + ); + System::reset_events(); + + // let's chill a validator now. + assert_ok!(Staking::chill(RuntimeOrigin::signed(11))); + + // the chilled validator score is updated to 0 and 11 is not part of the targets list + // anymore. + assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); + assert_eq!(>::score(&11), 0); + assert_eq!(voters_and_targets().1, [(21, 1000), (31, 500)]); + + // now, let's have 101 re-nominate 21 and kick him. Note that 101 also nominates 11 but + // that's a noop since 11 is Idle at the moment. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![21, 11])); + assert_eq!(voters_and_targets().1, [(21, 2100), (31, 500)]); + + // score of 21 and rebag hapened due to nomination. + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 2100 } + ] + ); + }) + } + + #[test] + fn kick_works() { + // Test case: kicking a nominator affects the target list score and rebagging may happen. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::kick() + ExtBuilder::default().build_and_execute(|| { + // bond extra to rebag nominated validator. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(101), 600)); + System::reset_events(); + + // 101 nominates both 11 and 21. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec!(11, 21)))); + // with score + let nominated_score = Staking::active_stake(&101); + assert_eq!(nominated_score, Ok(1100)); + + let _score_11_before = >::score(&11); + let _score_21_before = >::score(&21); + + assert_eq!(voters_and_targets().1, [(11, 2100), (21, 2100), (31, 500)]); + + // kick 101 from nominating 21. + assert_ok!(Staking::kick(RuntimeOrigin::signed(21), vec![101])); + + // target list was updated as expected, rebagging 21. + //assert_eq!(voters_and_targets().1, [(11, 2100), (21, 1000), (31, 500)]); + + // TODO(gpestana): we don't have the primitives for this, may need to add one more + // method to the OnStakingUpdate, + // eg. `OnStakingUpdate::drop_nomination(who, Vec)`, which updates the + // target score of a validator by dropping hte nominations on that nominator. + }) + } + + #[test] + fn rewards_work() { + // Test case: validator and nominators' rewards are reflected in the target list scores, + // which also may cause rebaging of the target list. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::stakers_payout() + ExtBuilder::default().build_and_execute(|| { + // all payee destinations are Staked. + let _ = Payee::::iter() + .map(|(_, dest)| assert_eq!(dest, RewardDestination::Staked)) + .collect::>(); + + // initial state voters. + assert_eq!(voters_and_targets().0, [(11, 1000), (21, 1000), (31, 500), (101, 500)]); + // initial state targets. + assert_eq!(voters_and_targets().1, [(11, 1500), (21, 1500), (31, 500)]); + + // 101 nominates validator 11 and 21. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + let stake_101_before = Staking::ledger(Stash(101)).unwrap().active; + assert_eq!(stake_101_before, 500); + + // add reward points to 11 in era 0. + Staking::reward_by_ids(vec![(11, 1)]); + + mock::start_active_era(1); + + // payout 11 and nominators. + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(11), 11, current_era() - 1)); + + // stake of nominator 101 increased since it was exposed to payout. + assert!(Staking::ledger(Stash(101)).unwrap().active > stake_101_before); + + // current bags list, nominators and validators state are OK. + assert_ok!(stake_tracker_sanity_tests()); + + // overview of the target list is as expected: 11 and 21 have increased the score after + // the payout as they were directly and indirectly exposed to the payout. + assert_eq!(voters_and_targets().1, [(11, 12575), (21, 4520), (31, 500)]); + + // rebag happened for both 11 and 21, which indirectly had its score increased. + assert_eq!( + target_bags_events(), + [ + BagsEvent::ScoreUpdated { who: 11, new_score: 1500 }, + BagsEvent::Rebagged { who: 11, from: 2000, to: 10000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 9555 }, + BagsEvent::Rebagged { who: 11, from: 10000, to: u128::MAX }, + BagsEvent::ScoreUpdated { who: 11, new_score: 12575 }, + BagsEvent::Rebagged { who: 21, from: 2000, to: 10000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 4520 } + ] + ); + }) + } + + #[test] + fn slashing_works() { + // Test case: slashing a validator affects the target list score of the validator according + // to its slashed self-stake and the slashed stake of its nominators. A slash may cause + // target list rebagging of indirect slashing (targets which were not slashed by their + // nominators were exposed to a slash from validator). + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * OnOffenceHandler::on_offence() + ExtBuilder::default().build_and_execute(|| { + assert_ok!(Staking::nominate(RuntimeOrigin::signed(41), vec![21, 11])); + // unbond 450 from 41 so that the slash will cause the rebag of a validator which + // target score was indirectly affected by the slash. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(41), 450)); + System::reset_events(); + + // checks the current targets' score and list sorting. + assert_eq!(voters_and_targets().1, [(21, 2050), (11, 2050), (31, 500)]); + assert_ok!(stake_tracker_sanity_tests()); + + // get the bonded stake of the nominators that wilbe affected by the slash. + let stake_101_before = Staking::ledger(Stash(101)).unwrap().active; + let stake_41_before = Staking::ledger(Stash(41)).unwrap().active; + + // target score of 11 is the sum of self-stake and nominations stake. + let score_11_before = >::score(&11); + assert_eq!(score_11_before, 2050); + + let self_stake_11_before = Staking::ledger(Stash(11)).unwrap().active; + assert_eq!(score_11_before, self_stake_11_before + stake_101_before + stake_41_before,); + + // same for 21. + let score_21_before = >::score(&21); + assert_eq!(score_21_before, 2050); + + let self_stake_21_before = Staking::ledger(Stash(21)).unwrap().active; + assert_eq!(score_21_before, self_stake_21_before + stake_101_before + stake_41_before,); + + // advance one era for the exposures to update given the current nominations. + start_active_era(current_era() + 1); + + // we immediately slash 11 with a 50% slash. + let exposure = Staking::eras_stakers(active_era(), &11); + let slash_percent = Perbill::from_percent(50); + on_offence_now( + &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], + &[slash_percent], + ); + + // 11 has been chilled and not part of the targets list anymore (using + // `DisablementStrategy::WhenSlashed`). + assert!(!>::contains(&11)); + assert_eq!(>::score(&11), 0); + + // self-stake of 11 has decreased by 50% due to slash. + assert_eq!( + Staking::ledger(Stash(11)).unwrap().active, + slash_percent * self_stake_11_before + ); + + // although 21 was not directly slashed, their nominators were. This will be reflected + // in its current target score. + let score_21_after = >::score(&21); + assert!(score_21_after < score_21_before); + + // slashed amounts from nominators are reflected in the score of 21. + let slashed_101 = stake_101_before - Staking::ledger(Stash(101)).unwrap().active; + let slashed_41 = stake_41_before - Staking::ledger(Stash(41)).unwrap().active; + + assert_eq!( + score_21_after, + Staking::ledger(Stash(21)).unwrap().active + + (stake_101_before - slashed_101) + + (stake_41_before - slashed_41), + ); + + // the target list has been updated accordingly and an indirect rebag of 21 happened. + assert_eq!(voters_and_targets().1, [(21, score_21_after), (31, 500)]); + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 21, from: 10000, to: 2000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1965 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1872 } + ] + ); + }) + } } From 33a935715093893bd93f4da2d9155df1697f124c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 15 Nov 2023 23:04:18 +0100 Subject: [PATCH 018/133] more stake_tracker integration tests --- substrate/frame/staking/src/tests.rs | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 4c78a9f56e8d..0783e729d54c 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7081,6 +7081,53 @@ mod stake_tracker { }) } + #[test] + fn bond_and_unbond_work() { + // Test case: unbond on validator and nominator affects the target list score + // accordingly and rebagging may happen. + // Call paths covered: + // * Call::validate() + // * Call::nominate() + // * Call::bond() + // * Call::unbond() + ExtBuilder::default().build_and_execute(|| { + // bond and nominate with stash 61. + assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, Default::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31])); + assert_ok!(stake_tracker_sanity_tests()); + + let score_31 = >::score(&31); + let self_stake_31 = Staking::ledger(Stash(31)).unwrap().active; + let self_stake_61 = Staking::ledger(Stash(61)).unwrap().active; + + // new score of 31 is the self stake + 61 stake from nomination. + assert_eq!(score_31, self_stake_31 + self_stake_61); + + // 61 nominating 31 reflected as a target list score update and rebag. + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 31, from: 500, to: 1000 }, + BagsEvent::ScoreUpdated { who: 31, new_score: score_31 } + ] + ); + System::reset_events(); + + // now we unbond a portion of the stake of 61. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(61), 250)); + assert_ok!(stake_tracker_sanity_tests()); + + // score of 61 was updated after unbonding. + assert_eq!(>::score(&31), score_31 - 250); + + // nominator unbonding was not enough to rebag 31 but score was updated, as expected. + assert_eq!( + target_bags_events(), + [BagsEvent::ScoreUpdated { who: 31, new_score: score_31 - 250 }] + ); + }) + } + #[test] fn bond_extra_works() { // Test case: bonding extra on validator and nominator affects the target list score From 01793c58335b353e5d59f7588f198e5404d171b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 16 Nov 2023 00:32:13 +0100 Subject: [PATCH 019/133] fixes target score updates when kicking --- substrate/frame/stake-tracker/README.md | 2 +- substrate/frame/staking/src/mock.rs | 20 +++++++---- substrate/frame/staking/src/pallet/mod.rs | 7 ++-- substrate/frame/staking/src/tests.rs | 41 ++++++++++++++++------- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/substrate/frame/stake-tracker/README.md b/substrate/frame/stake-tracker/README.md index 0b42eb6529da..378afa394c8d 100644 --- a/substrate/frame/stake-tracker/README.md +++ b/substrate/frame/stake-tracker/README.md @@ -1,6 +1,6 @@ # Pallet `stake-tracker` -The stake-tracker pallet is listens to staking events through implemeting the +The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] trait and forwards those events to one or multiple types (e.g. pallets) that must be kept up to date with certain updates in staking. The pallet does not expose any callables and acts as a multiplexer of staking events. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 3500d4043820..4e74113c22bd 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -909,15 +909,21 @@ pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { } // compare final result with target list. - assert_eq!(map.keys().len(), TargetBagsList::count() as usize); + let mut valid_validators_count = 0; for (target, stake) in map.into_iter() { - let stake_in_list = TargetBagsList::get_score(&target).unwrap(); - assert_eq!( - stake, stake_in_list, - "target list score of {:?} is not correct. expected {:?}, got {:?}", - target, stake, stake_in_list - ); + if let Ok(stake_in_list) = TargetBagsList::get_score(&target) { + assert_eq!( + stake, stake_in_list, + "target list score of {:?} is not correct. expected {:?}, got {:?}", + target, stake, stake_in_list + ); + valid_validators_count += 1; + } else { + // moot target nomination, do nothing. + } } + assert_eq!(valid_validators_count, TargetBagsList::count() as usize); + Ok(()) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 8451ff4b108e..c17e9eb124a7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ - EraIndex, Page, SessionIndex, + EraIndex, OnStakingUpdate, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, }; use sp_std::prelude::*; @@ -264,7 +264,7 @@ pub mod pallet { /// Something that listens to staking updates and performs actions based on the data it /// receives. - type EventListeners: sp_staking::OnStakingUpdate>; + type EventListeners: OnStakingUpdate>; /// Some parameters of the benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -1646,6 +1646,9 @@ pub mod pallet { if let Some(ref mut nom) = maybe_nom { if let Some(pos) = nom.targets.iter().position(|v| v == stash) { nom.targets.swap_remove(pos); + // update nominations and trickle down to target list score. + Self::do_add_nominator(&nom_stash, nom.clone()); + Self::deposit_event(Event::::Kicked { nominator: nom_stash.clone(), stash: stash.clone(), diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0783e729d54c..8abb2ff40c9a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7084,7 +7084,8 @@ mod stake_tracker { #[test] fn bond_and_unbond_work() { // Test case: unbond on validator and nominator affects the target list score - // accordingly and rebagging may happen. + // accordingly and rebagging may happen. It also adds some moot nominations that are + // basically noops. // Call paths covered: // * Call::validate() // * Call::nominate() @@ -7093,7 +7094,12 @@ mod stake_tracker { ExtBuilder::default().build_and_execute(|| { // bond and nominate with stash 61. assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, Default::default())); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31, 7777, 8888])); + + // 7777 and 8888 are moot nominations. + assert_noop!(Staking::status(&7777), Error::::NotStash); + assert_noop!(Staking::status(&8888), Error::::NotStash); + assert_ok!(stake_tracker_sanity_tests()); let score_31 = >::score(&31); @@ -7307,24 +7313,35 @@ mod stake_tracker { // 101 nominates both 11 and 21. assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec!(11, 21)))); // with score - let nominated_score = Staking::active_stake(&101); - assert_eq!(nominated_score, Ok(1100)); + let nominated_score = Staking::active_stake(&101).unwrap(); + assert_eq!(nominated_score, 1100); - let _score_11_before = >::score(&11); - let _score_21_before = >::score(&21); + let score_11_before = >::score(&11); + let score_21_before = >::score(&21); - assert_eq!(voters_and_targets().1, [(11, 2100), (21, 2100), (31, 500)]); + assert_eq!( + voters_and_targets().1, + [(11, score_11_before), (21, score_21_before), (31, 500)] + ); // kick 101 from nominating 21. assert_ok!(Staking::kick(RuntimeOrigin::signed(21), vec![101])); // target list was updated as expected, rebagging 21. - //assert_eq!(voters_and_targets().1, [(11, 2100), (21, 1000), (31, 500)]); + assert_eq!( + voters_and_targets().1, + [(11, score_11_before), (21, score_21_before - nominated_score), (31, 500)] + ); + + assert_eq!( + target_bags_events(), + [ + BagsEvent::Rebagged { who: 21, from: 10000, to: 1000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1000 } + ] + ); - // TODO(gpestana): we don't have the primitives for this, may need to add one more - // method to the OnStakingUpdate, - // eg. `OnStakingUpdate::drop_nomination(who, Vec)`, which updates the - // target score of a validator by dropping hte nominations on that nominator. + assert_ok!(stake_tracker_sanity_tests()); }) } From fee0514f6a469ac0dba8ce9c544d57e4f3695895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 17 Nov 2023 22:56:13 +0100 Subject: [PATCH 020/133] Addresses review comments; moves stake-tracker into staking crate --- Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 2 +- substrate/frame/staking/src/ledger.rs | 12 ++------ .../{ => staking}/stake-tracker/Cargo.toml | 30 +++++++++---------- .../{ => staking}/stake-tracker/README.md | 0 .../{ => staking}/stake-tracker/src/lib.rs | 0 .../{ => staking}/stake-tracker/src/mock.rs | 0 .../{ => staking}/stake-tracker/src/tests.rs | 0 8 files changed, 20 insertions(+), 26 deletions(-) rename substrate/frame/{ => staking}/stake-tracker/Cargo.toml (68%) rename substrate/frame/{ => staking}/stake-tracker/README.md (100%) rename substrate/frame/{ => staking}/stake-tracker/src/lib.rs (100%) rename substrate/frame/{ => staking}/stake-tracker/src/mock.rs (100%) rename substrate/frame/{ => staking}/stake-tracker/src/tests.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 6590b8a8d9be..cd6df4e9e8b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -343,8 +343,8 @@ members = [ "substrate/frame/session", "substrate/frame/session/benchmarking", "substrate/frame/society", - "substrate/frame/stake-tracker", "substrate/frame/staking", + "substrate/frame/staking/stake-tracker", "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", "substrate/frame/staking/runtime-api", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 353a63abb92f..e3bfe6ecda07 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -42,7 +42,7 @@ sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } -pallet-stake-tracker = { path = "../stake-tracker" } +pallet-stake-tracker = { path = "./stake-tracker" } pallet-staking-reward-curve = { path = "reward-curve" } pallet-bags-list = { path = "../bags-list" } substrate-test-utils = { path = "../../test-utils" } diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index d50b3d1482fc..d724de08e82f 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -184,10 +184,7 @@ impl StakingLedger { T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); Ledger::::insert(controller, &self); - >>::on_stake_update( - &self.stash, - prev_stake, - ); + T::EventListeners::on_stake_update(&self.stash, prev_stake); Ok(()) } @@ -222,13 +219,10 @@ impl StakingLedger { // call on validator remove or on nominator remove. match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { - StakerStatus::Validator => , - >>::on_validator_remove(stash), + StakerStatus::Validator => T::EventListeners::on_validator_remove(stash), StakerStatus::Nominator(_) => { let nominations = crate::Pallet::::nominations(stash).unwrap_or_default(); - >>::on_nominator_remove(stash, nominations) + T::EventListeners::on_nominator_remove(stash, nominations) }, StakerStatus::Idle => (), }; diff --git a/substrate/frame/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml similarity index 68% rename from substrate/frame/stake-tracker/Cargo.toml rename to substrate/frame/staking/stake-tracker/Cargo.toml index f1716aaf07f2..39c734debd74 100644 --- a/substrate/frame/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -15,26 +15,26 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime", features = ["serde"] } -sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking", features = ["serde"] } -sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } +sp-runtime = { version = "24.0.0", default-features = false, path = "../../../primitives/runtime", features = ["serde"] } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking", features = ["serde"] } +sp-std = { version = "8.0.0", default-features = false, path = "../../../primitives/std" } -sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elections" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support"} -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support"} +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } log = { version = "0.4.17", default-features = false } [dev-dependencies] -sp-std = { version = "8.0.0", default-features = false, path = "../../primitives/std" } -sp-core = { version = "21.0.0", path = "../../primitives/core" } -sp-io = { version = "23.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../primitives/runtime", features = ["serde"] } -sp-tracing = { version = "10.0.0", path = "../../primitives/tracing" } -pallet-bags-list = { version = "4.0.0-dev", path = "../bags-list" } -pallet-balances = { version = "4.0.0-dev", path = "../balances" } +sp-std = { version = "8.0.0", default-features = false, path = "../../../primitives/std" } +sp-core = { version = "21.0.0", path = "../../../primitives/core" } +sp-io = { version = "23.0.0", default-features = false, path = "../../../primitives/io" } +sp-runtime = { version = "24.0.0", default-features = false, path = "../../../primitives/runtime", features = ["serde"] } +sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" } +pallet-bags-list = { version = "4.0.0-dev", path = "../../bags-list" } +pallet-balances = { version = "4.0.0-dev", path = "../../balances" } [features] default = ["std"] diff --git a/substrate/frame/stake-tracker/README.md b/substrate/frame/staking/stake-tracker/README.md similarity index 100% rename from substrate/frame/stake-tracker/README.md rename to substrate/frame/staking/stake-tracker/README.md diff --git a/substrate/frame/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs similarity index 100% rename from substrate/frame/stake-tracker/src/lib.rs rename to substrate/frame/staking/stake-tracker/src/lib.rs diff --git a/substrate/frame/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs similarity index 100% rename from substrate/frame/stake-tracker/src/mock.rs rename to substrate/frame/staking/stake-tracker/src/mock.rs diff --git a/substrate/frame/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs similarity index 100% rename from substrate/frame/stake-tracker/src/tests.rs rename to substrate/frame/staking/stake-tracker/src/tests.rs From 30a9c471ec90f2a1f0f0f373b2c9a97b63ba0e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 17 Nov 2023 23:21:11 +0100 Subject: [PATCH 021/133] Adds more defensives --- substrate/frame/staking/src/ledger.rs | 30 +++++++++++++------ .../frame/staking/stake-tracker/src/lib.rs | 3 +- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index d724de08e82f..7ce1251fbe0d 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -217,15 +217,27 @@ impl StakingLedger { pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; - // call on validator remove or on nominator remove. - match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { - StakerStatus::Validator => T::EventListeners::on_validator_remove(stash), - StakerStatus::Nominator(_) => { - let nominations = crate::Pallet::::nominations(stash).unwrap_or_default(); - T::EventListeners::on_nominator_remove(stash, nominations) - }, - StakerStatus::Idle => (), - }; + // Note: by now, we expect that the caller has already called `on_nominator_remove` and/or + // `on_validator_remove`. However, we check here again and make sure the owner of the ledger + // is idle before clearing all the storage items of its ledger. + let was_cleared = + match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { + StakerStatus::Validator => { + T::EventListeners::on_validator_remove(stash); + false + }, + StakerStatus::Nominator(nominations) => { + T::EventListeners::on_nominator_remove(stash, nominations); + false + }, + StakerStatus::Idle => true, + }; + + if !was_cleared { + defensive!( + "`ledger.kill()` was called before removing the staker. this is likely a bug." + ); + } >::get(&controller).ok_or(Error::::NotController).map(|ledger| { T::Currency::remove_lock(STAKING_ID, &ledger.stash); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 8e9c3212599e..e206b0194229 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -132,12 +132,13 @@ pub mod pallet { } impl Pallet { - /// Returns the vote weight of a staker based on its current *active* stake, as returned by + /// Returns the balance of a staker based on its current *active* stake, as returned by /// the staking interface. pub(crate) fn active_vote_of(who: &T::AccountId) -> BalanceOf { T::Staking::stake(who).map(|s| s.active).defensive_unwrap_or_default() } + /// Converts a balance into the staker's vote weight. pub(crate) fn weight_of(balance: BalanceOf) -> VoteWeight { ::CurrencyToVote::to_vote( balance, From 05c40db79ce75cb41f4e843f285fe2e11c2ae493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 19 Nov 2023 12:51:01 +0100 Subject: [PATCH 022/133] ledger.kill will fail if preconditions have not been met --- substrate/frame/staking/src/ledger.rs | 26 +++++++------------------- substrate/frame/staking/src/tests.rs | 11 +++++++++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 7ce1251fbe0d..19e776c8bd53 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -218,25 +218,13 @@ impl StakingLedger { let controller = >::get(stash).ok_or(Error::::NotStash)?; // Note: by now, we expect that the caller has already called `on_nominator_remove` and/or - // `on_validator_remove`. However, we check here again and make sure the owner of the ledger - // is idle before clearing all the storage items of its ledger. - let was_cleared = - match crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) { - StakerStatus::Validator => { - T::EventListeners::on_validator_remove(stash); - false - }, - StakerStatus::Nominator(nominations) => { - T::EventListeners::on_nominator_remove(stash, nominations); - false - }, - StakerStatus::Idle => true, - }; - - if !was_cleared { - defensive!( - "`ledger.kill()` was called before removing the staker. this is likely a bug." - ); + // `on_validator_remove` and the stash is idle. This can be achieved by calling + // `[crate::Pallet::::kill_stash]` prior to this call. + if crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) != + StakerStatus::Idle + { + defensive!("tried to kill a ledger before calling `kill_stash()`. this may lead to inconsistent states."); + return Err(Error::::BadState) } >::get(&controller).ok_or(Error::::NotController).map(|ledger| { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 8abb2ff40c9a..54ad212c9e6d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -140,6 +140,17 @@ fn kill_stash_works() { }); } +#[test] +#[should_panic] +fn kill_ledger_preconditions_works() { + ExtBuilder::default().build_and_execute(|| { + // Account 11 (also controller) is stashed and locked + assert_eq!(Staking::bonded(&11), Some(11)); + // Trying to call `Ledger::kill` directly will fail. + assert!(StakingLedger::::kill(&11).is_err()); + }) +} + #[test] fn basic_setup_works() { // Verifies initial conditions of mock From 77d77628c7d21f928e9bd536e9ee36ee78d240d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 19 Nov 2023 15:33:21 +0100 Subject: [PATCH 023/133] fixes remaining tests --- substrate/frame/staking/src/tests.rs | 121 +++++++++++++++++---------- 1 file changed, 77 insertions(+), 44 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 54ad212c9e6d..3093d6c499df 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -335,10 +335,30 @@ fn rewards_should_work() { individual: vec![(11, 100), (21, 50)].into_iter().collect(), } ); - let part_for_11 = Perbill::from_rational::(1000, 1125); - let part_for_21 = Perbill::from_rational::(1000, 1375); - let part_for_101_from_11 = Perbill::from_rational::(125, 1125); - let part_for_101_from_21 = Perbill::from_rational::(375, 1375); + + let exposure_11 = EraInfo::::get_full_exposure(active_era(), &11).total; + let exposure_21 = EraInfo::::get_full_exposure(active_era(), &21).total; + + let exposure_101_to_11 = EraInfo::::get_full_exposure(active_era(), &11) + .others + .iter() + .find(|o| o.who == 101) + .unwrap() + .value; + let exposure_101_to_21 = EraInfo::::get_full_exposure(active_era(), &21) + .others + .iter() + .find(|o| o.who == 101) + .unwrap() + .value; + + assert_eq!(exposure_101_to_11, 375); + assert_eq!(exposure_101_to_21, 125); + + let part_for_11 = Perbill::from_rational(1000, exposure_11); + let part_for_21 = Perbill::from_rational(1000, exposure_21); + let part_for_101_from_11 = Perbill::from_rational::(exposure_101_to_11, exposure_11); + let part_for_101_from_21 = Perbill::from_rational::(exposure_101_to_21, exposure_21); start_session(2); start_session(3); @@ -654,7 +674,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(ErasStakersPaged::::iter_prefix_values((active_era(),)).count(), 2); assert_eq!( - Staking::eras_stakers(active_era(), &11), + Staking::eras_stakers(active_era(), &21), Exposure { total: 1000 + 800, own: 1000, @@ -665,7 +685,7 @@ fn nominating_and_rewards_should_work() { }, ); assert_eq!( - Staking::eras_stakers(active_era(), &21), + Staking::eras_stakers(active_era(), &11), Exposure { total: 1000 + 1200, own: 1000, @@ -689,32 +709,32 @@ fn nominating_and_rewards_should_work() { mock::make_all_reward_payment(1); let payout_for_11 = total_payout_1 / 3; let payout_for_21 = 2 * total_payout_1 / 3; - // Nominator 2: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> + // Nominator 2: has [400/1800 ~ 2/9 from 21] + [600/2200 ~ 3/11 from 11]'s reward. ==> // 2/9 + 3/11 assert_eq_error_rate!( Balances::total_balance(&1), - initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), + initial_balance + (2 * payout_for_21 / 9 + 3 * payout_for_11 / 11), 2, ); - // Nominator 3: has [400/1800 ~ 2/9 from 10] + [600/2200 ~ 3/11 from 21]'s reward. ==> + // Nominator 3: has [400/1800 ~ 2/9 from 21] + [600/2200 ~ 3/11 from 11]'s reward. ==> // 2/9 + 3/11 assert_eq_error_rate!( Balances::total_balance(&3), - initial_balance + (2 * payout_for_11 / 9 + 3 * payout_for_21 / 11), + initial_balance + (2 * payout_for_21 / 9 + 3 * payout_for_11 / 11), 2, ); - // Validator 11: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 + // Validator 21: got 800 / 1800 external stake => 8/18 =? 4/9 => Validator's share = 5/9 assert_eq_error_rate!( - Balances::total_balance(&11), - initial_balance + 5 * payout_for_11 / 9, + Balances::total_balance(&21), + initial_balance_21 + 5 * payout_for_21 / 9, 2, ); - // Validator 21: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = + // Validator 11: got 1200 / 2200 external stake => 12/22 =? 6/11 => Validator's share = // 5/11 assert_eq_error_rate!( - Balances::total_balance(&21), - initial_balance_21 + 5 * payout_for_21 / 11, + Balances::total_balance(&11), + initial_balance + 5 * payout_for_11 / 11, 2, ); }); @@ -2507,7 +2527,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // amount, but less and less if they submit multiple reports in one span. ExtBuilder::default().build_and_execute(|| { // The reporters' reward is calculated from the total exposure. - let initial_balance = 1125; + let initial_balance = EraInfo::::get_full_exposure(active_era(), &11).total; assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); @@ -2537,7 +2557,7 @@ fn subsequent_reports_in_same_span_pay_out_less() { // F1 * (reward_proportion * slash - prior_payout) // 50% * (10% * (initial_balance / 2) - prior_payout) let reward = ((initial_balance / 20) - prior_payout) / 2; - assert_eq!(Balances::free_balance(1), 10 + prior_payout + reward); + assert_eq_error_rate!(Balances::free_balance(1), 10 + prior_payout + reward, 2); }); } @@ -2737,7 +2757,6 @@ fn garbage_collection_on_window_pruning() { }) } -// TODO(gpestana): double check #[test] fn slashing_nominators_by_span_max() { ExtBuilder::default().build_and_execute(|| { @@ -2760,14 +2779,14 @@ fn slashing_nominators_by_span_max() { offender: (11, Staking::eras_stakers(active_era(), &11)), reporters: vec![], }], - &[Perbill::from_percent(10)], + &[Perbill::from_percent(5)], 2, DisableStrategy::WhenSlashed, ); - assert_eq!(Balances::free_balance(11), 900); + assert_eq!(Balances::free_balance(11), 950); - let slash_1_amount = Perbill::from_percent(10) * nominated_value_11; + let slash_1_amount = Perbill::from_percent(5) * nominated_value_11; assert_eq!(Balances::free_balance(101), 2000 - slash_1_amount); let expected_spans = vec![ @@ -2787,16 +2806,16 @@ fn slashing_nominators_by_span_max() { offender: (21, Staking::eras_stakers(active_era(), &21)), reporters: vec![], }], - &[Perbill::from_percent(30)], + &[Perbill::from_percent(80)], 3, DisableStrategy::WhenSlashed, ); // 11 was not further slashed, but 21 and 101 were. - assert_eq!(Balances::free_balance(11), 900); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(Balances::free_balance(11), 950); + assert_eq!(Balances::free_balance(21), 1200); - let slash_2_amount = Perbill::from_percent(30) * nominated_value_21; + let slash_2_amount = Perbill::from_percent(80) * nominated_value_21; assert!(slash_2_amount > slash_1_amount); // only the maximum slash in a single span is taken. @@ -2816,7 +2835,7 @@ fn slashing_nominators_by_span_max() { // 11 was further slashed, but 21 and 101 were not. assert_eq!(Balances::free_balance(11), 800); - assert_eq!(Balances::free_balance(21), 1700); + assert_eq!(Balances::free_balance(21), 1200); let slash_3_amount = Perbill::from_percent(20) * nominated_value_21; assert!(slash_3_amount < slash_2_amount); @@ -3256,14 +3275,19 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); - assert_eq!(exposure_21.total, 1000 + 125); - assert_eq!(exposure_11.total, 1000 + 375); + let exposure_101_for_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; + let exposure_101_for_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; + + assert_eq!(exposure_11.total, 1000 + exposure_101_for_11); + assert_eq!(exposure_21.total, 1000 + exposure_101_for_21); on_offence_now( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], &[Perbill::from_percent(10)], ); + let nominator_slash_amount_11 = exposure_101_for_11 / 10; + assert_eq!( staking_events_since_last_call(), vec![ @@ -3277,12 +3301,11 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid slash_era: 1 }, Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 37 }, + Event::Slashed { staker: 101, amount: nominator_slash_amount_11 }, ] ); // post-slash balance - let nominator_slash_amount_11 = 375 / 10; assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); @@ -3296,15 +3319,18 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); - // TODO(gpestana): re-do calculations - println!("{:?}", exposure_11); - println!("{:?}", exposure_21); - // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 - // 900 + 146 - assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); - // 1000 + 342 - assert!(matches!(exposure_21, Exposure { own: 1000, total: 1342, .. })); - assert_eq!(500 - 146 - 342, nominator_slash_amount_11); + let exposure_101_for_11 = exposure_11.others.iter().find(|o| o.who == 101).unwrap().value; + let exposure_101_for_21 = exposure_21.others.iter().find(|o| o.who == 101).unwrap().value; + + assert_eq!(exposure_101_for_11, 136); + assert_eq!(exposure_101_for_21, 327); + + // 11's own expo is reduced. sum of support from 11 is less (136), thus total is + // 900 + 136 + assert!(matches!(exposure_11, Exposure { own: 900, total: 1036, .. })); + // 1000 + 327 + assert!(matches!(exposure_21, Exposure { own: 1000, total: 1327, .. })); + assert_eq!(500 - exposure_101_for_11 - exposure_101_for_21, nominator_slash_amount_11); }); } @@ -3545,8 +3571,13 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let init_balance_11 = Balances::total_balance(&11); let init_balance_101 = Balances::total_balance(&101); - let part_for_11 = Perbill::from_rational::(1000, 1125); - let part_for_101 = Perbill::from_rational::(125, 1125); + let exposures = EraInfo::::get_full_exposure(active_era(), &11); + let exposure_11 = exposures.total; + let self_stake_11 = exposures.own; + let exposure_101_for_11 = exposures.others.iter().find(|o| o.who == 101).unwrap().value; + + let part_for_11 = Perbill::from_rational::(self_stake_11, exposure_11); + let part_for_101 = Perbill::from_rational::(exposure_101_for_11, exposure_11); // Check state Payee::::insert(11, RewardDestination::Controller); @@ -3606,13 +3637,15 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // Era 0 can't be rewarded anymore and current era can't be rewarded yet // only era 1 and 2 can be rewarded. - assert_eq!( + assert_eq_error_rate!( Balances::total_balance(&11), init_balance_11 + part_for_11 * (total_payout_1 + total_payout_2), + 2, ); - assert_eq!( + assert_eq_error_rate!( Balances::total_balance(&101), init_balance_101 + part_for_101 * (total_payout_1 + total_payout_2), + 2, ); }); } From f3e41850dd404a858917dd1fe338069b1554ce87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 19 Nov 2023 18:12:50 +0100 Subject: [PATCH 024/133] Adds stake-tracker to westend runtime --- Cargo.lock | 2 + polkadot/runtime/westend/Cargo.toml | 4 + .../runtime/westend/src/bag_thresholds.rs | 208 +++++++++++++++++- polkadot/runtime/westend/src/lib.rs | 36 ++- .../test-staking-e2e/Cargo.toml | 1 + .../test-staking-e2e/src/mock.rs | 37 +++- 6 files changed, 273 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a77d05d11773..cce64c06489e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9763,6 +9763,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-multi-phase", "pallet-session", + "pallet-stake-tracker", "pallet-staking", "pallet-timestamp", "parity-scale-codec", @@ -20728,6 +20729,7 @@ dependencies = [ "pallet-session", "pallet-session-benchmarking", "pallet-society", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-runtime-api", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index eaebf01e3a76..3238a7b19157 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -78,6 +78,7 @@ pallet-scheduler = { path = "../../../substrate/frame/scheduler", default-featur pallet-session = { path = "../../../substrate/frame/session", default-features = false } pallet-society = { path = "../../../substrate/frame/society", default-features = false } pallet-staking = { path = "../../../substrate/frame/staking", default-features = false } +pallet-stake-tracker = { path = "../../../substrate/frame/staking/stake-tracker", default-features = false } pallet-staking-reward-curve = { package = "pallet-staking-reward-curve", path = "../../../substrate/frame/staking/reward-curve" } pallet-staking-runtime-api = { path = "../../../substrate/frame/staking/runtime-api", default-features = false } pallet-state-trie-migration = { path = "../../../substrate/frame/state-trie-migration", default-features = false } @@ -185,6 +186,7 @@ std = [ "pallet-society/std", "pallet-staking-runtime-api/std", "pallet-staking/std", + "pallet-stake-tracker/std", "pallet-state-trie-migration/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -264,6 +266,7 @@ runtime-benchmarks = [ "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -322,6 +325,7 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", diff --git a/polkadot/runtime/westend/src/bag_thresholds.rs b/polkadot/runtime/westend/src/bag_thresholds.rs index de28520d4619..9bb80ca3571d 100644 --- a/polkadot/runtime/westend/src/bag_thresholds.rs +++ b/polkadot/runtime/westend/src/bag_thresholds.rs @@ -29,8 +29,212 @@ pub const EXISTENTIAL_WEIGHT: u64 = 10_000_000_000; #[allow(unused)] pub const CONSTANT_RATIO: f64 = 1.1131723507077667; -/// Upper thresholds delimiting the bag list. -pub const THRESHOLDS: [u64; 200] = [ +/// Upper thresholds delimiting the voters bag list. +pub const VOTER_THRESHOLDS: [u64; 200] = [ + 10_000_000_000, + 11_131_723_507, + 12_391_526_824, + 13_793_905_044, + 15_354_993_703, + 17_092_754_435, + 19_027_181_634, + 21_180_532_507, + 23_577_583_160, + 26_245_913_670, + 29_216_225_417, + 32_522_694_326, + 36_203_364_094, + 40_300_583_912, + 44_861_495_728, + 49_938_576_656, + 55_590_242_767, + 61_881_521_217, + 68_884_798_439, + 76_680_653_006, + 85_358_782_760, + 95_019_036_859, + 105_772_564_622, + 117_743_094_401, + 131_068_357_174, + 145_901_671_259, + 162_413_706_368, + 180_794_447_305, + 201_255_379_901, + 224_031_924_337, + 249_386_143_848, + 277_609_759_981, + 309_027_509_097, + 344_000_878_735, + 382_932_266_827, + 426_269_611_626, + 474_511_545_609, + 528_213_132_664, + 587_992_254_562, + 654_536_720_209, + 728_612_179_460, + 811_070_932_564, + 902_861_736_593, + 1_005_040_721_687, + 1_118_783_542_717, + 1_245_398_906_179, + 1_386_343_627_960, + 1_543_239_395_225, + 1_717_891_425_287, + 1_912_309_236_147, + 2_128_729_767_682, + 2_369_643_119_512, + 2_637_821_201_686, + 2_936_349_627_828, + 3_268_663_217_709, + 3_638_585_517_729, + 4_050_372_794_022, + 4_508_763_004_364, + 5_019_030_312_352, + 5_587_045_771_074, + 6_219_344_874_498, + 6_923_202_753_807, + 7_706_717_883_882, + 8_578_905_263_043, + 9_549_800_138_161, + 10_630_573_468_586, + 11_833_660_457_397, + 13_172_903_628_838, + 14_663_712_098_160, + 16_323_238_866_411, + 18_170_578_180_087, + 20_226_985_226_447, + 22_516_120_692_255, + 25_064_322_999_817, + 27_900_911_352_605, + 31_058_523_077_268, + 34_573_489_143_434, + 38_486_252_181_966, + 42_841_831_811_331, + 47_690_342_626_046, + 53_087_570_807_094, + 59_095_615_988_698, + 65_783_605_766_662, + 73_228_491_069_308, + 81_515_931_542_404, + 90_741_281_135_191, + 101_010_685_227_495, + 112_442_301_921_293, + 125_167_661_548_718, + 139_333_180_038_781, + 155_101_843_555_358, + 172_655_083_789_626, + 192_194_865_483_744, + 213_946_010_204_502, + 238_158_783_103_893, + 265_111_772_429_462, + 295_115_094_915_607, + 328_513_963_936_552, + 365_692_661_475_578, + 407_078_959_611_349, + 453_149_042_394_237, + 504_432_984_742_966, + 561_520_851_400_862, + 625_069_486_125_324, + 695_810_069_225_823, + 774_556_530_406_243, + 862_214_913_708_369, + 959_793_802_308_039, + 1_068_415_923_109_985, + 1_189_331_064_661_951, + 1_323_930_457_019_515, + 1_473_762_779_014_021, + 1_640_551_977_100_649, + 1_826_217_100_807_404, + 2_032_894_383_008_501, + 2_262_961_819_074_188, + 2_519_066_527_700_738, + 2_804_155_208_229_882, + 3_121_508_044_894_685, + 3_474_776_448_088_622, + 3_868_025_066_902_796, + 4_305_778_556_320_752, + 4_793_073_637_166_665, + 5_335_517_047_800_242, + 5_939_350_054_341_159, + 6_611_520_261_667_250, + 7_359_761_551_432_161, + 8_192_683_066_856_378, + 9_119_868_268_136_230, + 10_151_985_198_186_376, + 11_300_909_227_415_580, + 12_579_859_689_817_292, + 14_003_551_982_487_792, + 15_588_366_878_604_342, + 17_352_539_001_951_086, + 19_316_366_631_550_092, + 21_502_445_250_375_680, + 23_935_927_525_325_748, + 26_644_812_709_737_600, + 29_660_268_798_266_784, + 33_016_991_140_790_860, + 36_753_601_641_491_664, + 40_913_093_136_236_104, + 45_543_324_061_189_736, + 50_697_569_104_240_168, + 56_435_132_174_936_472, + 62_822_028_745_677_552, + 69_931_745_415_056_768, + 77_846_085_432_775_824, + 86_656_109_914_600_688, + 96_463_185_576_826_656, + 107_380_151_045_315_664, + 119_532_615_158_469_088, + 133_060_402_202_199_856, + 148_119_160_705_543_712, + 164_882_154_307_451_552, + 183_542_255_300_186_560, + 204_314_163_786_713_728, + 227_436_877_985_347_776, + 253_176_444_104_585_088, + 281_829_017_427_734_464, + 313_724_269_827_691_328, + 349_229_182_918_168_832, + 388_752_270_484_770_624, + 432_748_278_778_513_664, + 481_723_418_752_617_984, + 536_241_190_443_833_600, + 596_928_866_512_693_376, + 664_484_709_541_257_600, + 739_686_006_129_409_280, + 823_398_010_228_713_984, + 916_583_898_614_395_264, + 1_020_315_853_041_475_584, + 1_135_787_396_594_579_584, + 1_264_327_126_171_442_688, + 1_407_413_999_103_859_968, + 1_566_694_349_801_462_272, + 1_744_000_832_209_069_824, + 1_941_373_506_026_471_680, + 2_161_083_309_305_266_176, + 2_405_658_187_494_662_656, + 2_677_912_179_572_818_944, + 2_980_977_795_924_034_048, + 3_318_342_060_496_414_208, + 3_693_886_631_935_247_360, + 4_111_932_465_319_354_368, + 4_577_289_528_371_127_808, + 5_095_312_144_166_932_480, + 5_671_960_597_112_134_656, + 6_313_869_711_009_142_784, + 7_028_425_188_266_614_784, + 7_823_848_588_596_424_704, + 8_709_291_924_949_524_480, + 9_694_942_965_096_232_960, + 10_792_142_450_433_898_496, + 12_013_514_580_722_579_456, + 13_373_112_266_084_982_784, + 14_886_578_817_516_689_408, + 16_571_327_936_291_497_984, + 18_446_744_073_709_551_615, +]; + +/// Upper thresholds delimiting the targets bag list. +pub const TARGET_THRESHOLDS: [crate::Balance; 200] = [ 10_000_000_000, 11_131_723_507, 12_391_526_824, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index ec94973af4f3..694d0696610d 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -106,7 +106,6 @@ pub use pallet_balances::Call as BalancesCall; pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; #[cfg(feature = "std")] pub use pallet_staking::StakerStatus; -use pallet_staking::UseValidatorsMap; pub use pallet_timestamp::Call as TimestampCall; use sp_runtime::traits::Get; #[cfg(any(feature = "std", test))] @@ -614,7 +613,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { } parameter_types! { - pub const BagThresholds: &'static [u64] = &bag_thresholds::THRESHOLDS; + pub const VoterBagThresholds: &'static [u64] = &bag_thresholds::VOTER_THRESHOLDS; + pub const TargetBagThresholds: &'static [Balance] = &bag_thresholds::TARGET_THRESHOLDS; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -622,10 +622,26 @@ impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ScoreProvider = Staking; type WeightInfo = weights::pallet_bags_list::WeightInfo; - type BagThresholds = BagThresholds; + type BagThresholds = VoterBagThresholds; type Score = sp_npos_elections::VoteWeight; } +type TargetBagsListInstance = pallet_bags_list::Instance2; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ScoreProvider = pallet_bags_list::Pallet; + type WeightInfo = weights::pallet_bags_list::WeightInfo; + type BagThresholds = TargetBagThresholds; + type Score = Balance; +} + +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterList; + type TargetList = TargetList; +} + pallet_staking_reward_curve::build! { const REWARD_CURVE: PiecewiseLinear<'static> = curve!( min_inflation: 0_025_000, @@ -675,12 +691,12 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; - type TargetList = UseValidatorsMap; + type TargetList = TargetList; type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; type BenchmarkingConfig = runtime_common::StakingBenchmarkingConfig; - type EventListeners = NominationPools; + type EventListeners = (StakeTracker, NominationPools); type WeightInfo = weights::pallet_staking::WeightInfo; } @@ -1036,6 +1052,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::Slots(..) | RuntimeCall::Auctions(..) | // Specifically omitting the entire XCM Pallet RuntimeCall::VoterList(..) | + RuntimeCall::TargetList(..) | RuntimeCall::NominationPools(..) | RuntimeCall::FastUnstake(..) ), @@ -1046,6 +1063,7 @@ impl InstanceFilter for ProxyType { RuntimeCall::Session(..) | RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | + RuntimeCall::TargetList(..) | RuntimeCall::NominationPools(..) ) }, @@ -1440,6 +1458,12 @@ construct_runtime! { // Provides a semi-sorted list of nominators for staking. VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 25, + // Provides a sorted list of validators for staking. + TargetList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 103, + + // Stake tracker for staking. + StakeTracker: pallet_stake_tracker::{Pallet, Storage} = 104, + // Nomination pools for staking. NominationPools: pallet_nomination_pools::{Pallet, Call, Storage, Event, Config, FreezeReason} = 29, @@ -1597,6 +1621,8 @@ mod benches { [runtime_parachains::paras_inherent, ParaInherent] // Substrate [pallet_bags_list, VoterList] + [pallet_bags_list, TargetList] + [pallet_stake_tracker, StakeTracker] [pallet_balances, Balances] [pallet_conviction_voting, ConvictionVoting] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index f5d1991d1990..f83b391016eb 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -32,6 +32,7 @@ frame-election-provider-support = { path = "../../election-provider-support" } pallet-election-provider-multi-phase = { path = ".." } pallet-staking = { path = "../../staking" } +pallet-stake-tracker = { path = "../../staking/stake-tracker" } pallet-bags-list = { path = "../../bags-list" } pallet-balances = { path = "../../balances" } pallet-timestamp = { path = "../../timestamp" } diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 751ffc07aa5d..e6c2ce4a6b24 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -70,7 +70,9 @@ frame_support::construct_runtime!( ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, Balances: pallet_balances, - BagsList: pallet_bags_list, + VoterBagsList: pallet_bags_list::, + TargetBagsList: pallet_bags_list::, + StakeTracker: pallet_stake_tracker, Session: pallet_session, Historical: pallet_session::historical, Timestamp: pallet_timestamp, @@ -230,10 +232,12 @@ impl MinerConfig for Runtime { } } -const THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +const VOTERS_THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +const TARGETS_THRESHOLDS: [Balance; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; parameter_types! { - pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; + pub static VoterBagThresholds: &'static [VoteWeight] = &VOTERS_THRESHOLDS; + pub static TargetBagThresholds: &'static [Balance] = &TARGETS_THRESHOLDS; pub const SessionsPerEra: sp_staking::SessionIndex = 2; pub const BondingDuration: sp_staking::EraIndex = 28; pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. @@ -241,14 +245,31 @@ parameter_types! { pub HistoryDepth: u32 = 84; } -impl pallet_bags_list::Config for Runtime { +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type ScoreProvider = Staking; - type BagThresholds = BagThresholds; + type BagThresholds = VoterBagThresholds; type Score = VoteWeight; } +type TargetBagsListInstance = pallet_bags_list::Instance2; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = Staking; + type BagThresholds = TargetBagThresholds; + type Score = VoteWeight; +} + +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterBagsList; + type TargetList = TargetBagsList; +} + /// Upper limit on the number of NPOS nominations. const MAX_QUOTA_NOMINATIONS: u32 = 16; @@ -272,12 +293,12 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; - type VoterList = BagsList; + type VoterList = VoterBagsList; type NominationsQuota = pallet_staking::FixedNominationsQuota; - type TargetList = pallet_staking::UseValidatorsMap; + type TargetList = TargetBagsList; type MaxUnlockingChunks = ConstU32<32>; type HistoryDepth = HistoryDepth; - type EventListeners = (); + type EventListeners = StakeTracker; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; } From bd2d7e2450918f256c689fe828005b4f0a8f0262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 19 Nov 2023 18:34:16 +0100 Subject: [PATCH 025/133] nits to make CI happy --- substrate/frame/staking/stake-tracker/src/mock.rs | 2 +- substrate/frame/staking/stake-tracker/src/tests.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 6e20f3511f10..144c10b8c07f 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -311,7 +311,7 @@ pub(crate) fn update_nominations_of(who: AccountId, new_nominations: Nominations let (current_stake, prev_nominations) = current_nom.get(&who).unwrap(); TestNominators::mutate(|n| { - n.insert(who, (current_stake.clone(), new_nominations)); + n.insert(who, (*current_stake, new_nominations)); }); >::on_nominator_update( diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 14d990c1cde6..04d6912a4909 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -354,8 +354,8 @@ mod staking_integration { #[test] fn staking_interface_works() { ExtBuilder::default().build_and_execute(|| { - assert_eq!(TestNominators::get().iter().count(), 0); - assert_eq!(TestValidators::get().iter().count(), 0); + assert_eq!(TestNominators::get().len(), 0); + assert_eq!(TestValidators::get().len(), 0); add_nominator(1, 100); let n = TestNominators::get(); From ed3cc4822f5ef2189d2facee66c075158d55e177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Nov 2023 12:15:48 +0100 Subject: [PATCH 026/133] Update substrate/frame/staking/src/mock.rs Co-authored-by: Liam Aharon --- substrate/frame/staking/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4e74113c22bd..2c882306ad72 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -603,7 +603,7 @@ impl ExtBuilder { ext.execute_with(test); ext.execute_with(|| { Staking::do_try_state(System::block_number()) - .map_err(|err| println!(" 🕵️‍♂️ try_state failue: {:?}", err)) + .map_err(|err| println!(" 🕵️‍♂️ try_state failure: {:?}", err)) .unwrap(); }); } From dc141ad58130c5293a4fcc79517c1b3df1ea2913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Nov 2023 12:15:58 +0100 Subject: [PATCH 027/133] Update substrate/frame/staking/stake-tracker/src/mock.rs Co-authored-by: Liam Aharon --- substrate/frame/staking/stake-tracker/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 144c10b8c07f..7feaaa2adfe4 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -415,7 +415,7 @@ impl ExtBuilder { if self.populate_lists { populate_lists(); } - // move pass genesis to register events. + // move past genesis to register events. System::set_block_number(1); test() From bbb5740d0467b0460e2de33f7034b3c653bf1e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Nov 2023 12:16:19 +0100 Subject: [PATCH 028/133] Update substrate/frame/staking/stake-tracker/src/lib.rs Co-authored-by: Liam Aharon --- substrate/frame/staking/stake-tracker/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index e206b0194229..54d8448bf2e8 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -367,13 +367,13 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_remove(who, vec![]); } - // Fired when an existing nominator updates their nominations. - // - // This is called when a nominator updates their nominations. The nominator's stake remains the - // same (updates to the nominator's stake should emit [`Self::on_stake_update`] instead). - // However, the score of the nominated targets must be updated accordingly. - // - // Note: it is assumed that who's staking state is updated *before* calling this method. + /// Fired when an existing nominator updates their nominations. + /// + /// This is called when a nominator updates their nominations. The nominator's stake remains the + /// same (updates to the nominator's stake should emit [`Self::on_stake_update`] instead). + /// However, the score of the nominated targets must be updated accordingly. + /// + /// Note: it is assumed that who's staking state is updated *before* calling this method. fn on_nominator_update(who: &T::AccountId, prev_nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); From 1d98e7dc9f08c3fe146cdfaad5ef7b2c93458b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Nov 2023 12:18:56 +0100 Subject: [PATCH 029/133] Update substrate/frame/staking/stake-tracker/Cargo.toml Co-authored-by: Liam Aharon --- substrate/frame/staking/stake-tracker/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 39c734debd74..4a7a92a445c9 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Parity Technologies "] homepage = "https://substrate.io" edition = "2021" license = "Apache-2.0" -repository = "https://github.com/paritytech/substrate" +repository = "https://github.com/paritytech/polkadot-sdk" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] From 964413c2c01af11bfc3bfd0ad0b0d809c747f777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 21 Nov 2023 18:34:34 +0100 Subject: [PATCH 030/133] Adds try-state checks to stake-tracker pallet; review nits --- substrate/frame/staking/src/mock.rs | 2 + .../frame/staking/stake-tracker/README.md | 4 +- .../frame/staking/stake-tracker/src/lib.rs | 91 ++++++++++++++++++- .../frame/staking/stake-tracker/src/mock.rs | 17 +++- .../frame/staking/stake-tracker/src/tests.rs | 17 +++- 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 2c882306ad72..50baa12afca5 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -876,6 +876,8 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } +/// Similar to the try-state checks of the stake-tracker pallet, but works without `try-runtime` +/// feature enabled. pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { use sp_staking::StakingInterface; diff --git a/substrate/frame/staking/stake-tracker/README.md b/substrate/frame/staking/stake-tracker/README.md index 378afa394c8d..a10afc9f5924 100644 --- a/substrate/frame/staking/stake-tracker/README.md +++ b/substrate/frame/staking/stake-tracker/README.md @@ -5,5 +5,5 @@ The stake-tracker pallet listens to staking events through implementing the must be kept up to date with certain updates in staking. The pallet does not expose any callables and acts as a multiplexer of staking events. - Currently, the stake tracker pallet is used to update the semi-sorted target and voter lists - implemented through bags lists. +Currently, the stake tracker pallet is used to update the sorted targe list and semi-sorted voter +lists implemented through bags lists. diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 54d8448bf2e8..0992e6c5f505 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -102,6 +102,7 @@ pub mod pallet { use crate::*; use frame_election_provider_support::{ExtendedBalance, VoteWeight}; use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::BlockNumberFor; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -131,6 +132,14 @@ pub mod pallet { >; } + #[pallet::hooks] + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } + impl Pallet { /// Returns the balance of a staker based on its current *active* stake, as returned by /// the staking interface. @@ -206,6 +215,86 @@ pub mod pallet { }, } } + + #[cfg(any(test, feature = "try-runtime"))] + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + // Invariants 1: + // * All stakers in the target list are of type validator. + for target in T::TargetList::iter() { + if ::status(&target).unwrap_or(StakerStatus::Idle) != + StakerStatus::Validator + { + return Err("staker in target list is not a validator")? + } + } + + // Invariant 2: + // * The target score in the target list is the sum of self-stake and all stake from + // nominations. + // * All valid validators are part of the target list. + let mut map: BTreeMap, ExtendedBalance> = BTreeMap::new(); + + for nominator in T::VoterList::iter() { + if let Some(nominations) = ::nominations(&nominator) + { + let score = + >>::get_score(&nominator) + .map_err(|_| "nominator score must exist in voter bags list")?; + + for nomination in nominations { + if let Some(stake) = map.get_mut(&nomination) { + *stake += score as ExtendedBalance; + } else { + map.insert(nomination, score.into()); + } + } + } + } + for target in T::TargetList::iter() { + let score = + >>::get_score(&target) + .map_err(|_| "target score must exist in voter bags list")?; + + if let Some(stake) = map.get_mut(&target) { + *stake += score as ExtendedBalance; + } else { + map.insert(target, score.into()); + } + } + + // compare final result with target list. + let mut valid_validators_count = 0; + for (target, stake) in map.into_iter() { + if let Ok(stake_in_list) = T::TargetList::get_score(&target) { + let stake_in_list = Self::to_vote_extended(stake_in_list); + + if stake != stake_in_list { + log!( + error, + "try-runtime: score of {:?} in list: {:?}, sum of all stake: {:?}", + target, + stake_in_list, + stake, + ); + return Err( + "target score in the target list is different than the expected".into() + ) + } + + valid_validators_count += 1; + } else { + // moot target nomination, do nothing. + } + } + + let count = T::TargetList::count() as usize; + ensure!( + valid_validators_count == count, + "target list count is different from total of targets.", + ); + + Ok(()) + } } } @@ -409,7 +498,7 @@ impl OnStakingUpdate> for Pallet { // noop: the updates to target and voter lists when applying a slash are performed // through [`Self::on_nominator_remove`] and [`Self::on_validator_remove`] when the stakers are // chilled. When the slash is applied, the ledger is updated of the affected stashes is, thus - // the stake is propagated through the `[Self::update::]`. + // the stake is propagated through the [`Self::update::`]. fn on_slash( _stash: &T::AccountId, _slashed_active: BalanceOf, diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 7feaaa2adfe4..0568190197f3 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -278,11 +278,6 @@ pub(crate) fn stake_of(who: AccountId) -> Option> { StakingMock::stake(&who).ok() } -#[allow(dead_code)] -pub(crate) fn score_of_voter(who: AccountId) -> VoteWeight { - >::score(&who) -} - pub(crate) fn score_of_target(who: AccountId) -> Balance { as ScoreProvider>::score( &who, @@ -389,6 +384,10 @@ pub(crate) fn voter_bags_events() -> Vec>() } +parameter_types! { + pub static DisableTryRuntimeChecks: bool = false; +} + #[derive(Default, Copy, Clone)] pub struct ExtBuilder { populate_lists: bool, @@ -420,5 +419,13 @@ impl ExtBuilder { test() }); + + if !DisableTryRuntimeChecks::get() { + ext.execute_with(|| { + StakeTracker::do_try_state() + .map_err(|err| println!(" 🕵️‍♂️ try_state failure: {:?}", err)) + .unwrap(); + }); + } } } diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 04d6912a4909..8246af32e9bc 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -66,6 +66,10 @@ fn update_score_works() { ); assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::get_score(&1), Ok(0)); + + // disables the try runtime checks since the score of 10 was updated manually, so the target + // list was not updated accordingly. + DisableTryRuntimeChecks::set(true); }) } @@ -156,6 +160,7 @@ fn on_stake_update_sorting_works() { let initial_sort = TargetBagsList::iter().collect::>(); // 10 starts with more score than 11. + assert_eq!(score_of_target(10), 300); assert_eq!(score_of_target(11), 200); assert!(score_of_target(10) > score_of_target(11)); assert_eq!(initial_sort, [10, 11]); @@ -164,13 +169,15 @@ fn on_stake_update_sorting_works() { add_nominator_with_nominations(5, 200, vec![11]); assert_eq!(score_of_target(11), 400); assert!(score_of_target(10) < score_of_target(11)); + // sorting is now reverted as expected. assert_eq!( TargetBagsList::iter().collect::>(), initial_sort.iter().rev().cloned().collect::>() ); - // now we remove the stake 5 to get back to the initial state. + // now we remove the staker 5 to get back to the initial state. remove_staker(5); + assert_eq!(score_of_target(10), 300); assert_eq!(score_of_target(11), 200); assert!(score_of_target(10) > score_of_target(11)); assert_eq!(TargetBagsList::iter().collect::>(), initial_sort); @@ -192,17 +199,19 @@ fn on_stake_update_sorting_works() { let voter_scores_before = get_scores::(); assert_eq!(voter_scores_before, [(10, 100), (11, 100), (1, 100), (2, 100)]); - // nothing changes. - >::on_stake_update(&11, stake_of(11)); + // noop, nothing changes. + let initial_stake = stake_of(11); + >::on_stake_update(&11, initial_stake); assert_eq!(voter_scores_before, get_scores::()); + // now let's change the self-vote of 11 and call `on_stake_update` again. let nominations = ::nominations(&11).unwrap(); let new_stake = Stake { total: 1, active: 1 }; TestNominators::mutate(|n| { n.insert(11, (new_stake, nominations.clone())); }); - >::on_stake_update(&11, stake_of(11)); + >::on_stake_update(&11, initial_stake); // although the voter score of 11 is 1, the voter list sorting has not been updated // automatically. From 25c97e13ce4fa0bfe8f82ae3d123bd2439bcc8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 24 Nov 2023 15:38:31 +0100 Subject: [PATCH 031/133] Removes duplicate assert --- substrate/frame/staking/src/pallet/impls.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 3121f9f1c6c5..35368c24b476 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1027,11 +1027,6 @@ impl Pallet { T::VoterList::count() ); - debug_assert_eq!( - Nominators::::count() + Validators::::count(), - T::VoterList::count() - ); - outcome } From f9c439ca46c8700c0c657652088f071ec5575bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 2 Dec 2023 21:01:12 +0100 Subject: [PATCH 032/133] Refactors staking and `stake-tracker` so that target and voter lists include idle stakers (#2497) In this PR we change the current assumptions so that `TargetList` and `VoterList` **also** keep track of the idle stakers (w.g. chilled) and the target scores are tracked and updated even while the validator is chilled. The idle stakers will be removed when the ledger unbonds. This allows the stake-tracker to keep track of the chilled validators and respective score so that a re-validate of a chilled validator is brought up with the correct target score (i.e. self stake + all current nominations in the system). --------- Co-authored-by: command-bot <> --- substrate/frame/staking/src/mock.rs | 9 +- substrate/frame/staking/src/pallet/impls.rs | 178 +++++++++++++----- substrate/frame/staking/src/pallet/mod.rs | 5 +- substrate/frame/staking/src/tests.rs | 96 ++++++++-- .../frame/staking/stake-tracker/src/lib.rs | 78 +++++--- .../frame/staking/stake-tracker/src/tests.rs | 36 +++- substrate/primitives/staking/src/lib.rs | 10 + 7 files changed, 311 insertions(+), 101 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 50baa12afca5..9c7839da10ef 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -602,7 +602,7 @@ impl ExtBuilder { let mut ext = self.build(); ext.execute_with(test); ext.execute_with(|| { - Staking::do_try_state(System::block_number()) + let _ = Staking::do_try_state(System::block_number()) .map_err(|err| println!(" 🕵️‍♂️ try_state failure: {:?}", err)) .unwrap(); }); @@ -881,7 +881,12 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { use sp_staking::StakingInterface; - assert_eq!(Nominators::::count() + Validators::::count(), VoterBagsList::count()); + assert_eq!( + Nominators::::count() + Validators::::count(), + VoterBagsList::iter() + .filter(|v| Staking::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32, + ); // recalculate the target's stake based on voter's nominations and compare with the score in the // target list. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 35368c24b476..9be8acfc1520 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -318,9 +318,10 @@ impl Pallet { /// Chill a stash account. pub(crate) fn chill_stash(stash: &T::AccountId) { - let chilled_as_validator = Self::do_remove_validator(stash); - let chilled_as_nominator = Self::do_remove_nominator(stash); + let chilled_as_validator = Self::do_chill_validator(stash); + let chilled_as_nominator = Self::do_chill_nominator(stash); if chilled_as_validator || chilled_as_nominator { + debug_assert_eq!(Self::status(stash), Ok(StakerStatus::Idle)); Self::deposit_event(Event::::Chilled { stash: stash.clone() }); } } @@ -832,7 +833,9 @@ impl Pallet { let mut nominators_taken = 0u32; let mut min_active_stake = u64::MAX; - let mut sorted_voters = T::VoterList::iter(); + // voter list also contains chilled/idle voters, filter those. + let mut sorted_voters = + T::VoterList::iter().filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)); while all_voters.len() < final_predicted_len as usize && voters_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -940,7 +943,9 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - let mut targets_iter = T::TargetList::iter(); + // target list also contains chilled/idle validators, filter those. + let mut targets_iter = + T::TargetList::iter().filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)); while all_targets.len() < final_predicted_len as usize && targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -980,28 +985,52 @@ impl Pallet { /// to `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { - if !Nominators::::contains_key(who) { - // new nominator. - Nominators::::insert(who, nominations); - >>::on_nominator_add( - who, - ); - } else { - // update nominations. - let prev_nominations = Self::nominations(who).unwrap_or_default(); - Nominators::::insert(who, nominations); - >>::on_nominator_update( - who, - prev_nominations, - ); - } + match (Nominators::::contains_key(who), T::VoterList::contains(who)) { + (false, false) => { + // new nomination + Nominators::::insert(who, nominations); + >>::on_nominator_add( + who, + ); + }, + (true, true) | (false, true) => { + // update nominations or un-chill nominator. + let prev_nominations = Self::nominations(who).unwrap_or_default(); + Nominators::::insert(who, nominations); + >>::on_nominator_update( + who, + prev_nominations, + ); + }, + (true, false) => { + defensive!("unexpected state."); + }, + }; debug_assert_eq!( Nominators::::count() + Validators::::count(), - T::VoterList::count() + T::VoterList::iter() + .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32, ); } + pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { + let outcome = if Nominators::::contains_key(who) { + >>::on_nominator_idle( + who, + Self::nominations(who).unwrap_or_default(), + ); + + Nominators::::remove(who); + true + } else { + false + }; + + outcome + } + /// This function will remove a nominator from the `Nominators` storage map, /// and `VoterList`. /// @@ -1011,20 +1040,44 @@ impl Pallet { /// `Nominators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { - let outcome = if Nominators::::contains_key(who) { - >>::on_nominator_remove( - who, - Self::nominations(who).unwrap_or_default(), - ); - Nominators::::remove(who); - true - } else { - false + let nominations = Self::nominations(who).unwrap_or_default(); + + let outcome = match (Nominators::::contains_key(who), T::VoterList::contains(who)) { + // ensure that the voter is idle before removing it. + (true, true) => { + // first chill nominator. + Self::do_chill_nominator(who); + + >>::on_nominator_remove( + who, + nominations, + ); + Nominators::::remove(who); + true + }, + // nominator is idle already, remove it. + (false, true) => { + >>::on_nominator_remove( + who, + nominations, + ); + true + }, + (true, false) => { + defensive!( + "inconsistent state: staker is in nominators list but not in voter list" + ); + false + }, + // nominator has been already removed. + (false, false) => false, }; debug_assert_eq!( Nominators::::count() + Validators::::count(), - T::VoterList::count() + T::VoterList::iter() + .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32, ); outcome @@ -1049,10 +1102,21 @@ impl Pallet { debug_assert_eq!( Nominators::::count() + Validators::::count(), - T::VoterList::count() + T::VoterList::iter() + .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32, ); } + pub(crate) fn do_chill_validator(who: &T::AccountId) -> bool { + if Validators::::contains_key(who) { + Validators::::remove(who); + true + } else { + false + } + } + /// This function will remove a validator from the `Validators` storage map. /// /// Returns true if `who` was removed from `Validators`, otherwise false. @@ -1061,19 +1125,39 @@ impl Pallet { /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { - let outcome = if Validators::::contains_key(who) { - Validators::::remove(who); - >>::on_validator_remove( - who, - ); - true - } else { - false + let outcome = match (Validators::::contains_key(who), T::TargetList::contains(who)) { + // ensure the validator is idle before removing it. + (true, true) => { + Self::do_chill_validator(who); + + >>::on_validator_remove( + who, + ); + Validators::::remove(who); + true + }, + // validator is idle, remove it. + (false, true) => { + >>::on_validator_remove( + who, + ); + true + }, + (true, false) => { + defensive!( + "inconsistent state: staker is in validators list but not in targets list" + ); + false + }, + // validator has been already removed. + (false, false) => false, }; debug_assert_eq!( Nominators::::count() + Validators::::count(), - T::VoterList::count() + T::VoterList::iter() + .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32, ); outcome @@ -1824,8 +1908,9 @@ impl StakingInterface for Pallet { impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { ensure!( - T::VoterList::iter() - .all(|x| >::contains_key(&x) || >::contains_key(&x)), + T::VoterList::iter().all(|x| >::contains_key(&x) || + >::contains_key(&x) || + Self::status(&x) == Ok(StakerStatus::Idle)), "VoterList contains non-staker" ); @@ -1837,12 +1922,15 @@ impl Pallet { fn check_count() -> Result<(), TryRuntimeError> { ensure!( - ::VoterList::count() == - Nominators::::count() + Validators::::count(), + ::VoterList::iter() + .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .count() as u32 == Nominators::::count() + Validators::::count(), "wrong external count (VoterList.count != Nominators.count + Validators.count)" ); ensure!( - ::TargetList::count() == Validators::::count(), + ::TargetList::iter() + .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) + .count() as u32 == Validators::::count(), "wrong external count (TargetList.count != Validators.count)" ); ensure!( diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index c17e9eb124a7..56bc6b82b9f4 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1151,7 +1151,7 @@ pub mod pallet { } } - Self::do_remove_nominator(stash); + Self::do_chill_nominator(stash); Self::do_add_validator(stash, prefs.clone()); Self::deposit_event(Event::::ValidatorPrefsSet { stash: ledger.stash, prefs }); @@ -1225,7 +1225,7 @@ pub mod pallet { suppressed: false, }; - Self::do_remove_validator(stash); + Self::do_chill_validator(stash); Self::do_add_nominator(stash, nominations); Ok(()) @@ -1646,6 +1646,7 @@ pub mod pallet { if let Some(ref mut nom) = maybe_nom { if let Some(pos) = nom.targets.iter().position(|v| v == stash) { nom.targets.swap_remove(pos); + // update nominations and trickle down to target list score. Self::do_add_nominator(&nom_stash, nom.clone()); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3093d6c499df..f6cc84b931bd 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -520,6 +520,7 @@ fn blocking_and_kicking_works() { RuntimeOrigin::signed(11), ValidatorPrefs { blocked: true, ..Default::default() } )); + // attempt to nominate from 100/101... assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); // should have worked since we're already nominated them @@ -5030,6 +5031,7 @@ fn on_finalize_weight_is_nonzero() { mod sorted_list_provider_integration { use super::*; use frame_election_provider_support::ScoreProvider; + use sp_staking::StakingInterface; #[test] fn nominator_bond_unbond_chill_works() { @@ -5069,11 +5071,32 @@ mod sorted_list_provider_integration { assert_eq!(TargetBagsList::score(&11), 1520); assert_eq!(TargetBagsList::score(&21), 1520); - // finally, stash 42 chills and unbond completely. + // stash 42 chills, but remains bonded. Thus it is in idle state. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); - assert_eq!(VoterBagsList::contains(&42), false); + assert_eq!(VoterBagsList::contains(&42), true); + assert!(>::get(&42).is_some()); + assert_ok!(>::get(StakingAccount::Stash(42))); + assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); + + // scores of previously nominated validators were updated. assert_eq!(TargetBagsList::score(&11), 1500); assert_eq!(TargetBagsList::score(&21), 1500); + + // stash 42 unbonds completely by requesting all unbonding rewards and thus its ledger + // is killed. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(42), 20)); + // active bonded is 0, ledger will be killed when all the unlocking funds are withdrawn. + assert_eq!(>::get(StakingAccount::Stash(42)).unwrap().active, 0); + + // roll to block where stash can successfully withdraw unbonding chunks. + start_active_era(current_era() + BondingDuration::get()); + + // after withdrawing, the ledger is killed. + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(42), 0)); + assert!(>::get(&42).is_none()); + assert!(>::get(StakingAccount::Stash(42)).is_err()); + assert!(Staking::status(&42).is_err()); + assert_eq!(VoterBagsList::contains(&42), false); }) } @@ -5103,10 +5126,18 @@ mod sorted_list_provider_integration { assert_eq!(VoterBagsList::score(&42), 20); assert_eq!(TargetBagsList::score(&42), 20); - // finally, stash 42 chills and unbond completely. + // stash 42 chills, thus it should be part of the voter and target bags list but with + // `Idle` status. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); + assert_eq!(VoterBagsList::contains(&42), true); + assert_eq!(TargetBagsList::contains(&42), true); + assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); + + // finally, remove the validator (similar to withdraw all and subsequent ledger kill). + assert_ok!(Staking::kill_stash(&42, 0)); assert_eq!(VoterBagsList::contains(&42), false); assert_eq!(TargetBagsList::contains(&42), false); + assert!(Staking::status(&42).is_err()); }) } } @@ -7272,7 +7303,6 @@ mod stake_tracker { // * Call::validate() // * Call::nominate() // * Call::chill() - // * Call::kick() ExtBuilder::default().build_and_execute(|| { // bond extra to rebag nominated validator. assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(101), 600)); @@ -7320,25 +7350,33 @@ mod stake_tracker { // let's chill a validator now. assert_ok!(Staking::chill(RuntimeOrigin::signed(11))); - // the chilled validator score is updated to 0 and 11 is not part of the targets list - // anymore. + // the chilled validator score remains the same, 11 is still part of the targets list + // but its staker status is Idle and it was removed from the nominator sand validators + // list. assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); - assert_eq!(>::score(&11), 0); - assert_eq!(voters_and_targets().1, [(21, 1000), (31, 500)]); + assert_eq!(>::score(&11), 1000); + assert_eq!(voters_and_targets().1, [(11, 1000), (21, 1000), (31, 500)]); + assert!(!Nominators::::contains_key(&11)); + assert!(!Validators::::contains_key(&11)); - // now, let's have 101 re-nominate 21 and kick him. Note that 101 also nominates 11 but - // that's a noop since 11 is Idle at the moment. + // now, let's have 101 re-nominate 21. Note that 101 also nominates 11: even + // though 11 is chilled at the moment. assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![21, 11])); - assert_eq!(voters_and_targets().1, [(21, 2100), (31, 500)]); + assert_eq!(voters_and_targets().1, [(21, 2100), (11, 2100), (31, 500)]); - // score of 21 and rebag hapened due to nomination. + // score update and rebag hapened to 21 and 11 (idle) due to nomination of 101. assert_eq!( target_bags_events(), [ BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 2100 } + BagsEvent::ScoreUpdated { who: 21, new_score: 2100 }, + BagsEvent::Rebagged { who: 11, from: 1000, to: 10000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 2100 }, ] ); + + assert_eq!(Staking::status(&21).unwrap(), StakerStatus::Validator); + assert_eq!(Staking::status(&11).unwrap(), StakerStatus::Idle); }) } @@ -7492,15 +7530,19 @@ mod stake_tracker { // we immediately slash 11 with a 50% slash. let exposure = Staking::eras_stakers(active_era(), &11); let slash_percent = Perbill::from_percent(50); + let total_stake_to_slash = slash_percent * exposure.total; on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[slash_percent], ); - // 11 has been chilled and not part of the targets list anymore (using - // `DisablementStrategy::WhenSlashed`). - assert!(!>::contains(&11)); - assert_eq!(>::score(&11), 0); + // 11 has been chilled but it is still part of the targets list and it is in `Idle` + // state. + assert!(>::contains(&11)); + assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); + // and its balance has been updated based on the slash applied. + let score_11_after = >::score(&11); + assert_eq!(score_11_after, score_11_before - total_stake_to_slash); // self-stake of 11 has decreased by 50% due to slash. assert_eq!( @@ -7525,15 +7567,31 @@ mod stake_tracker { ); // the target list has been updated accordingly and an indirect rebag of 21 happened. - assert_eq!(voters_and_targets().1, [(21, score_21_after), (31, 500)]); + // 11, althoug chilled, is still part of the target list. + assert_eq!( + voters_and_targets().1, + [(11, score_11_after), (21, score_21_after), (31, 500)] + ); assert_eq!( target_bags_events(), [ + BagsEvent::Rebagged { who: 11, from: 10000, to: 2000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1550 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1465 }, BagsEvent::Rebagged { who: 21, from: 10000, to: 2000 }, BagsEvent::ScoreUpdated { who: 21, new_score: 1965 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 1872 } + BagsEvent::ScoreUpdated { who: 21, new_score: 1872 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1372 }, ] ); + + // fetching targets sorted and filtered by status works. + assert_eq!( + TargetBagsList::iter() + .filter(|t| Staking::status(&t).unwrap() != StakerStatus::Idle) + .collect::>(), + [21, 31], + ); }) } } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 0992e6c5f505..5159e4f963d0 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -135,7 +135,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + fn try_state(_n: BlockNumberFor) -> Result<(), TryRuntimeError> { Self::do_try_state() } } @@ -352,11 +352,7 @@ impl OnStakingUpdate> for Pallet { // updates vote weight of nominated targets accordingly. Note: this will update // the score of up to `T::MaxNominations` validators. for target in nominations.into_iter() { - // target may be chilling due to a recent slash, verify if it is active - // before updating the score. - if ::is_validator(&target) { - Self::update_score::(&target, stake_imbalance); - } + Self::update_score::(&target, stake_imbalance); } }, StakerStatus::Validator => { @@ -380,9 +376,13 @@ impl OnStakingUpdate> for Pallet { fn on_nominator_add(who: &T::AccountId) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); - let _ = T::VoterList::on_insert(who.clone(), nominator_vote).defensive_proof( - "staker should not exist in VoterList, as per the contract with staking.", - ); + // voter may exist in the list in case of re-enabling a chilled nominator; + if T::VoterList::contains(who) { + return + } + + let _ = T::VoterList::on_insert(who.clone(), nominator_vote) + .defensive_proof("staker does not exist in the list as per check above; qed."); // If who is a nominator, update the vote weight of the nominations if they exist. Note: // this will update the score of up to `T::MaxNominations` validators. @@ -407,9 +407,11 @@ impl OnStakingUpdate> for Pallet { // // Note: it is assumed that who's staking state is updated *before* calling this method. fn on_validator_add(who: &T::AccountId) { - let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)).defensive_proof( - "staker should not exist in TargetList, as per the contract with staking.", - ); + // target may exist in the list in case of re-enabling a chilled validator; + if !T::TargetList::contains(who) { + let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)) + .expect("staker does not exist in the list as per check above; qed."); + } log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); @@ -417,17 +419,17 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_add(who) } - // Fired when someone removes their intention to nominate, either due to chill or validating. - // - // Note: it is assumed that who's staking state is updated *before* the caller calling into - // this method. Thus, the nominations before the nominator has been removed from staking are - // passed in, so that the target list can be updated accordingly. - fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { + /// Fired when some nominator becomes idle and stops nominating without being removed from the + /// staking state. + /// + /// Note: it is assumed that `who`'s staking ledger and `nominations` are up to date before + /// calling this method. + fn on_nominator_idle(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); log!( debug, - "on_nominator_remove: {:?} with {:?}. impacting {:?}", + "remove nominations from {:?} with {:?} weight. impacting {:?}.", who, nominator_vote, nominations, @@ -438,13 +440,27 @@ impl OnStakingUpdate> for Pallet { for t in nominations.iter() { Self::update_score::(&t, StakeImbalance::Negative(nominator_vote.into())) } + } + + // Fired when someone removes their intention to nominate and is completely removed from the + // staking state. + fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { + log!(debug, "on_nominator_remove: {:?}, impacting {:?}", who, nominations); + + if T::Staking::status(who).is_ok() { + //debug_assert!(!T::VoterList::contains(who)); + + // nominator must be idle before removing completely. + Self::on_nominator_idle(who, nominations); + } let _ = T::VoterList::on_remove(&who).defensive_proof( "the nominator exists in the list as per the contract with staking; qed.", ); } - // Fired when someone removes their intention to validate, either due to chill or nominating. + // Fired when someone removes their intention to validate and is completely removed from the + // staking state. fn on_validator_remove(who: &T::AccountId) { log!(debug, "on_validator_remove: {:?}", who,); @@ -495,15 +511,25 @@ impl OnStakingUpdate> for Pallet { } } - // noop: the updates to target and voter lists when applying a slash are performed - // through [`Self::on_nominator_remove`] and [`Self::on_validator_remove`] when the stakers are - // chilled. When the slash is applied, the ledger is updated of the affected stashes is, thus - // the stake is propagated through the [`Self::update::`]. + /// Fired when a slash happens. + /// + /// In practice, this only updates the score of the slashed validators, since the score of the + /// nominators and corresponding scores are updated through the `ledger.update` calls following + /// the slash. fn on_slash( - _stash: &T::AccountId, + stash: &T::AccountId, _slashed_active: BalanceOf, _slashed_unlocking: &BTreeMap>, - _slashed_total: BalanceOf, + slashed_total: BalanceOf, ) { + let stake_imbalance = StakeImbalance::Negative(Self::to_vote_extended(slashed_total)); + + match T::Staking::status(stash).defensive_proof("called on_slash on a unbonded stash") { + Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) => + Self::update_score::(stash, stake_imbalance), + // score of target impacted by nominators will be updated through ledger.update. + Ok(StakerStatus::Nominator(_)) => (), + Err(_) => (), // nothing to see here. + } } } diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 8246af32e9bc..f427e7f3ad9a 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -19,7 +19,7 @@ use crate::{mock::*, StakeImbalance}; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_support::assert_ok; use sp_staking::{OnStakingUpdate, Stake, StakingInterface}; @@ -292,22 +292,44 @@ fn on_validator_add_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: Duplicate: \"staker should not exist in VoterList, as per the contract with staking.\""] -fn on_nominator_add_already_exists_defensive_works() { +fn on_nominator_add_already_exists_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - // voter already exists in the list, trying to emit `on_add_nominator` again will fail. assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::count(), 4); + assert_eq!(>::score(&1), 100); + + let voter_list_before = VoterBagsList::iter().collect::>(); + let target_list_before = TargetBagsList::iter().collect::>(); + + // noop. >::on_nominator_add(&1); + assert!(VoterBagsList::contains(&1)); + assert_eq!(VoterBagsList::count(), 4); + assert_eq!(>::score(&1), 100); + + assert_eq!(VoterBagsList::iter().collect::>(), voter_list_before); + assert_eq!(TargetBagsList::iter().collect::>(), target_list_before); }); } #[test] -#[should_panic = "Defensive failure has been triggered!: Duplicate: \"staker should not exist in TargetList, as per the contract with staking.\""] -fn on_validator_add_already_exists_defensive_works() { +fn on_validator_add_already_exists_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - // validator already exists in the list, trying to emit `on_add_validator` again will fail. assert!(TargetBagsList::contains(&10)); + assert_eq!(TargetBagsList::count(), 2); + assert_eq!(>::score(&10), 300); + + let voter_list_before = VoterBagsList::iter().collect::>(); + let target_list_before = TargetBagsList::iter().collect::>(); + + // noop >::on_validator_add(&10); + assert!(TargetBagsList::contains(&10)); + assert_eq!(TargetBagsList::count(), 2); + assert_eq!(>::score(&10), 300); + + assert_eq!(VoterBagsList::iter().collect::>(), voter_list_before); + assert_eq!(TargetBagsList::iter().collect::>(), target_list_before); }); } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index c2ac5ae004b1..40ac62d674de 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -114,6 +114,11 @@ pub trait OnStakingUpdate { /// nominator. fn on_nominator_update(_who: &AccountId, _prev_nominations: Vec) {} + /// Fired when an existng nominator becomes idle. + /// + /// An idle nominator stops nominating but its stake state should not be removed. + fn on_nominator_idle(_who: &AccountId, _prev_nominations: Vec) {} + /// Fired when someone removes their intention to nominate, either due to chill or validating. /// /// The set of nominations at the time of removal is provided as it can no longer be fetched in @@ -130,6 +135,11 @@ pub trait OnStakingUpdate { /// Note validator preference changes are not communicated, but could be added if needed. fn on_validator_update(_who: &AccountId) {} + /// Fired when an existing validator becomes idle. + /// + /// An idle validator stops validating but its stake state should not be removed. + fn on_validator_idle(_who: &AccountId) {} + /// Fired when someone removes their intention to validate, either due to chill or nominating. fn on_validator_remove(_who: &AccountId) {} From b09f8bc174aeeb7b92061bd081d57ebf0e29a311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 5 Dec 2023 12:10:57 +0100 Subject: [PATCH 033/133] Addresses review comments --- substrate/frame/staking/src/ledger.rs | 27 +++++++----- substrate/frame/staking/src/pallet/impls.rs | 47 +++++---------------- substrate/frame/staking/src/tests.rs | 40 +++++++++++++++++- 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 19e776c8bd53..5068487be220 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -33,7 +33,8 @@ use frame_support::{ defensive, - traits::{Defensive, LockableCurrency, WithdrawReasons}, + ensure, + traits::{LockableCurrency, WithdrawReasons}, }; use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingAccount, StakingInterface}; use sp_std::prelude::*; @@ -184,7 +185,11 @@ impl StakingLedger { T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); Ledger::::insert(controller, &self); - T::EventListeners::on_stake_update(&self.stash, prev_stake); + // fire `on_stake_update` if there was a stake update. + let new_stake: Stake<_> = self.clone().into(); + if new_stake != prev_stake.unwrap_or_default() { + T::EventListeners::on_stake_update(&self.stash, prev_stake); + } Ok(()) } @@ -214,18 +219,18 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. + /// + /// Note: we assume that [`T::EventListeners::on_nominator_remove`] and/or + /// [`T::EventListeners::on_validator_remove`] have been called and the stash is idle, prior to + /// call this method. This can be achieved by calling `[crate::Pallet::::kill_stash]` prior + /// to this call. pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; - // Note: by now, we expect that the caller has already called `on_nominator_remove` and/or - // `on_validator_remove` and the stash is idle. This can be achieved by calling - // `[crate::Pallet::::kill_stash]` prior to this call. - if crate::Pallet::::status(stash).defensive_unwrap_or(StakerStatus::Idle) != - StakerStatus::Idle - { - defensive!("tried to kill a ledger before calling `kill_stash()`. this may lead to inconsistent states."); - return Err(Error::::BadState) - } + ensure!( + crate::Pallet::::status(stash) == Ok(StakerStatus::Idle), + Error::::BadState + ); >::get(&controller).ok_or(Error::::NotController).map(|ledger| { T::Currency::remove_lock(STAKING_ID, &ledger.stash); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9be8acfc1520..ea46abc916da 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -347,13 +347,9 @@ impl Pallet { ledger.active += amount; ledger.total += amount; let r = T::Currency::deposit_into_existing(stash, amount).ok(); - - let _ = match ::status(stash) - .expect("stash is a staker; qed.") - { - StakerStatus::Nominator(_) | StakerStatus::Validator => ledger.update(), - StakerStatus::Idle => Ok(()), - }; + let _ = ledger + .update() + .defensive_proof("ledger fetched from storage, so it exists; qed."); Ok(r) }) @@ -989,18 +985,13 @@ impl Pallet { (false, false) => { // new nomination Nominators::::insert(who, nominations); - >>::on_nominator_add( - who, - ); + T::EventListeners::on_nominator_add(who); }, (true, true) | (false, true) => { // update nominations or un-chill nominator. let prev_nominations = Self::nominations(who).unwrap_or_default(); Nominators::::insert(who, nominations); - >>::on_nominator_update( - who, - prev_nominations, - ); + T::EventListeners::on_nominator_update(who, prev_nominations); }, (true, false) => { defensive!("unexpected state."); @@ -1017,11 +1008,7 @@ impl Pallet { pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { let outcome = if Nominators::::contains_key(who) { - >>::on_nominator_idle( - who, - Self::nominations(who).unwrap_or_default(), - ); - + T::EventListeners::on_nominator_idle(who, Self::nominations(who).unwrap_or_default()); Nominators::::remove(who); true } else { @@ -1048,19 +1035,13 @@ impl Pallet { // first chill nominator. Self::do_chill_nominator(who); - >>::on_nominator_remove( - who, - nominations, - ); + T::EventListeners::on_nominator_remove(who, nominations); Nominators::::remove(who); true }, // nominator is idle already, remove it. (false, true) => { - >>::on_nominator_remove( - who, - nominations, - ); + T::EventListeners::on_nominator_remove(who, nominations); true }, (true, false) => { @@ -1093,9 +1074,7 @@ impl Pallet { pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { Validators::::insert(who, prefs); - >>::on_validator_add( - who, - ); + T::EventListeners::on_validator_add(who); } else { Validators::::insert(who, prefs); } @@ -1130,17 +1109,13 @@ impl Pallet { (true, true) => { Self::do_chill_validator(who); - >>::on_validator_remove( - who, - ); + T::EventListeners::on_validator_remove(who); Validators::::remove(who); true }, // validator is idle, remove it. (false, true) => { - >>::on_validator_remove( - who, - ); + T::EventListeners::on_validator_remove(who); true }, (true, false) => { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f6cc84b931bd..0086f81ae385 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -141,7 +141,6 @@ fn kill_stash_works() { } #[test] -#[should_panic] fn kill_ledger_preconditions_works() { ExtBuilder::default().build_and_execute(|| { // Account 11 (also controller) is stashed and locked @@ -7473,7 +7472,6 @@ mod stake_tracker { assert_eq!( target_bags_events(), [ - BagsEvent::ScoreUpdated { who: 11, new_score: 1500 }, BagsEvent::Rebagged { who: 11, from: 2000, to: 10000 }, BagsEvent::ScoreUpdated { who: 11, new_score: 9555 }, BagsEvent::Rebagged { who: 11, from: 10000, to: u128::MAX }, @@ -7594,4 +7592,42 @@ mod stake_tracker { ); }) } + + #[test] + fn no_redundant_update_ledger_events() { + ExtBuilder::default().build_and_execute(|| { + // 101 nominates 11 and 21. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + + let ledger = Staking::ledger(StakingAccount::Stash(101)).unwrap(); + + // calling update on a ledger with no stake changes will not affect the target's score. + assert_ok!(ledger.update()); + + assert_eq!( + target_bags_events(), + [], + ); + + let score_11_before = TargetBagsList::score(&11); + let score_21_before = TargetBagsList::score(&21); + + let extra = 100; + + // however, updating the stake of the nominator will affect the score of its nominated + // targets, as expected. + let mut ledger = Staking::ledger(StakingAccount::Stash(101)).unwrap(); + ledger.active += extra; + ledger.total += extra; + assert_ok!(ledger.update()); + + assert_eq!( + target_bags_events(), + [ + BagsEvent::ScoreUpdated { who: 11, new_score: score_11_before + extra }, + BagsEvent::ScoreUpdated { who: 21, new_score: score_21_before + extra }, + ], + ); + }) + } } From 062868d3db55dd621c922d2134db8bb7ecf60b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 5 Dec 2023 14:27:39 +0100 Subject: [PATCH 034/133] review comments --- substrate/frame/staking/stake-tracker/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 5159e4f963d0..b6dbadad2121 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -447,10 +447,8 @@ impl OnStakingUpdate> for Pallet { fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { log!(debug, "on_nominator_remove: {:?}, impacting {:?}", who, nominations); - if T::Staking::status(who).is_ok() { - //debug_assert!(!T::VoterList::contains(who)); - - // nominator must be idle before removing completely. + // nominator must be idle before removing completely. + if T::Staking::status(who).unwrap_or(StakerStatus::Idle) != StakerStatus::Idle { Self::on_nominator_idle(who, nominations); } From 70ab8c3c881b2b729186c11d87b8f7a8a99c3355 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 5 Dec 2023 13:44:40 +0000 Subject: [PATCH 035/133] ".git/.scripts/commands/fmt/fmt.sh" --- Cargo.toml | 2 +- polkadot/runtime/westend/Cargo.toml | 6 +++--- substrate/frame/staking/src/ledger.rs | 18 +++++++----------- substrate/frame/staking/src/tests.rs | 9 +++------ .../frame/staking/stake-tracker/Cargo.toml | 4 ++-- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cbbacc0e7384..c72324156ac9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -353,10 +353,10 @@ members = [ "substrate/frame/session/benchmarking", "substrate/frame/society", "substrate/frame/staking", - "substrate/frame/staking/stake-tracker", "substrate/frame/staking/reward-curve", "substrate/frame/staking/reward-fn", "substrate/frame/staking/runtime-api", + "substrate/frame/staking/stake-tracker", "substrate/frame/state-trie-migration", "substrate/frame/statement", "substrate/frame/sudo", diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 63c3b08db440..418db22cf92e 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -184,9 +184,9 @@ std = [ "pallet-session-benchmarking?/std", "pallet-session/std", "pallet-society/std", + "pallet-stake-tracker/std", "pallet-staking-runtime-api/std", "pallet-staking/std", - "pallet-stake-tracker/std", "pallet-state-trie-migration/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -265,8 +265,8 @@ runtime-benchmarks = [ "pallet-scheduler/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", "pallet-stake-tracker/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -324,8 +324,8 @@ try-runtime = [ "pallet-scheduler/try-runtime", "pallet-session/try-runtime", "pallet-society/try-runtime", - "pallet-staking/try-runtime", "pallet-stake-tracker/try-runtime", + "pallet-staking/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 5068487be220..a42fb94e97cf 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -32,8 +32,7 @@ //! state consistency. use frame_support::{ - defensive, - ensure, + defensive, ensure, traits::{LockableCurrency, WithdrawReasons}, }; use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingAccount, StakingInterface}; @@ -185,11 +184,11 @@ impl StakingLedger { T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); Ledger::::insert(controller, &self); - // fire `on_stake_update` if there was a stake update. - let new_stake: Stake<_> = self.clone().into(); - if new_stake != prev_stake.unwrap_or_default() { - T::EventListeners::on_stake_update(&self.stash, prev_stake); - } + // fire `on_stake_update` if there was a stake update. + let new_stake: Stake<_> = self.clone().into(); + if new_stake != prev_stake.unwrap_or_default() { + T::EventListeners::on_stake_update(&self.stash, prev_stake); + } Ok(()) } @@ -227,10 +226,7 @@ impl StakingLedger { pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; - ensure!( - crate::Pallet::::status(stash) == Ok(StakerStatus::Idle), - Error::::BadState - ); + ensure!(crate::Pallet::::status(stash) == Ok(StakerStatus::Idle), Error::::BadState); >::get(&controller).ok_or(Error::::NotController).map(|ledger| { T::Currency::remove_lock(STAKING_ID, &ledger.stash); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3e1616ca6f00..3a9792e8e1ea 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7588,13 +7588,10 @@ mod stake_tracker { // calling update on a ledger with no stake changes will not affect the target's score. assert_ok!(ledger.update()); - assert_eq!( - target_bags_events(), - [], - ); + assert_eq!(target_bags_events(), [],); - let score_11_before = TargetBagsList::score(&11); - let score_21_before = TargetBagsList::score(&21); + let score_11_before = TargetBagsList::score(&11); + let score_21_before = TargetBagsList::score(&21); let extra = 100; diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 4a7a92a445c9..a47ce200b9a6 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/paritytech/polkadot-sdk" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] } +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } sp-runtime = { version = "24.0.0", default-features = false, path = "../../../primitives/runtime", features = ["serde"] } @@ -22,7 +22,7 @@ sp-std = { version = "8.0.0", default-features = false, path = "../../../primiti sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" } frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support"} +frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } log = { version = "0.4.17", default-features = false } From ee52b6f1d61070587194d2755a7f89e4cfa629ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 5 Dec 2023 16:56:35 +0100 Subject: [PATCH 036/133] Update documentation --- substrate/frame/staking/src/pallet/impls.rs | 31 ++++--- substrate/frame/staking/src/pallet/mod.rs | 43 +++++---- .../frame/staking/stake-tracker/README.md | 9 -- .../frame/staking/stake-tracker/src/lib.rs | 88 +++++++++++-------- 4 files changed, 100 insertions(+), 71 deletions(-) delete mode 100644 substrate/frame/staking/stake-tracker/README.md diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 23c3f5715d2f..b1c9c1550916 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -318,11 +318,20 @@ impl Pallet { } /// Chill a stash account. + /// + /// Chilling consists of removing the nominator/validator's stash from the corresponding + /// `Nominators` or `Validators` storage map. + /// + /// Note: chilling a staker does not remove its footprint from the voter list or target list. + /// + /// Invariant: upon chilling the status of the stash must be `StakerStatus::Idle`. pub(crate) fn chill_stash(stash: &T::AccountId) { let chilled_as_validator = Self::do_chill_validator(stash); let chilled_as_nominator = Self::do_chill_nominator(stash); if chilled_as_validator || chilled_as_nominator { + debug_assert!(T::VoterList::contains(stash) || T::TargetList::contains(stash)); debug_assert_eq!(Self::status(stash), Ok(StakerStatus::Idle)); + Self::deposit_event(Event::::Chilled { stash: stash.clone() }); } } @@ -986,9 +995,8 @@ impl Pallet { /// /// If the nominator already exists, their nominations will be updated. /// - /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any access - /// to `Nominators` or `VoterList` outside of this function is almost certainly - /// wrong. + /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any + /// access to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { match (Nominators::::contains_key(who), T::VoterList::contains(who)) { (false, false) => { @@ -1015,6 +1023,10 @@ impl Pallet { ); } + /// Tries to chill a nominator. + /// + /// A chilled nominator is removed from the `Nominators` map, and the nominator's new state must + /// be signalled to [`T::EventListeners`]. pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { let outcome = if Nominators::::contains_key(who) { T::EventListeners::on_nominator_idle(who, Self::nominations(who).unwrap_or_default()); @@ -1032,9 +1044,8 @@ impl Pallet { /// /// Returns true if `who` was removed from `Nominators`, otherwise false. /// - /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access to - /// `Nominators` or `VoterList` outside of this function is almost certainly - /// wrong. + /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access + /// to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { let nominations = Self::nominations(who).unwrap_or_default(); @@ -1043,9 +1054,7 @@ impl Pallet { (true, true) => { // first chill nominator. Self::do_chill_nominator(who); - T::EventListeners::on_nominator_remove(who, nominations); - Nominators::::remove(who); true }, // nominator is idle already, remove it. @@ -1096,6 +1105,9 @@ impl Pallet { ); } + /// Tries to chill a validator. + /// + /// A chilled validator is removed from the `Validators` map. pub(crate) fn do_chill_validator(who: &T::AccountId) -> bool { if Validators::::contains_key(who) { Validators::::remove(who); @@ -1116,10 +1128,9 @@ impl Pallet { let outcome = match (Validators::::contains_key(who), T::TargetList::contains(who)) { // ensure the validator is idle before removing it. (true, true) => { + // first chill validator. Self::do_chill_validator(who); - T::EventListeners::on_validator_remove(who); - Validators::::remove(who); true }, // validator is idle, remove it. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index a5b43af63ae9..1b5514e113c7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -222,31 +222,41 @@ pub mod pallet { /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; - /// Something that provides a best-effort sorted list of voters aka electing nominators, - /// used for NPoS election. + /// Something that provides a best-effort sorted list of voters (aka electing and chilled + /// nominators), used for NPoS election. /// /// The changes to nominators are reported to this. Moreover, each validator's self-vote is /// also reported as one independent vote. /// + /// Voters will be removed from this list when their ledger is killed. Otherwise, the voter + /// is kept in this list, even when it is chilled. + /// /// To keep the load off the chain as much as possible, changes made to the staked amount /// via rewards and slashes are not reported and thus need to be manually fixed by the /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. /// - /// Invariant: what comes out of this list will always be a nominator. + /// Invariant: what comes out of this list will always be a nominator OR a chilled + /// nominator. type VoterList: SortedListProvider; - /// Something that provides a sorted list of targets aka electable validators, used for NPoS - /// election. + /// Something that provides a sorted list of targets (aka electable and chilled + /// validators), used for NPoS election. + /// + /// The changes to the approval stake of each validator are reported to this list through + /// [`Self::EventListeners`]. The target(s) approval stake in the list should be updated in + /// any of these cases: + /// 1. The stake of a validator or nominator is updated. + /// 2. The nominations of a voter are updated. + /// 3. A nominator or validator ledger is removed from the staking system. /// - /// The changes to the approval stake of each validator are reported to this. This means any - /// change to: - /// 1. The stake of any validator or nominator. - /// 2. The targets of any nominator - /// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc) + /// Unlike `VoterList`, the values in this list are always kept up to date with both the + /// voter and target ledger's state at all the time (even upon rewards, slashes, etc) and + /// thus it represent an accurate approval stake of all target accounts in the system. /// - /// Unlike `VoterList`, the values in this list are always kept up to date with rewards, - /// slashes, etc, and thus represent the accurate approval stake of all account being - /// nominated by nominators. + /// Chilled validators will *not* be removed from this list. Even when chilled, the target's + /// approval voting must be kept up to date. In case a chilled validator re-validates their + /// intention to be a validator again, their target score is up to date with the nominations + /// in the system. type TargetList: SortedListProvider>; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can @@ -346,10 +356,9 @@ pub mod pallet { /// The map from nominator stash key to their nomination preferences, namely the validators that /// they wish to support. /// - /// Note that the keys of this storage map might become non-decodable in case the - /// account's [`NominationsQuota::MaxNominations`] configuration is decreased. - /// In this rare case, these nominators - /// are still existent in storage, their key is correct and retrievable (i.e. `contains_key` + /// Note that the keys of this storage map might become non-decodable in case the account's + /// [`NominationsQuota::MaxNominations`] configuration is decreased. In this rare case, these + /// nominators still exist in storage, their key is correct and retrievable (i.e. `contains_key` /// indicates that they exist), but their value cannot be decoded. Therefore, the non-decodable /// nominators will effectively not-exist, until they re-submit their preferences such that it /// is within the bounds of the newly set `Config::MaxNominations`. diff --git a/substrate/frame/staking/stake-tracker/README.md b/substrate/frame/staking/stake-tracker/README.md deleted file mode 100644 index a10afc9f5924..000000000000 --- a/substrate/frame/staking/stake-tracker/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Pallet `stake-tracker` - -The stake-tracker pallet listens to staking events through implementing the -[`OnStakingUpdate`] trait and forwards those events to one or multiple types (e.g. pallets) that -must be kept up to date with certain updates in staking. The pallet does not expose any -callables and acts as a multiplexer of staking events. - -Currently, the stake tracker pallet is used to update the sorted targe list and semi-sorted voter -lists implemented through bags lists. diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index b6dbadad2121..faddb143465e 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -15,19 +15,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # StakeTracker +//! # Stake Tracker Pallet //! -//! FRAME stake tracker pallet +//! The stake-tracker pallet is responsible to keep track of stake and approval voting of voters and +//! targets in the staking system. //! //! ## Overview //! -//! The stake-tracker pallet listens to staking events through implementing the -//! [`OnStakingUpdate`] trait and forwards those events to one or multiple types (e.g. pallets) that -//! must be kept track of the stake and staker's state. The pallet does not expose any -//! callables and acts as a multiplexer of staking events. -//! -//! Currently, the stake tracker pallet is used to update a voter and target sorted target list -//! implemented through the bags lists pallet. +//! The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] +//! trait and, based on those events, ensures that the score of nodes in the lists +//! [`Config::VoterList`] and [`Config::TargetList`] are kept up to date with the staker's bonds +//! and nominations in the system. In addition, the pallet also ensures that [`Config::TargetList`] +//! is *strictly sorted* based on the targets' approvals. //! //! ## Goals //! @@ -35,20 +34,32 @@ //! //! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals //! (which include self-vote and nominations). -//! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. +//! * The [`Config::VoterList`] keeps a semi-sorted list of voters, loosely sorted by bonded stake. +//! This pallet does nothing to ensure that the voter list sorting is correct. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new -//! nomination updates, nominator/validator slashes and rewards. +//! nomination updates, nominator/validator slashes and rewards. This pallet *must* ensure that the +//! scores of the targets are always up to date *and* the targets are sorted by score at all time. +//! +//! Note that from the POV of this pallet, all events will result in one or multiple updates to +//! [`Config::VoterList`] and/or [`Config::TargetList`] state. If a set of staking updates require +//! too much weight to process (e.g. at nominator's rewards payout or at nominator's slashes), the +//! event emitter should handle that in some way (e.g. buffering events). +//! +//! ## Domain-specific consideration on [`Config::VoterList`] and [`Config::TargetList`] +//! +//! In the context of Polkadot's staking system, both the voter and target lists will be implemented +//! by a bags-list pallet, which implements the `SortedListProvider` trait. //! -//! Note that from the POV of this pallet, all events will result in one or multiple -//! updates to the [`Config::VoterList`] and/or [`Config::TargetList`] state. If a update or set of -//! updates require too much weight to process (e.g. at nominator's rewards payout or at nominator's -//! slashes), the event emitter should handle that in some way (e.g. buffering events). +//! Note that the score provider of the target's bags-list is the list itself. This, coupled with +//! the fact that the target list sorting must be always up to date results in requiring this +//! pallet to ensure at all times that the score of the targets in the `TargetList` is *always* kept +//! up to date. //! //! ## Event emitter ordering and staking ledger state updates //! //! It is important to ensure that the events are emitted from staking (i.e. the calls into -//! [`OnStakingUpdate`]) *after* the caller ensures that the state of the staking ledger is up to -//! date, since the new state will be fetched and used to update the sorted lists accordingly. +//! [`OnStakingUpdate`]) *after* the staking ledger has been updated by the caller, since the new +//! state will be fetched and used to update the sorted lists accordingly. #![cfg_attr(not(feature = "std"), no_std)] @@ -126,6 +137,9 @@ pub mod pallet { type VoterList: SortedListProvider; /// Something that provides an *always* sorted list of targets. + /// + /// This pallet is responsible to keep the score and sorting of this pallet up to date with + /// the state from [`Self::StakingInterface`]. type TargetList: SortedListProvider< Self::AccountId, Score = ::Balance, @@ -299,11 +313,12 @@ pub mod pallet { } impl OnStakingUpdate> for Pallet { - // Fired when the stake amount of someone updates. - // - // When a nominator's stake is updated, all the nominated targets must be updated accordingly. - // - // Note: it is assumed that who's staking state is updated *before* this method is called. + /// Fired when the stake amount of some staker updates. + /// + /// When a nominator's stake is updated, all the nominated targets must be updated accordingly. + /// + /// Note: it is assumed that `who`'s staking ledger state is updated *before* this method is + /// called. fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { // closure to calculate the stake imbalance of a staker. let stake_imbalance_of = |prev_stake: Option>>, @@ -370,9 +385,10 @@ impl OnStakingUpdate> for Pallet { } } - // Fired when someone sets their intention to nominate. - // - // Note: it is assumed that who's staking state is updated *before* this method is called. + /// Fired when someone sets their intention to nominate. + /// + /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is + /// called. fn on_nominator_add(who: &T::AccountId) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); @@ -400,12 +416,13 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_nominator_add: {:?}. role: {:?}", who, T::Staking::status(who),); } - // Fired when someone sets their intention to validate. - // - // A validator is also considered a voter with self-vote and should be added to - // [`Config::VoterList`]. + /// Fired when someone sets their intention to validate. + /// + /// A validator is also considered a voter with self-vote and should also be added to + /// [`Config::VoterList`]. // - // Note: it is assumed that who's staking state is updated *before* calling this method. + /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this + /// method. fn on_validator_add(who: &T::AccountId) { // target may exist in the list in case of re-enabling a chilled validator; if !T::TargetList::contains(who) { @@ -442,8 +459,8 @@ impl OnStakingUpdate> for Pallet { } } - // Fired when someone removes their intention to nominate and is completely removed from the - // staking state. + /// Fired when someone removes their intention to nominate and is completely removed from the + /// staking state. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { log!(debug, "on_nominator_remove: {:?}, impacting {:?}", who, nominations); @@ -457,8 +474,8 @@ impl OnStakingUpdate> for Pallet { ); } - // Fired when someone removes their intention to validate and is completely removed from the - // staking state. + /// Fired when someone removes their intention to validate and is completely removed from the + /// staking state. fn on_validator_remove(who: &T::AccountId) { log!(debug, "on_validator_remove: {:?}", who,); @@ -476,7 +493,8 @@ impl OnStakingUpdate> for Pallet { /// same (updates to the nominator's stake should emit [`Self::on_stake_update`] instead). /// However, the score of the nominated targets must be updated accordingly. /// - /// Note: it is assumed that who's staking state is updated *before* calling this method. + /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this + /// method. fn on_nominator_update(who: &T::AccountId, prev_nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); From a3b0b41fce2423d2f5679204b964092a3c0d0340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 13 Dec 2023 17:40:59 +0100 Subject: [PATCH 037/133] Wraps slash tests on TestExternalities --- substrate/frame/staking/src/tests.rs | 460 ++++++++++++++------------- 1 file changed, 236 insertions(+), 224 deletions(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3a9792e8e1ea..dc0576d3eeff 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6142,240 +6142,252 @@ fn force_apply_min_commission_works() { #[test] fn proportional_slash_stop_slashing_if_remaining_zero() { - let c = |era, value| UnlockChunk:: { era, value }; + ExtBuilder::default().build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; - // we have some chunks, but they are not affected. - let unlocking = bounded_vec![c(1, 10), c(2, 10)]; + // we have some chunks, but they are not affected. + let unlocking = bounded_vec![c(1, 10), c(2, 10)]; - // Given - let mut ledger = StakingLedger::::new(123, 20); - ledger.total = 40; - ledger.unlocking = unlocking; + // Given bonded ledger + let mut ledger = Staking::ledger(StakingAccount::Stash(11)).unwrap(); + ledger.total = 40; + ledger.unlocking = unlocking; - assert_eq!(BondingDuration::get(), 3); + assert_eq!(BondingDuration::get(), 3); - // should not slash more than the amount requested, by accidentally slashing the first chunk. - assert_eq!(ledger.slash(18, 1, 0), 18); + // should not slash more than the amount requested, by accidentally slashing the first + // chunk. + assert_eq!(ledger.slash(18, 1, 0), 18); + }) } #[test] fn proportional_ledger_slash_works() { - let c = |era, value| UnlockChunk:: { era, value }; - // Given - let mut ledger = StakingLedger::::new(123, 10); - assert_eq!(BondingDuration::get(), 3); - - // When we slash a ledger with no unlocking chunks - assert_eq!(ledger.slash(5, 1, 0), 5); - // Then - assert_eq!(ledger.total, 5); - assert_eq!(ledger.active, 5); - assert_eq!(LedgerSlashPerEra::get().0, 5); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // When we slash a ledger with no unlocking chunks and the slash amount is greater then the - // total - assert_eq!(ledger.slash(11, 1, 0), 5); - // Then - assert_eq!(ledger.total, 0); - assert_eq!(ledger.active, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; - ledger.total = 2 * 10; - ledger.active = 0; - // When all the chunks overlap with the slash eras - assert_eq!(ledger.slash(20, 0, 0), 20); - // Then - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(140, 0, 3), 140); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); - assert_eq!(ledger.total, 4 * 100 - 140); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.total = 4 * 100; - ledger.active = 0; - // When the first 2 chunks don't overlap with the affected range of unlock eras. - assert_eq!(ledger.slash(15, 0, 3), 15); - // Then - assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); - assert_eq!(ledger.total, 4 * 100 - 15); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); - - // Given - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - // 900 - ledger.total = 40 + 10 + 100 + 250 + 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(900 / 2, 0, 0), 450); - // Then - assert_eq!(ledger.active, 500 / 2); - assert_eq!(ledger.unlocking, vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) - ); + ExtBuilder::default().build_and_execute(|| { + let c = |era, value| UnlockChunk:: { era, value }; - // slash 1/4th with not chunk. - ledger.unlocking = bounded_vec![]; - ledger.active = 500; - ledger.total = 500; - // When we have a partial slash that touches all chunks - assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); - // Then - assert_eq!(ledger.active, 3 * 500 / 4); - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, ledger.active); - assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); - assert_eq!(LedgerSlashPerEra::get().1, Default::default()); - - // Given we have the same as above, - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!(ledger.total, 900); - // When we have a higher min balance - assert_eq!( - ledger.slash( - 900 / 2, - 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it to - * get swept */ - 0 - ), - 450 - ); - assert_eq!(ledger.active, 500 / 2); - // the last chunk was not slashed 50% like all the rest, because some other earlier chunks got - // dusted. - assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); - assert_eq!(ledger.total, 900 / 2); - assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) - ); + // Given bonded ledger + let mut ledger = Staking::ledger(StakingAccount::Stash(11)).unwrap(); + assert_eq!(BondingDuration::get(), 3); - // Given - // slash order --------------------NA--------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; - ledger.active = 500; - ledger.total = 40 + 10 + 100 + 250 + 500; // 900 - assert_eq!( - ledger.slash( - 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 - 0, - 3 /* slash era 6 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 500 + 250 + 10 + 100 / 2 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); - assert_eq!(ledger.total, 90); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); - - // Given - // iteration order------------------NA---------2----------0----------1---- - ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; - ledger.active = 100; - ledger.total = 5 * 100; - // When - assert_eq!( - ledger.slash( - 351, // active + era 6 + era 7 + era 5 / 2 + 1 - 50, // min balance - everything slashed below 50 will get dusted - 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and - * ledge.active. This will cause the affected to go to zero, and then we will - * start slashing older chunks */ - ), - 400 - ); - // Then - assert_eq!(ledger.active, 0); - assert_eq!(ledger.unlocking, vec![c(4, 100)]); - assert_eq!(ledger.total, 100); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); - - // Tests for saturating arithmetic - - // Given - let slash = u64::MAX as Balance * 2; - // The value of the other parts of ledger that will get slashed - let value = slash - (10 * 4); - - ledger.active = 10; - ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; - ledger.total = value + 40; - // When - let slash_amount = ledger.slash(slash, 0, 0); - assert_eq_error_rate!(slash_amount, slash, 5); - // Then - assert_eq!(ledger.active, 0); // slash of 9 - assert_eq!(ledger.unlocking, vec![]); - assert_eq!(ledger.total, 0); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); - - // Given - use sp_runtime::PerThing as _; - let slash = u64::MAX as Balance * 2; - let value = u64::MAX as Balance * 2; - let unit = 100; - // slash * value that will saturate - assert!(slash.checked_mul(value).is_none()); - // but slash * unit won't. - assert!(slash.checked_mul(unit).is_some()); - ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; - //--------------------------------------note value^^^ - ledger.active = unit; - ledger.total = unit * 4 + value; - // When - assert_eq!(ledger.slash(slash, 0, 0), slash); - // Then - // The amount slashed out of `unit` - let affected_balance = value + unit * 4; - let ratio = - Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up).unwrap(); - // `unit` after the slash is applied - let unit_slashed = { - let unit_slash = ratio.mul_ceil(unit); - unit - unit_slash - }; - let value_slashed = { - let value_slash = ratio.mul_ceil(value); - value - value_slash - }; - assert_eq!(ledger.active, unit_slashed); - assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); - assert_eq!(ledger.total, value_slashed + 32); - assert_eq!(LedgerSlashPerEra::get().0, 0); - assert_eq!( - LedgerSlashPerEra::get().1, - BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) - ); + assert_eq!(ledger.total, 1000); + + // When we slash a ledger with no unlocking chunks + assert_eq!(ledger.slash(5, 1, 0), 5); + + // Then + assert_eq!(ledger.total, 995); + assert_eq!(ledger.active, 995); + assert_eq!(LedgerSlashPerEra::get().0, 995); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // When we slash a ledger with no unlocking chunks and the slash amount is greater then the + // total + assert_eq!(ledger.slash(2000, 1, 0), 995); + // Then + assert_eq!(ledger.total, 0); + assert_eq!(ledger.active, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10)]; + ledger.total = 2 * 10; + ledger.active = 0; + // When all the chunks overlap with the slash eras + assert_eq!(ledger.slash(20, 0, 0), 20); + // Then + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(140, 0, 3), 140); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 30), c(7, 30)]); + assert_eq!(ledger.total, 4 * 100 - 140); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 30), (7, 30)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.total = 4 * 100; + ledger.active = 0; + // When the first 2 chunks don't overlap with the affected range of unlock eras. + assert_eq!(ledger.slash(15, 0, 3), 15); + // Then + assert_eq!(ledger.unlocking, vec![c(4, 100), c(5, 100), c(6, 100 - 8), c(7, 100 - 7)]); + assert_eq!(ledger.total, 4 * 100 - 15); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(6, 92), (7, 93)])); + + // Given + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + // 900 + ledger.total = 40 + 10 + 100 + 250 + 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(900 / 2, 0, 0), 450); + // Then + assert_eq!(ledger.active, 500 / 2); + assert_eq!( + ledger.unlocking, + vec![c(4, 40 / 2), c(5, 100 / 2), c(6, 10 / 2), c(7, 250 / 2)] + ); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 40 / 2), (5, 100 / 2), (6, 10 / 2), (7, 250 / 2)]) + ); + + // slash 1/4th with not chunk. + ledger.unlocking = bounded_vec![]; + ledger.active = 500; + ledger.total = 500; + // When we have a partial slash that touches all chunks + assert_eq!(ledger.slash(500 / 4, 0, 0), 500 / 4); + // Then + assert_eq!(ledger.active, 3 * 500 / 4); + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, ledger.active); + assert_eq!(LedgerSlashPerEra::get().0, 3 * 500 / 4); + assert_eq!(LedgerSlashPerEra::get().1, Default::default()); + + // Given we have the same as above, + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!(ledger.total, 900); + // When we have a higher min balance + assert_eq!( + ledger.slash( + 900 / 2, + 25, /* min balance - chunks with era 0 & 2 will be slashed to <=25, causing it + * to get swept */ + 0 + ), + 450 + ); + assert_eq!(ledger.active, 500 / 2); + // the last chunk was not slashed 50% like all the rest, because some other earlier chunks + // got dusted. + assert_eq!(ledger.unlocking, vec![c(5, 100 / 2), c(7, 150)]); + assert_eq!(ledger.total, 900 / 2); + assert_eq!(LedgerSlashPerEra::get().0, 500 / 2); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, 100 / 2), (6, 0), (7, 150)]) + ); + + // Given + // slash order --------------------NA--------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 40), c(5, 100), c(6, 10), c(7, 250)]; + ledger.active = 500; + ledger.total = 40 + 10 + 100 + 250 + 500; // 900 + assert_eq!( + ledger.slash( + 500 + 10 + 250 + 100 / 2, // active + era 6 + era 7 + era 5 / 2 + 0, + 3 /* slash era 6 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we will + * start slashing older chunks */ + ), + 500 + 250 + 10 + 100 / 2 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 40), c(5, 100 / 2)]); + assert_eq!(ledger.total, 90); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 100 / 2), (6, 0), (7, 0)])); + + // Given + // iteration order------------------NA---------2----------0----------1---- + ledger.unlocking = bounded_vec![c(4, 100), c(5, 100), c(6, 100), c(7, 100)]; + ledger.active = 100; + ledger.total = 5 * 100; + // When + assert_eq!( + ledger.slash( + 351, // active + era 6 + era 7 + era 5 / 2 + 1 + 50, // min balance - everything slashed below 50 will get dusted + 3 /* slash era 3+3 first, so the affected parts are era 6, era 7 and + * ledge.active. This will cause the affected to go to zero, and then we + * will start slashing older chunks */ + ), + 400 + ); + // Then + assert_eq!(ledger.active, 0); + assert_eq!(ledger.unlocking, vec![c(4, 100)]); + assert_eq!(ledger.total, 100); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(5, 0), (6, 0), (7, 0)])); + + // Tests for saturating arithmetic + + // Given + let slash = u64::MAX as Balance * 2; + // The value of the other parts of ledger that will get slashed + let value = slash - (10 * 4); + + ledger.active = 10; + ledger.unlocking = bounded_vec![c(4, 10), c(5, 10), c(6, 10), c(7, value)]; + ledger.total = value + 40; + // When + let slash_amount = ledger.slash(slash, 0, 0); + assert_eq_error_rate!(slash_amount, slash, 5); + // Then + assert_eq!(ledger.active, 0); // slash of 9 + assert_eq!(ledger.unlocking, vec![]); + assert_eq!(ledger.total, 0); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!(LedgerSlashPerEra::get().1, BTreeMap::from([(4, 0), (5, 0), (6, 0), (7, 0)])); + + // Given + use sp_runtime::PerThing as _; + let slash = u64::MAX as Balance * 2; + let value = u64::MAX as Balance * 2; + let unit = 100; + // slash * value that will saturate + assert!(slash.checked_mul(value).is_none()); + // but slash * unit won't. + assert!(slash.checked_mul(unit).is_some()); + ledger.unlocking = bounded_vec![c(4, unit), c(5, value), c(6, unit), c(7, unit)]; + //--------------------------------------note value^^^ + ledger.active = unit; + ledger.total = unit * 4 + value; + // When + assert_eq!(ledger.slash(slash, 0, 0), slash); + // Then + // The amount slashed out of `unit` + let affected_balance = value + unit * 4; + let ratio = Perquintill::from_rational_with_rounding(slash, affected_balance, Rounding::Up) + .unwrap(); + // `unit` after the slash is applied + let unit_slashed = { + let unit_slash = ratio.mul_ceil(unit); + unit - unit_slash + }; + let value_slashed = { + let value_slash = ratio.mul_ceil(value); + value - value_slash + }; + assert_eq!(ledger.active, unit_slashed); + assert_eq!(ledger.unlocking, vec![c(5, value_slashed), c(7, 32)]); + assert_eq!(ledger.total, value_slashed + 32); + assert_eq!(LedgerSlashPerEra::get().0, 0); + assert_eq!( + LedgerSlashPerEra::get().1, + BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 32)]) + ); + }) } #[test] From f1526e0c100988936c4c8794778f3121352bb41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Dec 2023 15:27:33 +0100 Subject: [PATCH 038/133] Removes ability to explicitly add moot nominations, as it fails with BadTarget --- substrate/frame/staking/src/pallet/mod.rs | 7 ++- substrate/frame/staking/src/tests.rs | 73 +++++++++++++---------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 1b5514e113c7..5f9469a3eee8 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -38,7 +38,7 @@ use sp_runtime::{ use sp_staking::{ EraIndex, OnStakingUpdate, Page, SessionIndex, - StakingAccount::{self, Controller, Stash}, + StakingAccount::{self, Controller, Stash}, StakingInterface, }; use sp_std::prelude::*; @@ -1081,6 +1081,7 @@ pub mod pallet { ledger.update()?; + // TODO(gpestana): this should not be here bu rather on the ledger.rs // update this staker in the sorted list, if they exist in it. if T::VoterList::contains(&stash) { let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); @@ -1220,7 +1221,9 @@ pub mod pallet { .map(|t| T::Lookup::lookup(t).map_err(DispatchError::from)) .map(|n| { n.and_then(|n| { - if old.contains(&n) || !Validators::::get(&n).blocked { + // a good target nomination must be a valiator (active or idle). The + // validator must not be blocked. + if Self::status(&n).is_ok() && (old.contains(&n) || !Validators::::get(&n).blocked) { Ok(n) } else { Err(Error::::BadTarget.into()) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index dc0576d3eeff..1521c835701e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -39,7 +39,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - SessionIndex, + SessionIndex, StakingInterface, }; use sp_std::prelude::*; use substrate_test_utils::assert_eq_uvec; @@ -809,11 +809,11 @@ fn double_staking_should_fail() { ); // stash => attempting to nominate should fail. assert_noop!( - Staking::nominate(RuntimeOrigin::signed(stash), vec![1]), + Staking::nominate(RuntimeOrigin::signed(stash), vec![11]), Error::::NotController ); // controller => nominating should work. - assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); }); } @@ -1868,10 +1868,10 @@ fn switching_roles() { // add 2 nominators assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2000, RewardDestination::Account(1))); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 5])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(1), vec![11, 31])); assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 500, RewardDestination::Account(3))); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21, 31])); // add a new validator candidate assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 1000, RewardDestination::Account(5))); @@ -1884,8 +1884,8 @@ fn switching_roles() { mock::start_active_era(1); - // with current nominators 11 and 5 have the most stake - assert_eq_uvec!(validator_controllers(), vec![5, 11]); + // with current nominators 11 and 31 have the most stake + assert_eq_uvec!(validator_controllers(), vec![11, 31]); // 1 decides to be a validator. Consequences: assert_ok!(Staking::validate(RuntimeOrigin::signed(1), ValidatorPrefs::default())); @@ -1911,7 +1911,7 @@ fn switching_roles() { } #[test] -fn wrong_vote_is_moot() { +fn wrong_vote_errors() { ExtBuilder::default() .add_staker( 61, @@ -1919,7 +1919,6 @@ fn wrong_vote_is_moot() { 500, StakerStatus::Nominator(vec![ 11, 21, // good votes - 1, 2, 15, 1000, 25, // crap votes. No effect. ]), ) .build_and_execute(|| { @@ -1932,6 +1931,14 @@ fn wrong_vote_is_moot() { // our new voter is taken into account assert!(Staking::eras_stakers(active_era(), &11).others.iter().any(|i| i.who == 61)); assert!(Staking::eras_stakers(active_era(), &21).others.iter().any(|i| i.who == 61)); + + // trying to nominate a non-validator will fail. + assert_noop!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 1000]), Error::::BadTarget); + + // however, nominating an `Idle` validator is OK. + assert_eq!(Staking::status(&41), Ok(StakerStatus::Idle)); + assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 31, 41])); }); } @@ -5169,7 +5176,7 @@ mod election_data_provider { assert_eq!(::VoterList::count(), 4); assert_ok!(Staking::bond(RuntimeOrigin::signed(4), 5, Default::default(),)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![11])); assert_eq!(::VoterList::count(), 5); let voters_before = @@ -5421,11 +5428,12 @@ mod election_data_provider { fn lazy_quota_npos_voters_works_above_quota() { ExtBuilder::default() .nominate(false) + .has_stakers(true) .add_staker( 61, 60, 300, // 300 bond has 16 nomination quota. - StakerStatus::::Nominator(vec![21, 22, 23, 24, 25]), + StakerStatus::::Nominator(vec![11, 21, 31, 41]), ) .build_and_execute(|| { // unbond 78 from stash 60 so that it's bonded balance is 222, which has a lower @@ -5434,14 +5442,17 @@ mod election_data_provider { assert_eq!(Staking::api_nominations_quota(300 - 78), 2); // even through 61 has nomination quota of 2 at the time of the election, all the - // nominations (5) will be used. + // active nominations (4) will be used. + let expected_nominations = Staking::nominations(&61) + .unwrap_or(vec![]).len(); + assert_eq!( Staking::electing_voters(DataProviderBounds::default()) .unwrap() .iter() .map(|(stash, _, targets)| (*stash, targets.len())) .collect::>(), - vec![(11, 1), (21, 1), (31, 1), (61, 5)], + vec![(11, 1), (21, 1), (31, 1), (61, expected_nominations)], ); }); } @@ -5450,11 +5461,12 @@ mod election_data_provider { fn nominations_quota_limits_size_work() { ExtBuilder::default() .nominate(false) + .has_stakers(true) .add_staker( 71, 70, 333, - StakerStatus::::Nominator(vec![16, 15, 14, 13, 12, 11, 10]), + StakerStatus::::Nominator(vec![11, 21, 31, 41]), ) .build_and_execute(|| { // nominations of controller 70 won't be added due to voter size limit exceeded. @@ -5482,7 +5494,7 @@ mod election_data_provider { .iter() .map(|(stash, _, targets)| (*stash, targets.len())) .collect::>(), - vec![(11, 1), (21, 1), (31, 1), (71, 7)], + vec![(11, 1), (21, 1), (31, 1), (71, 4)], ); }); } @@ -5588,7 +5600,7 @@ fn min_bond_checks_work() { // 1000 is enough for nominator assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11])); assert_noop!( Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default()), Error::::InsufficientBond, @@ -5596,7 +5608,7 @@ fn min_bond_checks_work() { // 1500 is enough for validator assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11])); assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default())); // Can't unbond anything as validator @@ -5606,7 +5618,7 @@ fn min_bond_checks_work() { ); // Once they are a nominator, they can unbond 500 - assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![11])); assert_ok!(Staking::unbond(RuntimeOrigin::signed(3), 500)); assert_noop!( Staking::unbond(RuntimeOrigin::signed(3), 500), @@ -5639,7 +5651,7 @@ fn chill_other_works() { // Nominator assert_ok!(Staking::bond(RuntimeOrigin::signed(a), 1000, RewardDestination::Stash)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(a), vec![11])); // Validator assert_ok!(Staking::bond(RuntimeOrigin::signed(b), 1500, RewardDestination::Stash)); @@ -5925,8 +5937,8 @@ fn min_commission_works() { fn change_of_absolute_max_nominations() { use frame_election_provider_support::ElectionDataProvider; ExtBuilder::default() - .add_staker(61, 61, 10, StakerStatus::Nominator(vec![1])) - .add_staker(71, 71, 10, StakerStatus::Nominator(vec![1, 2, 3])) + .add_staker(61, 61, 10, StakerStatus::Nominator(vec![11])) + .add_staker(71, 71, 10, StakerStatus::Nominator(vec![11, 21, 31])) .balance_factor(10) .build_and_execute(|| { // pre-condition @@ -6002,7 +6014,7 @@ fn change_of_absolute_max_nominations() { assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 1); // now one of them can revive themselves by re-nominating to a proper value. - assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![11])); assert_eq!( Nominators::::iter() .map(|(k, n)| (k, n.targets.len())) @@ -6023,10 +6035,10 @@ fn change_of_absolute_max_nominations() { fn nomination_quota_max_changes_decoding() { use frame_election_provider_support::ElectionDataProvider; ExtBuilder::default() - .add_staker(60, 61, 10, StakerStatus::Nominator(vec![1])) - .add_staker(70, 71, 10, StakerStatus::Nominator(vec![1, 2, 3])) - .add_staker(30, 330, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) - .add_staker(50, 550, 10, StakerStatus::Nominator(vec![1, 2, 3, 4])) + .add_staker(60, 61, 10, StakerStatus::Nominator(vec![11])) + .add_staker(70, 71, 10, StakerStatus::Nominator(vec![11, 21, 31])) + .add_staker(30, 330, 10, StakerStatus::Nominator(vec![11, 21, 31, 41])) + .add_staker(50, 550, 10, StakerStatus::Nominator(vec![11, 21, 31, 41])) .balance_factor(10) .build_and_execute(|| { // pre-condition. @@ -7154,8 +7166,7 @@ mod stake_tracker { #[test] fn bond_and_unbond_work() { // Test case: unbond on validator and nominator affects the target list score - // accordingly and rebagging may happen. It also adds some moot nominations that are - // basically noops. + // accordingly and rebagging may happen. // Call paths covered: // * Call::validate() // * Call::nominate() @@ -7164,11 +7175,7 @@ mod stake_tracker { ExtBuilder::default().build_and_execute(|| { // bond and nominate with stash 61. assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, Default::default())); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31, 7777, 8888])); - - // 7777 and 8888 are moot nominations. - assert_noop!(Staking::status(&7777), Error::::NotStash); - assert_noop!(Staking::status(&8888), Error::::NotStash); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31])); assert_ok!(stake_tracker_sanity_tests()); From 2870db31e086aeedca51f6d912aa19d62cef17fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 20 Dec 2023 23:42:37 +0100 Subject: [PATCH 039/133] Keeps approvals even if the validator chills or stash is killed (if there are nominations) m --- substrate/frame/staking/src/pallet/impls.rs | 10 +- substrate/frame/staking/src/tests.rs | 80 ++++---- .../frame/staking/stake-tracker/src/lib.rs | 174 ++++++++++-------- .../frame/staking/stake-tracker/src/mock.rs | 64 +++++-- .../frame/staking/stake-tracker/src/tests.rs | 125 ++++++++++--- substrate/primitives/staking/src/lib.rs | 1 + 6 files changed, 306 insertions(+), 148 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b1c9c1550916..f0327431a7bd 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -957,9 +957,11 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - // target list also contains chilled/idle validators, filter those. - let mut targets_iter = - T::TargetList::iter().filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)); + // target list also contains chilled/idle validators and unbonded ledgers. filter those. + let mut targets_iter = T::TargetList::iter() + .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) + .filter(|t| !Self::status(&t).is_err()); + while all_targets.len() < final_predicted_len as usize && targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -1111,6 +1113,7 @@ impl Pallet { pub(crate) fn do_chill_validator(who: &T::AccountId) -> bool { if Validators::::contains_key(who) { Validators::::remove(who); + T::EventListeners::on_validator_idle(who); true } else { false @@ -1933,6 +1936,7 @@ impl Pallet { ensure!( ::TargetList::iter() .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) + .filter(|t| !Self::status(&t).is_err()) .count() as u32 == Validators::::count(), "wrong external count (TargetList.count != Validators.count)" ); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 1521c835701e..78f17d3abc61 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1933,7 +1933,10 @@ fn wrong_vote_errors() { assert!(Staking::eras_stakers(active_era(), &21).others.iter().any(|i| i.who == 61)); // trying to nominate a non-validator will fail. - assert_noop!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 1000]), Error::::BadTarget); + assert_noop!( + Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 1000]), + Error::::BadTarget + ); // however, nominating an `Idle` validator is OK. assert_eq!(Staking::status(&41), Ok(StakerStatus::Idle)); @@ -5061,11 +5064,12 @@ mod sorted_list_provider_integration { // initial targets. assert_eq!(TargetBagsList::iter().count(), 3); - assert_eq!(TargetBagsList::contains(&42), false); + assert!(!TargetBagsList::contains(&42)); // bond and set intention to validate. stash 42 is both target and voter. assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, Default::default())); assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); + assert_eq!(Staking::status(&42), Ok(StakerStatus::Validator)); assert_eq!(TargetBagsList::score(&42), 25); assert_eq!(VoterBagsList::score(&42), 25); @@ -5083,15 +5087,16 @@ mod sorted_list_provider_integration { // stash 42 chills, thus it should be part of the voter and target bags list but with // `Idle` status. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); - assert_eq!(VoterBagsList::contains(&42), true); - assert_eq!(TargetBagsList::contains(&42), true); + assert!(VoterBagsList::contains(&42)); + assert!(TargetBagsList::contains(&42)); assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); + // the target score of 42 is 0, since it is chilled and it has no nominations. + assert_eq!(TargetBagsList::score(&42), 0); - // finally, remove the validator (similar to withdraw all and subsequent ledger kill). + // after killing the stash, the node is removed from the target list. assert_ok!(Staking::kill_stash(&42, 0)); - assert_eq!(VoterBagsList::contains(&42), false); - assert_eq!(TargetBagsList::contains(&42), false); - assert!(Staking::status(&42).is_err()); + assert!(!TargetBagsList::contains(&42)); + assert_eq!(>::score(&42), 0); }) } } @@ -5443,8 +5448,7 @@ mod election_data_provider { // even through 61 has nomination quota of 2 at the time of the election, all the // active nominations (4) will be used. - let expected_nominations = Staking::nominations(&61) - .unwrap_or(vec![]).len(); + let expected_nominations = Staking::nominations(&61).unwrap_or(vec![]).len(); assert_eq!( Staking::electing_voters(DataProviderBounds::default()) @@ -5462,12 +5466,7 @@ mod election_data_provider { ExtBuilder::default() .nominate(false) .has_stakers(true) - .add_staker( - 71, - 70, - 333, - StakerStatus::::Nominator(vec![11, 21, 31, 41]), - ) + .add_staker(71, 70, 333, StakerStatus::::Nominator(vec![11, 21, 31, 41])) .build_and_execute(|| { // nominations of controller 70 won't be added due to voter size limit exceeded. let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build(); @@ -7344,7 +7343,7 @@ mod stake_tracker { BagsEvent::Rebagged { who: 11, from: 10000, to: 1000 }, BagsEvent::ScoreUpdated { who: 11, new_score: 1000 }, BagsEvent::Rebagged { who: 21, from: 10000, to: 1000 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 1000 } + BagsEvent::ScoreUpdated { who: 21, new_score: 1000 }, ] ); System::reset_events(); @@ -7352,28 +7351,31 @@ mod stake_tracker { // let's chill a validator now. assert_ok!(Staking::chill(RuntimeOrigin::signed(11))); - // the chilled validator score remains the same, 11 is still part of the targets list - // but its staker status is Idle and it was removed from the nominator sand validators - // list. + // the chilled validator score drops to 0, since it had only self-stake before chill. + assert_eq!(>::score(&11), 0); + + // 11 is still part of the targets list although the score is 0, since its status is + // Idle. However, it has been removed from the nominator sand validators lists. assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); - assert_eq!(>::score(&11), 1000); - assert_eq!(voters_and_targets().1, [(11, 1000), (21, 1000), (31, 500)]); + assert_eq!(voters_and_targets().1, [(21, 1000), (31, 500), (11, 0)]); assert!(!Nominators::::contains_key(&11)); assert!(!Validators::::contains_key(&11)); // now, let's have 101 re-nominate 21. Note that 101 also nominates 11: even // though 11 is chilled at the moment. assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![21, 11])); - assert_eq!(voters_and_targets().1, [(21, 2100), (11, 2100), (31, 500)]); + assert_eq!(voters_and_targets().1, [(21, 2100), (11, 1100), (31, 500)]); // score update and rebag hapened to 21 and 11 (idle) due to nomination of 101. assert_eq!( target_bags_events(), [ + BagsEvent::Rebagged { who: 11, from: 1000, to: 100 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 0 }, BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, BagsEvent::ScoreUpdated { who: 21, new_score: 2100 }, - BagsEvent::Rebagged { who: 11, from: 1000, to: 10000 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 2100 }, + BagsEvent::Rebagged { who: 11, from: 100, to: 2000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1100 }, ] ); @@ -7491,7 +7493,7 @@ mod stake_tracker { // Test case: slashing a validator affects the target list score of the validator according // to its slashed self-stake and the slashed stake of its nominators. A slash may cause // target list rebagging of indirect slashing (targets which were not slashed by their - // nominators were exposed to a slash from validator). + // nominators but were exposed to a slash from another validator). // Call paths covered: // * Call::validate() // * Call::nominate() @@ -7507,7 +7509,7 @@ mod stake_tracker { assert_eq!(voters_and_targets().1, [(21, 2050), (11, 2050), (31, 500)]); assert_ok!(stake_tracker_sanity_tests()); - // get the bonded stake of the nominators that wilbe affected by the slash. + // get the bonded stake of the nominators that will be affected by the slash. let stake_101_before = Staking::ledger(Stash(101)).unwrap().active; let stake_41_before = Staking::ledger(Stash(41)).unwrap().active; @@ -7538,12 +7540,16 @@ mod stake_tracker { ); // 11 has been chilled but it is still part of the targets list and it is in `Idle` - // state. + // state. It's current approvals reflects the fact that it is chilled (no self-stake) + // and the slash. assert!(>::contains(&11)); assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); - // and its balance has been updated based on the slash applied. + // and its balance has been updated based on the slash applied + chilling. let score_11_after = >::score(&11); - assert_eq!(score_11_after, score_11_before - total_stake_to_slash); + assert_eq!( + score_11_after, + score_11_before - total_stake_to_slash - self_stake_11_before + ); // self-stake of 11 has decreased by 50% due to slash. assert_eq!( @@ -7568,21 +7574,25 @@ mod stake_tracker { ); // the target list has been updated accordingly and an indirect rebag of 21 happened. - // 11, althoug chilled, is still part of the target list. + // Although 11 is chilled, it is still part of the target list. assert_eq!( voters_and_targets().1, - [(11, score_11_after), (21, score_21_after), (31, 500)] + [(21, score_21_after), (31, 500), (11, score_11_after)] ); assert_eq!( target_bags_events(), [ BagsEvent::Rebagged { who: 11, from: 10000, to: 2000 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 1550 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 1465 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1050 }, + BagsEvent::Rebagged { who: 11, from: 2000, to: 600 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 550 }, + BagsEvent::Rebagged { who: 11, from: 600, to: 500 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 465 }, BagsEvent::Rebagged { who: 21, from: 10000, to: 2000 }, BagsEvent::ScoreUpdated { who: 21, new_score: 1965 }, BagsEvent::ScoreUpdated { who: 21, new_score: 1872 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 1372 }, + BagsEvent::Rebagged { who: 11, from: 500, to: 400 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 372 }, ] ); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index faddb143465e..8f89b144f7e7 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -71,6 +71,7 @@ use frame_support::{ traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; use sp_npos_elections::ExtendedBalance; +use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; @@ -189,29 +190,28 @@ pub mod pallet { ) } - /// Updates a staker's score by increasing/decreasing an imbalance of the current score in - /// the list. - pub(crate) fn update_score( + /// Updates a target's score by increasing/decreasing an imbalance of the current score in + /// the target list. + pub(crate) fn update_target_score( who: &T::AccountId, imbalance: StakeImbalance, - ) where - L: SortedListProvider, Score = BalanceOf>, - { + ) { // there may be nominators who nominate a non-existant validator. if that's the case, // move on. This is an expected behaviour, so no defensive. - if !L::contains(who) { + if !T::TargetList::contains(who) { log!(debug, "update_score of {:?}, which is not a target", who); return } match imbalance { StakeImbalance::Positive(imbalance) => { - let _ = L::on_increase(who, Self::to_currency(imbalance)).defensive_proof( - "staker should exist in the list, otherwise returned earlier.", - ); + let _ = T::TargetList::on_increase(who, Self::to_currency(imbalance)) + .defensive_proof( + "staker should exist in the list, otherwise returned earlier.", + ); }, StakeImbalance::Negative(imbalance) => { - if let Ok(current_score) = L::get_score(who) { + if let Ok(current_score) = T::TargetList::get_score(who) { // if decreasing the imbalance makes the score lower than 0, the node will // be removed from the list when calling `L::on_decrease`, which is not // expected. Instead, we call `L::on_update` to set the new score that @@ -220,9 +220,18 @@ pub mod pallet { let balance = Self::to_vote_extended(current_score).saturating_sub(imbalance); - let _ = L::on_update(who, Self::to_currency(balance)).defensive_proof( - "staker exists in the list as per the check above; qed.", - ); + let _ = T::TargetList::on_update(who, Self::to_currency(balance)) + .defensive_proof( + "staker exists in the list as per the check above; qed.", + ); + + // the target is removed from the list IFF score is 0 and the ledger is not + // bonded in staking. + if balance.is_zero() && T::Staking::status(who).is_err() { + let _ = T::TargetList::on_remove(who).defensive_proof( + "staker exists in the list as per the check above; qed.", + ); + } } else { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); } @@ -232,17 +241,7 @@ pub mod pallet { #[cfg(any(test, feature = "try-runtime"))] pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - // Invariants 1: - // * All stakers in the target list are of type validator. - for target in T::TargetList::iter() { - if ::status(&target).unwrap_or(StakerStatus::Idle) != - StakerStatus::Validator - { - return Err("staker in target list is not a validator")? - } - } - - // Invariant 2: + // Invariant 1: // * The target score in the target list is the sum of self-stake and all stake from // nominations. // * All valid validators are part of the target list. @@ -367,13 +366,13 @@ impl OnStakingUpdate> for Pallet { // updates vote weight of nominated targets accordingly. Note: this will update // the score of up to `T::MaxNominations` validators. for target in nominations.into_iter() { - Self::update_score::(&target, stake_imbalance); + Self::update_target_score(&target, stake_imbalance); } }, StakerStatus::Validator => { // validator is both a target and a voter. let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); - Self::update_score::(&who, stake_imbalance); + Self::update_target_score(&who, stake_imbalance); let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( "the staker should exit in VoterList, as per the \ @@ -385,6 +384,72 @@ impl OnStakingUpdate> for Pallet { } } + /// Fired when someone sets their intention to validate. + /// + /// A validator is also considered a voter with self-vote and should also be added to + /// [`Config::VoterList`]. + // + /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this + /// method. + fn on_validator_add(who: &T::AccountId) { + // target may exist in the list in case of re-enabling a chilled validator; + if !T::TargetList::contains(who) { + let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)) + .expect("staker does not exist in the list as per check above; qed."); + } + + log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); + + // a validator is also a nominator. + Self::on_nominator_add(who) + } + + /// Fired when a validator becomes idle (i.e. chilling). + /// + /// While chilled, the target node remains in the grget list. + /// + /// While idling, the target node is not removed from the target list but its score is updated. + fn on_validator_idle(who: &T::AccountId) { + let self_stake = Self::weight_of(Self::active_vote_of(who)); + Self::update_target_score(who, StakeImbalance::Negative(self_stake.into())); + + // validator is a nominator too. + Self::on_nominator_idle(who, vec![]); + + log!(debug, "on_validator_idle: {:?}, decreased self-stake {}", who, self_stake); + } + + /// Fired when someone removes their intention to validate and is completely removed from the + /// staking state. + /// + /// The node is removed from the target list IFF its score is 0. + fn on_validator_remove(who: &T::AccountId) { + log!(debug, "on_validator_remove: {:?}", who,); + + // validator must be idle before removing completely. + if let Ok(status) = T::Staking::status(who) { + if status != StakerStatus::Idle { + Self::on_validator_idle(who); + } + } else { + defensive!("on_validator_remove called on a non-existing target."); + return + } + + // remove from target list IIF score is zero. + match T::TargetList::get_score(&who) { + Ok(score) => + if score.is_zero() { + let _ = T::TargetList::on_remove(&who) + .expect("target exists as per the check above; qed."); + }, + Err(_) => (), // nothing to see here. + } + + // validator is a nominator too. + Self::on_nominator_remove(who, vec![]); + } + /// Fired when someone sets their intention to nominate. /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is @@ -405,10 +470,7 @@ impl OnStakingUpdate> for Pallet { match T::Staking::status(who).defensive() { Ok(StakerStatus::Nominator(nominations)) => for t in nominations { - Self::update_score::( - &t, - StakeImbalance::Positive(nominator_vote.into()), - ) + Self::update_target_score(&t, StakeImbalance::Positive(nominator_vote.into())) }, Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) | Err(_) => (), // nada. }; @@ -416,28 +478,9 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_nominator_add: {:?}. role: {:?}", who, T::Staking::status(who),); } - /// Fired when someone sets their intention to validate. + /// Fired when a nominator becomes idle (i.e. chilling). /// - /// A validator is also considered a voter with self-vote and should also be added to - /// [`Config::VoterList`]. - // - /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this - /// method. - fn on_validator_add(who: &T::AccountId) { - // target may exist in the list in case of re-enabling a chilled validator; - if !T::TargetList::contains(who) { - let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)) - .expect("staker does not exist in the list as per check above; qed."); - } - - log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); - - // a validator is also a nominator. - Self::on_nominator_add(who) - } - - /// Fired when some nominator becomes idle and stops nominating without being removed from the - /// staking state. + /// While chilled, the voter node remains in the voter list. /// /// Note: it is assumed that `who`'s staking ledger and `nominations` are up to date before /// calling this method. @@ -455,7 +498,7 @@ impl OnStakingUpdate> for Pallet { // updates the nominated target's score. Note: this may update the score of up to // `T::MaxNominations` validators. for t in nominations.iter() { - Self::update_score::(&t, StakeImbalance::Negative(nominator_vote.into())) + Self::update_target_score(&t, StakeImbalance::Negative(nominator_vote.into())) } } @@ -474,19 +517,6 @@ impl OnStakingUpdate> for Pallet { ); } - /// Fired when someone removes their intention to validate and is completely removed from the - /// staking state. - fn on_validator_remove(who: &T::AccountId) { - log!(debug, "on_validator_remove: {:?}", who,); - - let _ = T::TargetList::on_remove(&who).defensive_proof( - "the validator exists in the list as per the contract with staking; qed.", - ); - - // validator is also a nominator. - Self::on_nominator_remove(who, vec![]); - } - /// Fired when an existing nominator updates their nominations. /// /// This is called when a nominator updates their nominations. The nominator's stake remains the @@ -510,19 +540,13 @@ impl OnStakingUpdate> for Pallet { // new nominations for target in curr_nominations.iter() { if !prev_nominations.contains(target) { - Self::update_score::( - &target, - StakeImbalance::Positive(nominator_vote.into()), - ); + Self::update_target_score(&target, StakeImbalance::Positive(nominator_vote.into())); } } // removed nominations for target in prev_nominations.iter() { if !curr_nominations.contains(target) { - Self::update_score::( - &target, - StakeImbalance::Negative(nominator_vote.into()), - ); + Self::update_target_score(&target, StakeImbalance::Negative(nominator_vote.into())); } } } @@ -542,7 +566,7 @@ impl OnStakingUpdate> for Pallet { match T::Staking::status(stash).defensive_proof("called on_slash on a unbonded stash") { Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) => - Self::update_score::(stash, stake_imbalance), + Self::update_target_score(stash, stake_imbalance), // score of target impacted by nominators will be updated through ledger.update. Ok(StakerStatus::Nominator(_)) => (), Err(_) => (), // nothing to see here. diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 0568190197f3..895225e5bc39 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -140,11 +140,17 @@ impl StakingInterface for StakingMock { ) -> Result, sp_runtime::DispatchError> { let nominators = TestNominators::get(); - match (TestValidators::get().contains_key(who), nominators.contains_key(who)) { - (true, true) => Ok(StakerStatus::Validator), - (false, true) => + match ( + TestValidators::get().contains_key(who), + nominators.contains_key(who), + Bonded::get().contains(who), + ) { + (true, true, true) => Ok(StakerStatus::Validator), + (false, true, true) => Ok(StakerStatus::Nominator(nominators.get(&who).expect("exists").1.clone())), - _ => Err("mock: not a staker or inconsistent data".into()), + (false, false, true) => Ok(StakerStatus::Idle), + (false, false, false) => Err("not a staker".into()), + _ => Err("mock: inconsistent data".into()), } } @@ -249,6 +255,7 @@ type Nominations = Vec; parameter_types! { pub static TestNominators: BTreeMap, Nominations)> = Default::default(); pub static TestValidators: BTreeMap> = Default::default(); + pub static Bonded: Vec = Default::default(); } pub(crate) fn get_scores>( @@ -266,6 +273,10 @@ pub(crate) fn populate_lists() { } pub(crate) fn add_nominator(who: AccountId, stake: Balance) { + Bonded::mutate(|b| { + b.push(who); + }); + TestNominators::mutate(|n| { n.insert(who, (Stake:: { active: stake, total: stake }, vec![])); }); @@ -316,6 +327,10 @@ pub(crate) fn update_nominations_of(who: AccountId, new_nominations: Nominations } pub(crate) fn add_validator(who: AccountId, stake: Balance) { + Bonded::mutate(|b| { + b.push(who); + }); + TestValidators::mutate(|v| { v.insert(who, Stake:: { active: stake, total: stake }); }); @@ -349,23 +364,46 @@ pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option>::on_stake_update(&who, prev_stake); } -pub(crate) fn remove_staker(who: AccountId) { +pub(crate) fn chill_staker(who: AccountId) { if TestNominators::get().contains_key(&who) && !TestValidators::get().contains_key(&who) { let nominations = ::nominations(&who).unwrap(); - >::on_nominator_remove( - &who, - nominations, - ); - TestNominators::mutate(|n| { - n.remove(&who); - }); + >::on_nominator_idle(&who, nominations); + TestNominators::mutate(|n| n.remove(&who)); } else if TestValidators::get().contains_key(&who) { - >::on_validator_remove(&who); + >::on_validator_idle(&who); TestValidators::mutate(|v| v.remove(&who)); + TestNominators::mutate(|v| v.remove(&who)); }; } +pub(crate) fn remove_staker(who: AccountId) { + match StakingMock::status(&who) { + Ok(StakerStatus::Nominator(_)) => { + let nominations = ::nominations(&who).unwrap(); + >::on_nominator_remove( + &who, + nominations, + ); + TestNominators::mutate(|n| { + n.remove(&who); + }); + }, + Ok(StakerStatus::Validator) => { + >::on_validator_remove(&who); + TestValidators::mutate(|v| v.remove(&who)); + }, + Ok(StakerStatus::Idle) => { + >::on_validator_remove(&who); + }, + _ => {}, + } + + Bonded::mutate(|b| { + b.retain(|s| s != &who); + }); +} + pub(crate) fn target_bags_events() -> Vec> { System::events() .into_iter() diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index f427e7f3ad9a..3b38eb179940 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -21,7 +21,7 @@ use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_support::assert_ok; -use sp_staking::{OnStakingUpdate, Stake, StakingInterface}; +use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingInterface}; // keeping tests clean. type A = AccountId; @@ -47,25 +47,23 @@ fn setup_works() { } #[test] -fn update_score_works() { +fn update_target_score_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - assert!(VoterBagsList::contains(&1)); - assert_eq!(VoterBagsList::get_score(&1), Ok(100)); + assert!(TargetBagsList::contains(&10)); + assert_eq!(TargetBagsList::get_score(&10), Ok(300)); - crate::Pallet::::update_score::(&1, StakeImbalance::Negative(10)); - assert_eq!(VoterBagsList::get_score(&1), Ok(90)); + crate::Pallet::::update_target_score(&10, StakeImbalance::Negative(100)); + assert_eq!(TargetBagsList::get_score(&10), Ok(200)); - crate::Pallet::::update_score::(&1, StakeImbalance::Positive(100)); - assert_eq!(VoterBagsList::get_score(&1), Ok(190)); + crate::Pallet::::update_target_score(&10, StakeImbalance::Positive(100)); + assert_eq!(TargetBagsList::get_score(&10), Ok(300)); - // when score decreases to 0, the node is not removed automatically and its balance is 0. - let current_score = VoterBagsList::get_score(&1).unwrap(); - crate::Pallet::::update_score::( - &1, + let current_score = TargetBagsList::get_score(&10).unwrap(); + crate::Pallet::::update_target_score( + &10, StakeImbalance::Negative(current_score.into()), ); - assert!(VoterBagsList::contains(&1)); - assert_eq!(VoterBagsList::get_score(&1), Ok(0)); + assert_eq!(TargetBagsList::get_score(&10), Ok(0)); // disables the try runtime checks since the score of 10 was updated manually, so the target // list was not updated accordingly. @@ -246,7 +244,7 @@ fn on_stake_update_defensive_not_in_list_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: Other(\"mock: not a staker or inconsistent data\"): \"staker should exist when calling on_stake_update and have a valid status\""] +#[should_panic = "Defensive failure has been triggered!: Other(\"not a staker\"): \"staker should exist when calling on_stake_update and have a valid status\""] fn on_stake_update_defensive_not_staker_works() { ExtBuilder::default().build_and_execute(|| { assert!(!VoterBagsList::contains(&1)); @@ -262,12 +260,7 @@ fn on_nominator_add_works() { assert!(!VoterBagsList::contains(&5)); assert_eq!(n.get(&5), None); - // add 5 as staker. - TestNominators::mutate(|n| { - n.insert(5, Default::default()); - }); - - >::on_nominator_add(&5); + add_nominator(5, 10); assert!(VoterBagsList::contains(&5)); }) } @@ -371,7 +364,7 @@ fn on_nominator_remove_defensive_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the validator exists in the list as per the contract with staking; qed.\""] +#[should_panic = "Defensive failure has been triggered!: \"on_validator_remove called on a non-existing target.\""] fn on_validator_remove_defensive_works() { ExtBuilder::default().build_and_execute(|| { assert!(!TargetBagsList::contains(&1)); @@ -391,10 +384,30 @@ mod staking_integration { add_nominator(1, 100); let n = TestNominators::get(); assert_eq!(n.get(&1).unwrap().0, Stake { active: 100u64, total: 100u64 }); + assert_eq!(StakingMock::status(&1), Ok(StakerStatus::Nominator(vec![]))); add_validator(2, 200); let v = TestValidators::get(); assert_eq!(v.get(&2).copied().unwrap(), Stake { active: 200u64, total: 200u64 }); + assert_eq!(StakingMock::status(&2), Ok(StakerStatus::Validator)); + + chill_staker(1); + assert_eq!(StakingMock::status(&1), Ok(StakerStatus::Idle)); + assert!(VoterBagsList::contains(&1)); + + remove_staker(1); + assert!(StakingMock::status(&1).is_err()); + assert!(!VoterBagsList::contains(&1)); + + chill_staker(2); + assert_eq!(StakingMock::status(&2), Ok(StakerStatus::Idle)); + assert!(TargetBagsList::contains(&2)); + assert!(VoterBagsList::contains(&2)); + + remove_staker(2); + assert!(StakingMock::status(&2).is_err()); + assert!(!TargetBagsList::contains(&2)); + assert!(!VoterBagsList::contains(&2)); }) } @@ -482,4 +495,72 @@ mod staking_integration { assert_eq!(get_scores::(), vec![(20, 600), (11, 200), (10, 200)]); }) } + + #[test] + fn target_chill_remove_lifecycle_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(TargetBagsList::contains(&10)); + // 10 has 2 nominations from 1 and 2. Each with 100 approvals, so 300 in total (2x + // nominated + // + 1x self-stake). + assert_eq!(>::score(&10), 300); + + // chill validator 10. + chill_staker(10); + assert_eq!(StakingMock::status(&10), Ok(StakerStatus::Idle)); + + // chilling removed the self stake (100) from score, but the nominations approvals + // remain. + assert!(TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 200); + + // even if the validator is removed, the target node remains in the list since approvals + // score != 0. + remove_staker(10); + assert!(TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 200); + assert!(StakingMock::status(&10).is_err()); + + // 1 stops nominating 10. + update_nominations_of(1, vec![]); + assert!(TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 100); + + // 2 stops nominating 10 and its approavals dropped to 0, thus the target node has been + // removed. + update_nominations_of(2, vec![]); + assert!(!TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 0); + }) + } + + #[test] + fn target_remove_lifecycle_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + assert!(TargetBagsList::contains(&10)); + // 10 has 2 nominations from 1 and 2. Each with 100 approvals, so 300 in total (2x + // nominated + // + 1x self-stake). + assert_eq!(>::score(&10), 300); + + // remove validator 10. + remove_staker(10); + + // but the target list keeps track of the remaining approvals of 10, without the self + // stake. + assert!(TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 200); + + // 1 stops nominating 10. + update_nominations_of(1, vec![]); + assert!(TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 100); + + // 2 stops nominating 10. Since approvals of 10 drop to 0, the target list node is + // removed. + update_nominations_of(2, vec![]); + assert!(!TargetBagsList::contains(&10)); + assert_eq!(>::score(&10), 0); + }) + } } diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 40ac62d674de..1496bb116d80 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -176,6 +176,7 @@ pub trait StakingInterface { + MaxEncodedLen + FullCodec + TypeInfo + + Zero + Saturating; /// AccountId type used by the staking system. From 6713df37a7afc7121bf6430c9635837a0af1eba0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 24 Dec 2023 11:53:05 +0000 Subject: [PATCH 040/133] Update docs; VoterList node is removed upon chilling. --- substrate/frame/staking/src/pallet/impls.rs | 5 +- substrate/frame/staking/src/pallet/mod.rs | 26 ++-- substrate/frame/staking/src/tests.rs | 17 ++- .../frame/staking/stake-tracker/src/lib.rs | 120 +++++++++--------- .../frame/staking/stake-tracker/src/mock.rs | 7 +- .../frame/staking/stake-tracker/src/tests.rs | 10 +- 6 files changed, 103 insertions(+), 82 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index f0327431a7bd..9f23098b8882 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -329,7 +329,6 @@ impl Pallet { let chilled_as_validator = Self::do_chill_validator(stash); let chilled_as_nominator = Self::do_chill_nominator(stash); if chilled_as_validator || chilled_as_nominator { - debug_assert!(T::VoterList::contains(stash) || T::TargetList::contains(stash)); debug_assert_eq!(Self::status(stash), Ok(StakerStatus::Idle)); Self::deposit_event(Event::::Chilled { stash: stash.clone() }); @@ -847,9 +846,7 @@ impl Pallet { let mut nominators_taken = 0u32; let mut min_active_stake = u64::MAX; - // voter list also contains chilled/idle voters, filter those. - let mut sorted_voters = - T::VoterList::iter().filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)); + let mut sorted_voters = T::VoterList::iter(); while all_voters.len() < final_predicted_len as usize && voters_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5f9469a3eee8..e62f2563a9bc 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -38,7 +38,8 @@ use sp_runtime::{ use sp_staking::{ EraIndex, OnStakingUpdate, Page, SessionIndex, - StakingAccount::{self, Controller, Stash}, StakingInterface, + StakingAccount::{self, Controller, Stash}, + StakingInterface, }; use sp_std::prelude::*; @@ -222,21 +223,20 @@ pub mod pallet { /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; - /// Something that provides a best-effort sorted list of voters (aka electing and chilled - /// nominators), used for NPoS election. + /// Something that provides a best-effort sorted list of voters (aka electing nominators), + /// used for NPoS election. /// /// The changes to nominators are reported to this. Moreover, each validator's self-vote is /// also reported as one independent vote. /// - /// Voters will be removed from this list when their ledger is killed. Otherwise, the voter - /// is kept in this list, even when it is chilled. + /// Voters will be removed from this list when their ledger is killed or the nominator is + /// chilled. /// /// To keep the load off the chain as much as possible, changes made to the staked amount /// via rewards and slashes are not reported and thus need to be manually fixed by the /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. /// - /// Invariant: what comes out of this list will always be a nominator OR a chilled - /// nominator. + /// Invariant: what comes out of this list will always be an active nominator. type VoterList: SortedListProvider; /// Something that provides a sorted list of targets (aka electable and chilled @@ -246,8 +246,9 @@ pub mod pallet { /// [`Self::EventListeners`]. The target(s) approval stake in the list should be updated in /// any of these cases: /// 1. The stake of a validator or nominator is updated. - /// 2. The nominations of a voter are updated. - /// 3. A nominator or validator ledger is removed from the staking system. + /// 2. A nominator or validator is chilled. + /// 3. The nominations of a voter are updated. + /// 4. A nominator or validator ledger is removed from the staking system. /// /// Unlike `VoterList`, the values in this list are always kept up to date with both the /// voter and target ledger's state at all the time (even upon rewards, slashes, etc) and @@ -257,6 +258,9 @@ pub mod pallet { /// approval voting must be kept up to date. In case a chilled validator re-validates their /// intention to be a validator again, their target score is up to date with the nominations /// in the system. + /// + /// A target is removed from the list IFF its approval score is zero. This means that the + /// validator must be unbonded *AND* no staker is nominating it. type TargetList: SortedListProvider>; /// The maximum number of `unlocking` chunks a [`StakingLedger`] can @@ -1223,7 +1227,9 @@ pub mod pallet { n.and_then(|n| { // a good target nomination must be a valiator (active or idle). The // validator must not be blocked. - if Self::status(&n).is_ok() && (old.contains(&n) || !Validators::::get(&n).blocked) { + if Self::status(&n).is_ok() && + (old.contains(&n) || !Validators::::get(&n).blocked) + { Ok(n) } else { Err(Error::::BadTarget.into()) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 78f17d3abc61..932289feedd9 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -5030,7 +5030,8 @@ mod sorted_list_provider_integration { // stash 42 chills, but remains bonded. Thus it is in idle state. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); - assert_eq!(VoterBagsList::contains(&42), true); + // idle nominators are removed from the voter list. + assert_eq!(!VoterBagsList::contains(&42), true); assert!(>::get(&42).is_some()); assert_ok!(>::get(StakingAccount::Stash(42))); assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); @@ -5084,10 +5085,10 @@ mod sorted_list_provider_integration { assert_eq!(VoterBagsList::score(&42), 20); assert_eq!(TargetBagsList::score(&42), 20); - // stash 42 chills, thus it should be part of the voter and target bags list but with - // `Idle` status. + // stash 42 chills, thus it should be part of the target bags list but not in the voter + // list. And it is `Idle` status. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); - assert!(VoterBagsList::contains(&42)); + assert!(!VoterBagsList::contains(&42)); assert!(TargetBagsList::contains(&42)); assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); // the target score of 42 is 0, since it is chilled and it has no nominations. @@ -7159,6 +7160,14 @@ mod stake_tracker { BagsEvent::ScoreUpdated { who: 11, new_score: 100 } ] ); + + // since 1 was a nominator and it is chilled, it has been removed from the voter list. + assert!(!VoterBagsList::contains(&1)); + assert_eq!(Staking::status(&1), Ok(StakerStatus::Idle)); + + // killing the stash updates the staker's status. + assert_ok!(Staking::kill_stash(&1, 0)); + assert!(Staking::status(&1).is_err()); }) } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 8f89b144f7e7..175392106f00 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -17,8 +17,8 @@ //! # Stake Tracker Pallet //! -//! The stake-tracker pallet is responsible to keep track of stake and approval voting of voters and -//! targets in the staking system. +//! The stake-tracker pallet is responsible to keep track of the voter's stake and target's approval +//! voting in the staking system. //! //! ## Overview //! @@ -33,7 +33,7 @@ //! The [`OnStakingUpdate`] implementation aims at achieving the following goals: //! //! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals -//! (which include self-vote and nominations). +//! (which include self-vote and nominations' stake). //! * The [`Config::VoterList`] keeps a semi-sorted list of voters, loosely sorted by bonded stake. //! This pallet does nothing to ensure that the voter list sorting is correct. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new @@ -43,17 +43,33 @@ //! Note that from the POV of this pallet, all events will result in one or multiple updates to //! [`Config::VoterList`] and/or [`Config::TargetList`] state. If a set of staking updates require //! too much weight to process (e.g. at nominator's rewards payout or at nominator's slashes), the -//! event emitter should handle that in some way (e.g. buffering events). +//! event emitter should handle that in some way (e.g. buffering events and implementing a +//! multi-block event emitter). +//! +//! ## Staker status and list invariants +//! +//! There are a few list invariants that depend on the staker's (nominator or validator) state, as +//! exposed by the [`Config::Staking`] interface: +//! +//! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the +//! voter list's score. +//! * A [`sp_staking::StakerStatus::Validator`] is part of both voter and target list. And its +//! approvals score (nominations + self-stake) is kept up to date as the target list's score. +//! * A [`sp_staking::StakerStatus::Idle`] may have a target list's score while other stakers +//! nominate the idle validator. +//! * A staker which is not recognized by staking (i.e. not bonded) may still have an associated +//! target list score, in case there are other nominators nominating it. The list's node will +//! automatically be removed onced all the voters stop nominating the unbonded account. //! //! ## Domain-specific consideration on [`Config::VoterList`] and [`Config::TargetList`] //! //! In the context of Polkadot's staking system, both the voter and target lists will be implemented -//! by a bags-list pallet, which implements the `SortedListProvider` trait. +//! by a bags-list pallet, which implements the +//! [`frame_election_provider_support::SortedListProvider`] trait. //! //! Note that the score provider of the target's bags-list is the list itself. This, coupled with -//! the fact that the target list sorting must be always up to date results in requiring this -//! pallet to ensure at all times that the score of the targets in the `TargetList` is *always* kept -//! up to date. +//! the fact that the target list sorting must be always up to date, makes this pallet resposible +//! for ensuring that the score of the targets in the `TargetList` is *always* kept up to date. //! //! ## Event emitter ordering and staking ledger state updates //! @@ -180,7 +196,8 @@ pub mod pallet { .into() } - /// Converts an `ExtendedBalance` back to the staking interface's balance. + /// Converts an [`sp_npos_elections::ExtendedBalance`] back to the staking interface's + /// balance. pub(crate) fn to_currency( extended: ExtendedBalance, ) -> ::Balance { @@ -196,8 +213,8 @@ pub mod pallet { who: &T::AccountId, imbalance: StakeImbalance, ) { - // there may be nominators who nominate a non-existant validator. if that's the case, - // move on. This is an expected behaviour, so no defensive. + // there may be nominators who nominate a validator that is not bonded anymore. if + // that's the case, move on. This is an expected behaviour, so no defensive. if !T::TargetList::contains(who) { log!(debug, "update_score of {:?}, which is not a target", who); return @@ -212,25 +229,21 @@ pub mod pallet { }, StakeImbalance::Negative(imbalance) => { if let Ok(current_score) = T::TargetList::get_score(who) { - // if decreasing the imbalance makes the score lower than 0, the node will - // be removed from the list when calling `L::on_decrease`, which is not - // expected. Instead, we call `L::on_update` to set the new score that - // defensively saturates to 0. The node will be removed when `on_*_remove` - // is called. let balance = Self::to_vote_extended(current_score).saturating_sub(imbalance); - let _ = T::TargetList::on_update(who, Self::to_currency(balance)) - .defensive_proof( - "staker exists in the list as per the check above; qed.", - ); - // the target is removed from the list IFF score is 0 and the ledger is not // bonded in staking. if balance.is_zero() && T::Staking::status(who).is_err() { let _ = T::TargetList::on_remove(who).defensive_proof( "staker exists in the list as per the check above; qed.", ); + } else { + // update the target score without removing it. + let _ = T::TargetList::on_update(who, Self::to_currency(balance)) + .defensive_proof( + "staker exists in the list as per the check above; qed.", + ); } } else { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); @@ -241,7 +254,7 @@ pub mod pallet { #[cfg(any(test, feature = "try-runtime"))] pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - // Invariant 1: + // Invariant. // * The target score in the target list is the sum of self-stake and all stake from // nominations. // * All valid validators are part of the target list. @@ -406,7 +419,7 @@ impl OnStakingUpdate> for Pallet { /// Fired when a validator becomes idle (i.e. chilling). /// - /// While chilled, the target node remains in the grget list. + /// While chilled, the target node remains in the target list. /// /// While idling, the target node is not removed from the target list but its score is updated. fn on_validator_idle(who: &T::AccountId) { @@ -419,35 +432,32 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_validator_idle: {:?}, decreased self-stake {}", who, self_stake); } - /// Fired when someone removes their intention to validate and is completely removed from the - /// staking state. + /// Fired when someone removes their intention to validate and has been completely removed from + /// the staking state. /// /// The node is removed from the target list IFF its score is 0. fn on_validator_remove(who: &T::AccountId) { log!(debug, "on_validator_remove: {:?}", who,); // validator must be idle before removing completely. - if let Ok(status) = T::Staking::status(who) { - if status != StakerStatus::Idle { - Self::on_validator_idle(who); - } - } else { - defensive!("on_validator_remove called on a non-existing target."); - return - } + match T::Staking::status(who) { + Ok(StakerStatus::Idle) => (), // proceed + Ok(StakerStatus::Validator) => Self::on_validator_idle(who), + Ok(StakerStatus::Nominator(_)) => { + defensive!("on_validator_remove called on a nominator, unexpected."); + return + }, + Err(_) => { + defensive!("on_validator_remove called on a non-existing target."); + return + }, + }; // remove from target list IIF score is zero. - match T::TargetList::get_score(&who) { - Ok(score) => - if score.is_zero() { - let _ = T::TargetList::on_remove(&who) - .expect("target exists as per the check above; qed."); - }, - Err(_) => (), // nothing to see here. + if T::TargetList::get_score(&who).unwrap_or_default().is_zero() { + let _ = + T::TargetList::on_remove(&who).expect("target exists as per the check above; qed."); } - - // validator is a nominator too. - Self::on_nominator_remove(who, vec![]); } /// Fired when someone sets their intention to nominate. @@ -480,11 +490,17 @@ impl OnStakingUpdate> for Pallet { /// Fired when a nominator becomes idle (i.e. chilling). /// - /// While chilled, the voter node remains in the voter list. + /// From the `T::VotertList` PoV, chilling a nominator is the same as removing it. /// /// Note: it is assumed that `who`'s staking ledger and `nominations` are up to date before /// calling this method. fn on_nominator_idle(who: &T::AccountId, nominations: Vec) { + Self::on_nominator_remove(who, nominations); + } + + /// Fired when someone removes their intention to nominate and is completely removed from the + /// staking state. + fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); log!( @@ -500,21 +516,9 @@ impl OnStakingUpdate> for Pallet { for t in nominations.iter() { Self::update_target_score(&t, StakeImbalance::Negative(nominator_vote.into())) } - } - /// Fired when someone removes their intention to nominate and is completely removed from the - /// staking state. - fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { - log!(debug, "on_nominator_remove: {:?}, impacting {:?}", who, nominations); - - // nominator must be idle before removing completely. - if T::Staking::status(who).unwrap_or(StakerStatus::Idle) != StakerStatus::Idle { - Self::on_nominator_idle(who, nominations); - } - - let _ = T::VoterList::on_remove(&who).defensive_proof( - "the nominator exists in the list as per the contract with staking; qed.", - ); + let _ = T::VoterList::on_remove(&who) + .defensive_proof("the nominator exists in the list as per the contract with staking."); } /// Fired when an existing nominator updates their nominations. diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 895225e5bc39..bd822c5f6e56 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -393,9 +393,10 @@ pub(crate) fn remove_staker(who: AccountId) { >::on_validator_remove(&who); TestValidators::mutate(|v| v.remove(&who)); }, - Ok(StakerStatus::Idle) => { - >::on_validator_remove(&who); - }, + Ok(StakerStatus::Idle) => + if TargetBagsList::contains(&who) { + >::on_validator_remove(&who); + }, _ => {}, } diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 3b38eb179940..c74a0bd52964 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -349,7 +349,7 @@ fn on_nominator_remove_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the nominator exists in the list as per the contract with staking; qed.\""] +#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the nominator exists in the list as per the contract with staking.\""] fn on_nominator_remove_defensive_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(VoterBagsList::contains(&1)); @@ -393,7 +393,8 @@ mod staking_integration { chill_staker(1); assert_eq!(StakingMock::status(&1), Ok(StakerStatus::Idle)); - assert!(VoterBagsList::contains(&1)); + // a chilled nominator is removed from the voter list right away. + assert!(!VoterBagsList::contains(&1)); remove_staker(1); assert!(StakingMock::status(&1).is_err()); @@ -401,11 +402,13 @@ mod staking_integration { chill_staker(2); assert_eq!(StakingMock::status(&2), Ok(StakerStatus::Idle)); + // a chilled validator is kepts in the target list. assert!(TargetBagsList::contains(&2)); - assert!(VoterBagsList::contains(&2)); + assert!(!VoterBagsList::contains(&2)); remove_staker(2); assert!(StakingMock::status(&2).is_err()); + // a chilled validator is kepts in the target list if its score is 0. assert!(!TargetBagsList::contains(&2)); assert!(!VoterBagsList::contains(&2)); }) @@ -446,6 +449,7 @@ mod staking_integration { ExtBuilder::default().build_and_execute(|| { add_nominator(1, 100); assert!(VoterBagsList::contains(&1)); + remove_staker(1); assert!(!VoterBagsList::contains(&1)); From 341e28e9d4f0c48f2b6969b83a5b62b983ec15aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 26 Dec 2023 13:54:38 +0100 Subject: [PATCH 041/133] Update substrate/frame/staking/stake-tracker/src/lib.rs Co-authored-by: Liam Aharon --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 175392106f00..2149cf54d4b9 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -30,7 +30,7 @@ //! //! ## Goals //! -//! The [`OnStakingUpdate`] implementation aims at achieving the following goals: +//! The [`OnStakingUpdate`] implementation aims to achieve the following goals: //! //! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals //! (which include self-vote and nominations' stake). From dba853b8170dd959085dea25dbbbf029dfa4f3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 26 Dec 2023 12:58:59 +0000 Subject: [PATCH 042/133] review nits --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/stake-tracker/src/lib.rs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 9f23098b8882..4e9306c7d7ed 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1003,7 +1003,7 @@ impl Pallet { Nominators::::insert(who, nominations); T::EventListeners::on_nominator_add(who); }, - (true, true) | (false, true) => { + (_, true) => { // update nominations or un-chill nominator. let prev_nominations = Self::nominations(who).unwrap_or_default(); Nominators::::insert(who, nominations); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 2149cf54d4b9..df0da95d13a7 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -119,9 +119,9 @@ pub type AccountIdOf = ::AccountId; /// Represents a stake imbalance to be applied to a staker's score. #[derive(Copy, Clone, Debug)] pub enum StakeImbalance { - // Represents the reduction of stake by `Balance`. + /// Represents the reduction of stake by `Balance`. Negative(Balance), - // Represents the increase of stake by `Balance`. + /// Represents the increase of stake by `Balance`. Positive(Balance), } @@ -186,7 +186,7 @@ pub mod pallet { ) } - /// Fetches and converts a voter's weight into the `ExtendedBalance` type for safe + /// Fetches and converts a voter's weight into the [`ExtendedBalance`] type for safe /// computation. pub(crate) fn to_vote_extended(balance: BalanceOf) -> ExtendedBalance { ::CurrencyToVote::to_vote( @@ -500,6 +500,8 @@ impl OnStakingUpdate> for Pallet { /// Fired when someone removes their intention to nominate and is completely removed from the /// staking state. + /// + /// Note: this may update the score of up to [`T::MaxNominations`] validators. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); @@ -511,8 +513,7 @@ impl OnStakingUpdate> for Pallet { nominations, ); - // updates the nominated target's score. Note: this may update the score of up to - // `T::MaxNominations` validators. + // updates the nominated target's score. for t in nominations.iter() { Self::update_target_score(&t, StakeImbalance::Negative(nominator_vote.into())) } From b316f6fe616e42848716672b899ca1c54b8eeb16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 8 Jan 2024 11:42:15 +0100 Subject: [PATCH 043/133] Refactor `OnStakingUpdate` interface to be safer to use. (#2877) Co-authored-by: command-bot <> --- substrate/frame/staking/src/ledger.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 13 ++++++-- .../frame/staking/stake-tracker/src/lib.rs | 33 +++++++++++-------- .../frame/staking/stake-tracker/src/mock.rs | 29 +++++++++++----- .../frame/staking/stake-tracker/src/tests.rs | 24 +++++++++----- substrate/primitives/staking/src/lib.rs | 20 ++++++++--- 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index a42fb94e97cf..4746eca42cec 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -187,7 +187,7 @@ impl StakingLedger { // fire `on_stake_update` if there was a stake update. let new_stake: Stake<_> = self.clone().into(); if new_stake != prev_stake.unwrap_or_default() { - T::EventListeners::on_stake_update(&self.stash, prev_stake); + T::EventListeners::on_stake_update(&self.stash, prev_stake, new_stake); } Ok(()) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 4e9306c7d7ed..073bfce7be40 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -997,17 +997,19 @@ impl Pallet { /// NOTE: you must ALWAYS use this function to add nominator or update their targets. Any /// access to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { + let nomination_accounts = nominations.targets.to_vec(); + match (Nominators::::contains_key(who), T::VoterList::contains(who)) { (false, false) => { // new nomination Nominators::::insert(who, nominations); - T::EventListeners::on_nominator_add(who); + T::EventListeners::on_nominator_add(who, nomination_accounts); }, (_, true) => { // update nominations or un-chill nominator. let prev_nominations = Self::nominations(who).unwrap_or_default(); Nominators::::insert(who, nominations); - T::EventListeners::on_nominator_update(who, prev_nominations); + T::EventListeners::on_nominator_update(who, prev_nominations, nomination_accounts); }, (true, false) => { defensive!("unexpected state."); @@ -1091,7 +1093,12 @@ impl Pallet { pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { Validators::::insert(who, prefs); - T::EventListeners::on_validator_add(who); + + let self_stake = Self::stake(who); + T::EventListeners::on_validator_add( + who, + Some(self_stake.defensive_unwrap_or_default().into()), + ); } else { Validators::::insert(who, prefs); } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index df0da95d13a7..6926c61b896d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -331,7 +331,11 @@ impl OnStakingUpdate> for Pallet { /// /// Note: it is assumed that `who`'s staking ledger state is updated *before* this method is /// called. - fn on_stake_update(who: &T::AccountId, prev_stake: Option>>) { + fn on_stake_update( + who: &T::AccountId, + prev_stake: Option>>, + stake: Stake>, + ) { // closure to calculate the stake imbalance of a staker. let stake_imbalance_of = |prev_stake: Option>>, voter_weight: ExtendedBalance| { @@ -357,7 +361,7 @@ impl OnStakingUpdate> for Pallet { if let Ok(_) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( "staker should exist when calling on_stake_update and have a valid status", ) { - let voter_weight = Self::weight_of(Self::active_vote_of(who)); + let voter_weight = Self::weight_of(stake.active); match T::Staking::status(who).expect("status checked above; qed.") { StakerStatus::Nominator(nominations) => { @@ -404,17 +408,17 @@ impl OnStakingUpdate> for Pallet { // /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. - fn on_validator_add(who: &T::AccountId) { + fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { // target may exist in the list in case of re-enabling a chilled validator; if !T::TargetList::contains(who) { - let _ = T::TargetList::on_insert(who.clone(), Self::active_vote_of(who)) + let _ = T::TargetList::on_insert(who.clone(), self_stake.unwrap_or_default().active) .expect("staker does not exist in the list as per check above; qed."); } log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); // a validator is also a nominator. - Self::on_nominator_add(who) + Self::on_nominator_add(who, vec![]) } /// Fired when a validator becomes idle (i.e. chilling). @@ -464,7 +468,7 @@ impl OnStakingUpdate> for Pallet { /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is /// called. - fn on_nominator_add(who: &T::AccountId) { + fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); // voter may exist in the list in case of re-enabling a chilled nominator; @@ -478,7 +482,7 @@ impl OnStakingUpdate> for Pallet { // If who is a nominator, update the vote weight of the nominations if they exist. Note: // this will update the score of up to `T::MaxNominations` validators. match T::Staking::status(who).defensive() { - Ok(StakerStatus::Nominator(nominations)) => + Ok(StakerStatus::Nominator(_)) => for t in nominations { Self::update_target_score(&t, StakeImbalance::Positive(nominator_vote.into())) }, @@ -530,27 +534,28 @@ impl OnStakingUpdate> for Pallet { /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. - fn on_nominator_update(who: &T::AccountId, prev_nominations: Vec) { + fn on_nominator_update( + who: &T::AccountId, + prev_nominations: Vec, + nominations: Vec>, + ) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); - let curr_nominations = - ::nominations(&who).unwrap_or_default(); - log!( debug, "on_nominator_update: {:?}, with {:?}. previous nominations: {:?} -> new nominations {:?}", - who, nominator_vote, prev_nominations, curr_nominations, + who, nominator_vote, prev_nominations, nominations, ); // new nominations - for target in curr_nominations.iter() { + for target in nominations.iter() { if !prev_nominations.contains(target) { Self::update_target_score(&target, StakeImbalance::Positive(nominator_vote.into())); } } // removed nominations for target in prev_nominations.iter() { - if !curr_nominations.contains(target) { + if !nominations.contains(target) { Self::update_target_score(&target, StakeImbalance::Negative(nominator_vote.into())); } } diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index bd822c5f6e56..aabd043925ce 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -282,7 +282,7 @@ pub(crate) fn add_nominator(who: AccountId, stake: Balance) { }); // add new nominator (called at `fn bond` in staking) - >::on_nominator_add(&who); + >::on_nominator_add(&who, vec![]); } pub(crate) fn stake_of(who: AccountId) -> Option> { @@ -305,10 +305,14 @@ pub(crate) fn add_nominator_with_nominations( // add nominations (called at `fn nominate` in staking) TestNominators::mutate(|n| { - n.insert(who, (Stake:: { active: stake, total: stake }, nominations)); + n.insert(who, (Stake:: { active: stake, total: stake }, nominations.clone())); }); - >::on_nominator_update(&who, vec![]); + >::on_nominator_update( + &who, + vec![], + nominations, + ); } pub(crate) fn update_nominations_of(who: AccountId, new_nominations: Nominations) { @@ -317,29 +321,32 @@ pub(crate) fn update_nominations_of(who: AccountId, new_nominations: Nominations let (current_stake, prev_nominations) = current_nom.get(&who).unwrap(); TestNominators::mutate(|n| { - n.insert(who, (*current_stake, new_nominations)); + n.insert(who, (*current_stake, new_nominations.clone())); }); >::on_nominator_update( &who, prev_nominations.clone(), + new_nominations, ); } -pub(crate) fn add_validator(who: AccountId, stake: Balance) { +pub(crate) fn add_validator(who: AccountId, self_stake: Balance) { Bonded::mutate(|b| { b.push(who); }); + let stake = Stake { active: self_stake, total: self_stake }; + TestValidators::mutate(|v| { - v.insert(who, Stake:: { active: stake, total: stake }); + v.insert(who, stake); }); // validator is a nominator too. TestNominators::mutate(|v| { - v.insert(who, (Stake:: { active: stake, total: stake }, vec![])); + v.insert(who, (stake, vec![])); }); - >::on_validator_add(&who); + >::on_validator_add(&who, Some(stake)); } pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option>) { @@ -361,7 +368,11 @@ pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option panic!("not a staker"), } - >::on_stake_update(&who, prev_stake); + >::on_stake_update( + &who, + prev_stake, + Stake { total: new, active: new }, + ); } pub(crate) fn chill_staker(who: AccountId) { diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index c74a0bd52964..1608140677a3 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -107,7 +107,7 @@ fn on_stake_update_works() { n.insert(1, (new_stake, nominations.clone())); }); - >::on_stake_update(&1, stake_before); + >::on_stake_update(&1, stake_before, new_stake); assert_eq!(VoterBagsList::get_score(&1).unwrap(), new_stake.active); @@ -139,7 +139,7 @@ fn on_stake_update_works() { let stake_imbalance = stake_before.unwrap().active - new_stake.total; - >::on_stake_update(&10, stake_before); + >::on_stake_update(&10, stake_before, new_stake); assert_eq!(VoterBagsList::get_score(&10).unwrap(), new_stake.active); assert_eq!(StakingMock::stake(&10), Ok(new_stake)); @@ -199,7 +199,11 @@ fn on_stake_update_sorting_works() { // noop, nothing changes. let initial_stake = stake_of(11); - >::on_stake_update(&11, initial_stake); + >::on_stake_update( + &11, + initial_stake, + initial_stake.unwrap(), + ); assert_eq!(voter_scores_before, get_scores::()); // now let's change the self-vote of 11 and call `on_stake_update` again. @@ -209,7 +213,7 @@ fn on_stake_update_sorting_works() { n.insert(11, (new_stake, nominations.clone())); }); - >::on_stake_update(&11, initial_stake); + >::on_stake_update(&11, initial_stake, new_stake); // although the voter score of 11 is 1, the voter list sorting has not been updated // automatically. @@ -239,7 +243,7 @@ fn on_stake_update_defensive_not_in_list_works() { // removes 1 from nominator's list manually, while keeping it as staker. assert_ok!(VoterBagsList::on_remove(&1)); - >::on_stake_update(&1, None); + >::on_stake_update(&1, None, Stake::default()); }) } @@ -249,7 +253,7 @@ fn on_stake_update_defensive_not_staker_works() { ExtBuilder::default().build_and_execute(|| { assert!(!VoterBagsList::contains(&1)); - >::on_stake_update(&1, None); + >::on_stake_update(&1, None, Stake::default()); }) } @@ -295,7 +299,8 @@ fn on_nominator_add_already_exists_works() { let target_list_before = TargetBagsList::iter().collect::>(); // noop. - >::on_nominator_add(&1); + let nominations = ::nominations(&1).unwrap(); + >::on_nominator_add(&1, nominations); assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::count(), 4); assert_eq!(>::score(&1), 100); @@ -316,7 +321,10 @@ fn on_validator_add_already_exists_works() { let target_list_before = TargetBagsList::iter().collect::>(); // noop - >::on_validator_add(&10); + >::on_validator_add( + &10, + Some(Stake { total: 300, active: 300 }), + ); assert!(TargetBagsList::contains(&10)); assert_eq!(TargetBagsList::count(), 2); assert_eq!(>::score(&10), 300); diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 1496bb116d80..a9643e24e269 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -100,19 +100,29 @@ pub trait OnStakingUpdate { /// /// This is effectively any changes to the bond amount, such as bonding more funds, and /// unbonding. - fn on_stake_update(_who: &AccountId, _prev_stake: Option>) {} + fn on_stake_update( + _who: &AccountId, + _prev_stake: Option>, + _stake: Stake, + ) { + } /// Fired when someone sets their intention to nominate. /// /// This should never be fired for existing nominators. - fn on_nominator_add(_who: &AccountId) {} + fn on_nominator_add(_who: &AccountId, _nominations: Vec) {} /// Fired when an existing nominator updates their nominations. /// /// Note that this is not fired when a nominator changes their stake. For that, /// `on_stake_update` should be used, followed by querying whether `who` was a validator or a /// nominator. - fn on_nominator_update(_who: &AccountId, _prev_nominations: Vec) {} + fn on_nominator_update( + _who: &AccountId, + _prev_nominations: Vec, + _nominations: Vec, + ) { + } /// Fired when an existng nominator becomes idle. /// @@ -128,12 +138,12 @@ pub trait OnStakingUpdate { /// Fired when someone sets their intention to validate. /// /// Note validator preference changes are not communicated, but could be added if needed. - fn on_validator_add(_who: &AccountId) {} + fn on_validator_add(_who: &AccountId, _self_stake: Option>) {} /// Fired when an existing validator updates their preferences. /// /// Note validator preference changes are not communicated, but could be added if needed. - fn on_validator_update(_who: &AccountId) {} + fn on_validator_update(_who: &AccountId, _self_stake: Option>) {} /// Fired when an existing validator becomes idle. /// From 261456ecb871379fbfdf7f5d05b043b61bd7d6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 8 Jan 2024 14:16:09 +0100 Subject: [PATCH 044/133] Fixes fast-unstake test setup --- substrate/frame/fast-unstake/src/mock.rs | 5 ++++- substrate/frame/fast-unstake/src/tests.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 09a08f222b6b..86bbd4c44359 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -270,6 +270,7 @@ impl ExtBuilder { .map(|(stash, _, balance)| (stash, balance * 2)) .chain(validators_range.clone().map(|x| (x, 7 + 100))) .chain(nominators_range.clone().map(|x| (x, 7 + 100))) + .chain(vec![(42, 100_000)].into_iter()) .collect::>(), } .assimilate_storage(&mut storage); @@ -279,8 +280,10 @@ impl ExtBuilder { .unexposed .into_iter() .map(|(x, y, z)| (x, y, z, pallet_staking::StakerStatus::Nominator(vec![42]))) - .chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator))) .chain(nominators_range.map(|x| (x, x, 100, StakerStatus::Nominator(vec![x])))) + .chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator))) + .chain(vec![(42, 42, 107, pallet_staking::StakerStatus::Validator)].into_iter()) + .rev() // validators need to set intention to validate before being nominated. .collect::>(), ..Default::default() } diff --git a/substrate/frame/fast-unstake/src/tests.rs b/substrate/frame/fast-unstake/src/tests.rs index b19fe3b8c463..4237c0cbade6 100644 --- a/substrate/frame/fast-unstake/src/tests.rs +++ b/substrate/frame/fast-unstake/src/tests.rs @@ -816,19 +816,19 @@ mod on_idle { CurrentEra::::put(BondingDuration::get()); // create a new validator that 100% not exposed. - Balances::make_free_balance_be(&42, 100 + Deposit::get()); - assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 10, RewardDestination::Staked)); - assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); + Balances::make_free_balance_be(&43, 100 + Deposit::get()); + assert_ok!(Staking::bond(RuntimeOrigin::signed(43), 10, RewardDestination::Staked)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(43), Default::default())); // let them register: - assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(42))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(43))); // 2 block's enough to unstake them. next_block(true); assert_eq!( Head::::get(), Some(UnstakeRequest { - stashes: bounded_vec![(42, Deposit::get())], + stashes: bounded_vec![(43, Deposit::get())], checked: bounded_vec![3, 2, 1, 0] }) ); @@ -839,7 +839,7 @@ mod on_idle { fast_unstake_events_since_last_call(), vec![ Event::BatchChecked { eras: vec![3, 2, 1, 0] }, - Event::Unstaked { stash: 42, result: Ok(()) }, + Event::Unstaked { stash: 43, result: Ok(()) }, Event::BatchFinished { size: 1 } ] ); From bf1e043d41e7d0212b01f66b13227e69d46cd5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 21 Jan 2024 23:53:16 +0100 Subject: [PATCH 045/133] simplifies do_add_validator --- substrate/frame/staking/src/pallet/impls.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 8d9947bce993..2b6c23ce913f 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1092,16 +1092,13 @@ impl Pallet { /// wrong. pub fn do_add_validator(who: &T::AccountId, prefs: ValidatorPrefs) { if !Validators::::contains_key(who) { - Validators::::insert(who, prefs); - let self_stake = Self::stake(who); T::EventListeners::on_validator_add( who, Some(self_stake.defensive_unwrap_or_default().into()), ); - } else { - Validators::::insert(who, prefs); - } + }; + Validators::::insert(who, prefs); debug_assert_eq!( Nominators::::count() + Validators::::count(), From c0497b2df9e98686884eb29098019521e2659a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 22 Jan 2024 00:05:09 +0100 Subject: [PATCH 046/133] Adds prdoc --- prdoc/pr_1933.prdoc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 prdoc/pr_1933.prdoc diff --git a/prdoc/pr_1933.prdoc b/prdoc/pr_1933.prdoc new file mode 100644 index 000000000000..3dbfee9a6a40 --- /dev/null +++ b/prdoc/pr_1933.prdoc @@ -0,0 +1,21 @@ +title: Adds `stake-tracker` pallet and integrates it with the staking pallet + +doc: + - audience: Runtime Dev + description: | + The (newly added) `stake-tracker` pallet implements the `OnStakingUpdate` trait to listen to + staking events and multiplexes those events to one or multiple types (e.g. pallets). The + `stake-tracker` pallet is used as a degree of indirection to maintain an *always-sorted* + target and a semi-sorted voter list for staking (implemented by the bags list pallet). + Other notable changes in this PR are: + * Changes to assumptions of chilled and removed stakers: the target list keeps track + of validators that have been chilled/removed from the system, insofar as there are + nominators nominating them; + * Changes to staking `Call::nominate`: New nominations can only be performed on active or + chilling validators; + * Changes to `OnStakingUpdate` trait: new methods for signaling chilling of stakers + (`on_idle`) and refactors trait API for safety of use. + +crates: + - name: pallet-staking + - name: pallet-stake-tracker From 27129fb623f87c542af00433ab3abf2ec9cfa7f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 22 Jan 2024 09:06:09 +0100 Subject: [PATCH 047/133] fixes clippy --- .../frame/staking/stake-tracker/src/lib.rs | 29 ++++++++++--------- .../frame/staking/stake-tracker/src/mock.rs | 10 ++----- .../frame/staking/stake-tracker/src/tests.rs | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 6926c61b896d..7fbc7d6e2e3d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -105,7 +105,7 @@ pub(crate) const LOG_TARGET: &str = "runtime::stake-tracker"; macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { log::$level!( - target: crate::LOG_TARGET, + target: $crate::LOG_TARGET, concat!("[{:?}] 📚 ", $patter), >::block_number() $(, $values)* ) }; @@ -358,9 +358,13 @@ impl OnStakingUpdate> for Pallet { } }; - if let Ok(_) = T::Staking::status(who).and(T::Staking::stake(who)).defensive_proof( - "staker should exist when calling on_stake_update and have a valid status", - ) { + if T::Staking::status(who) + .and(T::Staking::stake(who)) + .defensive_proof( + "staker should exist when calling on_stake_update and have a valid status", + ) + .is_ok() + { let voter_weight = Self::weight_of(stake.active); match T::Staking::status(who).expect("status checked above; qed.") { @@ -389,7 +393,7 @@ impl OnStakingUpdate> for Pallet { StakerStatus::Validator => { // validator is both a target and a voter. let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); - Self::update_target_score(&who, stake_imbalance); + Self::update_target_score(who, stake_imbalance); let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( "the staker should exit in VoterList, as per the \ @@ -411,7 +415,7 @@ impl OnStakingUpdate> for Pallet { fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { // target may exist in the list in case of re-enabling a chilled validator; if !T::TargetList::contains(who) { - let _ = T::TargetList::on_insert(who.clone(), self_stake.unwrap_or_default().active) + T::TargetList::on_insert(who.clone(), self_stake.unwrap_or_default().active) .expect("staker does not exist in the list as per check above; qed."); } @@ -458,9 +462,8 @@ impl OnStakingUpdate> for Pallet { }; // remove from target list IIF score is zero. - if T::TargetList::get_score(&who).unwrap_or_default().is_zero() { - let _ = - T::TargetList::on_remove(&who).expect("target exists as per the check above; qed."); + if T::TargetList::get_score(who).unwrap_or_default().is_zero() { + T::TargetList::on_remove(who).expect("target exists as per the check above; qed."); } } @@ -519,10 +522,10 @@ impl OnStakingUpdate> for Pallet { // updates the nominated target's score. for t in nominations.iter() { - Self::update_target_score(&t, StakeImbalance::Negative(nominator_vote.into())) + Self::update_target_score(t, StakeImbalance::Negative(nominator_vote.into())) } - let _ = T::VoterList::on_remove(&who) + let _ = T::VoterList::on_remove(who) .defensive_proof("the nominator exists in the list as per the contract with staking."); } @@ -550,13 +553,13 @@ impl OnStakingUpdate> for Pallet { // new nominations for target in nominations.iter() { if !prev_nominations.contains(target) { - Self::update_target_score(&target, StakeImbalance::Positive(nominator_vote.into())); + Self::update_target_score(target, StakeImbalance::Positive(nominator_vote.into())); } } // removed nominations for target in prev_nominations.iter() { if !nominations.contains(target) { - Self::update_target_score(&target, StakeImbalance::Negative(nominator_vote.into())); + Self::update_target_score(target, StakeImbalance::Negative(nominator_vote.into())); } } } diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index aabd043925ce..d4c57da55940 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -147,7 +147,7 @@ impl StakingInterface for StakingMock { ) { (true, true, true) => Ok(StakerStatus::Validator), (false, true, true) => - Ok(StakerStatus::Nominator(nominators.get(&who).expect("exists").1.clone())), + Ok(StakerStatus::Nominator(nominators.get(who).expect("exists").1.clone())), (false, false, true) => Ok(StakerStatus::Idle), (false, false, false) => Err("not a staker".into()), _ => Err("mock: inconsistent data".into()), @@ -156,11 +156,7 @@ impl StakingInterface for StakingMock { fn nominations(who: &Self::AccountId) -> Option> { let n = TestNominators::get(); - if let Some(nominator) = n.get(&who) { - Some(nominator.1.clone()) - } else { - None - } + n.get(who).map(|nominator| nominator.1.clone()) } fn minimum_nominator_bond() -> Self::Balance { @@ -456,7 +452,7 @@ impl ExtBuilder { sp_io::TestExternalities::from(storage) } - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + pub fn build_and_execute(self, test: impl FnOnce()) { sp_tracing::try_init_simple(); let mut ext = self.build(); diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 1608140677a3..e7e829967c71 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -127,7 +127,7 @@ fn on_stake_update_works() { let target_score_before = TargetBagsList::get_score(&10).unwrap(); // validator has no nominations, as expected. - assert!(::nominations(&10).unwrap().len() == 0); + assert!(::nominations(&10).unwrap().is_empty()); // manually change the self stake. let new_stake = Stake { total: 10, active: 10 }; From f0098d6fb1f2d65557df1bee5db4c9be06679566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 23 Jan 2024 22:55:25 +0100 Subject: [PATCH 048/133] Fixes clippy --- substrate/frame/staking/src/tests.rs | 1 + substrate/frame/staking/stake-tracker/Cargo.toml | 9 +++++++++ substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 4bf63a8881f4..6181ed75ce8d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7285,6 +7285,7 @@ mod stake_tracker { 150, RewardDestination::Account(12), )); + assert_ok!(Staking::validate(RuntimeOrigin::signed(12), Default::default())); // 12 is a validator and has 150 self-vote. diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index a47ce200b9a6..cff5cb067a94 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -47,6 +47,9 @@ std = [ "scale-info/std", "sp-runtime/std", "sp-std/std", + "frame-election-provider-support/std", + "pallet-balances/std", + "pallet-bags-list/std", ] runtime-benchmarks = [ @@ -54,10 +57,16 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "sp-runtime/try-runtime", + "frame-election-provider-support/try-runtime", + "pallet-balances/try-runtime", + "pallet-bags-list/try-runtime", ] diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 7fbc7d6e2e3d..242b40e9569d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -166,7 +166,7 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), TryRuntimeError> { + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { Self::do_try_state() } } From f89a0460bb6371fed52c61f75f6faa937ee9b877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 1 Feb 2024 10:09:59 +0100 Subject: [PATCH 049/133] after master merge fixes --- substrate/frame/staking/src/mock.rs | 5 +++- substrate/frame/staking/src/tests.rs | 6 ++-- .../frame/staking/stake-tracker/Cargo.toml | 30 +++++++++---------- .../frame/staking/stake-tracker/src/mock.rs | 1 - 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index b00b786a0320..e0873ad5a94c 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -615,7 +615,10 @@ impl ExtBuilder { ext.execute_with(|| { if !SkipTryStateCheck::get() { let _ = Staking::do_try_state(System::block_number()) - .map_err(|err| println!(" 🕵️‍♂️ try_state failure: {:?}", err)) + .map_err(|err| { + println!(" 🕵️‍♂️ try_state failure: {:?}", err); + err + }) .unwrap(); } }); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ab1b2bc10af0..9662cf9ffe17 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -5018,7 +5018,7 @@ mod sorted_list_provider_integration { assert_eq!(TargetBagsList::score(&21), 1500); // bond and nominate (11, 21) with stash 42. - assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, Default::default())); + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, RewardDestination::Staked)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(42), vec![11, 21])); // stash 42 is now a voter with a score. @@ -5083,7 +5083,7 @@ mod sorted_list_provider_integration { assert!(!TargetBagsList::contains(&42)); // bond and set intention to validate. stash 42 is both target and voter. - assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, Default::default())); + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 25, RewardDestination::Staked)); assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); assert_eq!(Staking::status(&42), Ok(StakerStatus::Validator)); @@ -7397,7 +7397,7 @@ mod stake_tracker { // * Call::unbond() ExtBuilder::default().build_and_execute(|| { // bond and nominate with stash 61. - assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, Default::default())); + assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, RewardDestination::Staked)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31])); assert_ok!(stake_tracker_sanity_tests()); diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index cff5cb067a94..3b86a29dc308 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -15,26 +15,26 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../../primitives/runtime", features = ["serde"] } -sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking", features = ["serde"] } -sp-std = { version = "8.0.0", default-features = false, path = "../../../primitives/std" } +sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } +sp-staking = { default-features = false, path = "../../../primitives/staking", features = ["serde"] } +sp-std = { default-features = false, path = "../../../primitives/std" } -sp-npos-elections = { version = "4.0.0-dev", path = "../../../primitives/npos-elections" } -frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } -frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +sp-npos-elections = { path = "../../../primitives/npos-elections" } +frame-election-provider-support = { default-features = false, path = "../../election-provider-support" } +frame-benchmarking = { default-features = false, optional = true, path = "../../benchmarking" } +frame-support = { default-features = false, path = "../../support" } +frame-system = { default-features = false, path = "../../system" } log = { version = "0.4.17", default-features = false } [dev-dependencies] -sp-std = { version = "8.0.0", default-features = false, path = "../../../primitives/std" } -sp-core = { version = "21.0.0", path = "../../../primitives/core" } -sp-io = { version = "23.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "24.0.0", default-features = false, path = "../../../primitives/runtime", features = ["serde"] } -sp-tracing = { version = "10.0.0", path = "../../../primitives/tracing" } -pallet-bags-list = { version = "4.0.0-dev", path = "../../bags-list" } -pallet-balances = { version = "4.0.0-dev", path = "../../balances" } +sp-std = { default-features = false, path = "../../../primitives/std" } +sp-core = { path = "../../../primitives/core" } +sp-io = { default-features = false, path = "../../../primitives/io" } +sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } +sp-tracing = { path = "../../../primitives/tracing" } +pallet-bags-list = { path = "../../bags-list" } +pallet-balances = { path = "../../balances" } [features] default = ["std"] diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index d4c57da55940..7e41fcf044fc 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -64,7 +64,6 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type FreezeIdentifier = (); - type MaxHolds = (); type RuntimeHoldReason = (); type RuntimeFreezeReason = (); type MaxFreezes = (); From 18f11b7ed7ea9e1cae121002659cf62e55a200ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 1 Feb 2024 13:21:59 +0100 Subject: [PATCH 050/133] simplify on_remove_* logic --- Cargo.lock | 4 +- substrate/frame/staking/src/pallet/impls.rs | 62 +++++++++------------ 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edcf892ae186..9706ba852b30 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10751,8 +10751,8 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std 8.0.0", - "sp-tracing 10.0.0", + "sp-std 14.0.0", + "sp-tracing 16.0.0", ] [[package]] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 90ab5329da08..cb3f885e857b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1046,29 +1046,19 @@ impl Pallet { /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access /// to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { - let nominations = Self::nominations(who).unwrap_or_default(); - - let outcome = match (Nominators::::contains_key(who), T::VoterList::contains(who)) { - // ensure that the voter is idle before removing it. - (true, true) => { - // first chill nominator. - Self::do_chill_nominator(who); - T::EventListeners::on_nominator_remove(who, nominations); - true - }, - // nominator is idle already, remove it. - (false, true) => { + let outcome = match Self::status(who) { + Ok(StakerStatus::Nominator(nominations)) => { + let outcome = Self::do_chill_nominator(who); T::EventListeners::on_nominator_remove(who, nominations); - true + outcome }, - (true, false) => { - defensive!( - "inconsistent state: staker is in nominators list but not in voter list" - ); - false + Ok(StakerStatus::Validator) => { + let outcome = Self::do_chill_nominator(who); + T::EventListeners::on_nominator_remove(who, vec![]); + outcome }, - // nominator has been already removed. - (false, false) => false, + // not an active nomination, do nothing. + _ => false, }; debug_assert_eq!( @@ -1127,27 +1117,28 @@ impl Pallet { /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { - let outcome = match (Validators::::contains_key(who), T::TargetList::contains(who)) { - // ensure the validator is idle before removing it. - (true, true) => { - // first chill validator. - Self::do_chill_validator(who); + let outcome = match Self::status(who) { + Ok(StakerStatus::Validator) => { + // make sure the validator is chilled before removing it. + let outcome = Self::do_chill_validator(who); T::EventListeners::on_validator_remove(who); - true + outcome + }, + Ok(StakerStatus::Nominator(_)) => { + defensive!("called do_validator_remove on a nominator stash."); + false }, - // validator is idle, remove it. - (false, true) => { + Ok(StakerStatus::Idle) | Err(_) if T::TargetList::contains(who) => { + // try to remove "dangling" target. A dangling target does not have a bonded stash + // but is still part of the target list because a previously removed stash still has + // nominations from active nominators. T::EventListeners::on_validator_remove(who); - true + false }, - (true, false) => { - defensive!( - "inconsistent state: staker is in validators list but not in targets list" - ); + _ => { + // validator has been already removed. false }, - // validator has been already removed. - (false, false) => false, }; debug_assert_eq!( @@ -1857,6 +1848,7 @@ impl StakingInterface for Pallet { validator == *who || exposure_page.others.iter().any(|i| i.who == *who) }) } + fn status( who: &Self::AccountId, ) -> Result, DispatchError> { From 0e9537800c68aaf97415a0c0898fb83b9383a22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 16:08:23 +0100 Subject: [PATCH 051/133] Adds stake-tracker to benchmarking runtime --- Cargo.lock | 1 + substrate/bin/node/runtime/Cargo.toml | 3 + substrate/bin/node/runtime/src/lib.rs | 31 ++- .../{voter_bags.rs => voter_target_bags.rs} | 209 +++++++++++++++++- 4 files changed, 236 insertions(+), 8 deletions(-) rename substrate/bin/node/runtime/src/{voter_bags.rs => voter_target_bags.rs} (53%) diff --git a/Cargo.lock b/Cargo.lock index 9706ba852b30..dc72fd53c047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7027,6 +7027,7 @@ dependencies = [ "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-runtime-api", diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 4bb5fed2b09a..8b5d6f39f848 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -122,6 +122,7 @@ pallet-session-benchmarking = { path = "../../../frame/session/benchmarking", de pallet-staking = { path = "../../../frame/staking", default-features = false } pallet-staking-reward-curve = { path = "../../../frame/staking/reward-curve", default-features = false } pallet-staking-runtime-api = { path = "../../../frame/staking/runtime-api", default-features = false } +pallet-stake-tracker = { path = "../../../frame/staking/stake-tracker", default-features = false } pallet-state-trie-migration = { path = "../../../frame/state-trie-migration", default-features = false } pallet-statement = { path = "../../../frame/statement", default-features = false } pallet-scheduler = { path = "../../../frame/scheduler", default-features = false } @@ -225,6 +226,7 @@ std = [ "pallet-society/std", "pallet-staking-runtime-api/std", "pallet-staking/std", + "pallet-stake-tracker/std", "pallet-state-trie-migration/std", "pallet-statement/std", "pallet-sudo/std", @@ -400,6 +402,7 @@ try-runtime = [ "pallet-skip-feeless-payment/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-statement/try-runtime", "pallet-sudo/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 02d084c6c62b..4cb73744143d 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -123,7 +123,7 @@ use constants::{currency::*, time::*}; use sp_runtime::generic::Era; /// Generated voter bag information. -mod voter_bags; +mod voter_target_bags; /// Runtime API definition for assets. pub mod assets_api; @@ -683,17 +683,23 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; + type TargetList = TargetList; type NominationsQuota = pallet_staking::FixedNominationsQuota; - // This a placeholder, to be introduced in the next PR as an instance of bags-list - type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type HistoryDepth = HistoryDepth; - type EventListeners = NominationPools; + type EventListeners = (StakeTracker, NominationPools); type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; } +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterList; + type TargetList = TargetList; +} + impl pallet_fast_unstake::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ControlOrigin = frame_system::EnsureRoot; @@ -858,7 +864,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { } parameter_types! { - pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS; + pub const VoterBagThresholds: &'static [u64] = &voter_target_bags::VOTER_THRESHOLDS; + pub const TargetBagThresholds: &'static [Balance] = &voter_target_bags::TARGET_THRESHOLDS; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -867,11 +874,20 @@ impl pallet_bags_list::Config for Runtime { /// The voter bags-list is loosely kept up to date, and the real source of truth for the score /// of each node is the staking pallet. type ScoreProvider = Staking; - type BagThresholds = BagThresholds; + type BagThresholds = VoterBagThresholds; type Score = VoteWeight; type WeightInfo = pallet_bags_list::weights::SubstrateWeight; } +type TargetBagsListInstance = pallet_bags_list::Instance2; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ScoreProvider = pallet_bags_list::Pallet; + type BagThresholds = TargetBagThresholds; + type Score = Balance; + type WeightInfo = pallet_bags_list::weights::SubstrateWeight; +} + parameter_types! { pub const PostUnbondPoolsWindow: u32 = 4; pub const NominationPoolsPalletId: PalletId = PalletId(*b"py/nopls"); @@ -2102,6 +2118,7 @@ construct_runtime!( AssetConversionTxPayment: pallet_asset_conversion_tx_payment, ElectionProviderMultiPhase: pallet_election_provider_multi_phase, Staking: pallet_staking, + StakeTracker: pallet_stake_tracker, Session: pallet_session, Democracy: pallet_democracy, Council: pallet_collective::, @@ -2145,6 +2162,7 @@ construct_runtime!( CoreFellowship: pallet_core_fellowship, TransactionStorage: pallet_transaction_storage, VoterList: pallet_bags_list::, + TargetList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, @@ -2270,6 +2288,7 @@ mod benches { [pallet_assets, Assets] [pallet_babe, Babe] [pallet_bags_list, VoterList] + [pallet_bags_list, TargetList] [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_broker, Broker] diff --git a/substrate/bin/node/runtime/src/voter_bags.rs b/substrate/bin/node/runtime/src/voter_target_bags.rs similarity index 53% rename from substrate/bin/node/runtime/src/voter_bags.rs rename to substrate/bin/node/runtime/src/voter_target_bags.rs index bf18097ddf53..151004377410 100644 --- a/substrate/bin/node/runtime/src/voter_bags.rs +++ b/substrate/bin/node/runtime/src/voter_target_bags.rs @@ -33,8 +33,213 @@ pub const EXISTENTIAL_WEIGHT: u64 = 100_000_000_000_000; #[allow(unused)] pub const CONSTANT_RATIO: f64 = 1.0628253590743408; -/// Upper thresholds delimiting the bag list. -pub const THRESHOLDS: [u64; 200] = [ +/// Upper thresholds delimiting the voters bag list. +pub const VOTER_THRESHOLDS: [u64; 200] = [ + 100_000_000_000_000, + 106_282_535_907_434, + 112_959_774_389_150, + 120_056_512_776_105, + 127_599_106_300_477, + 135_615_565_971_369, + 144_135_662_599_590, + 153_191_037_357_827, + 162_815_319_286_803, + 173_044_250_183_800, + 183_915_817_337_347, + 195_470_394_601_017, + 207_750_892_330_229, + 220_802_916_738_890, + 234_674_939_267_673, + 249_418_476_592_914, + 265_088_281_944_639, + 281_742_548_444_211, + 299_443_125_216_738, + 318_255_747_080_822, + 338_250_278_668_647, + 359_500_973_883_001, + 382_086_751_654_776, + 406_091_489_025_036, + 431_604_332_640_068, + 458_720_029_816_222, + 487_539_280_404_019, + 518_169_110_758_247, + 550_723_271_202_866, + 585_322_658_466_782, + 622_095_764_659_305, + 661_179_154_452_653, + 702_717_972_243_610, + 746_866_481_177_808, + 793_788_636_038_393, + 843_658_692_126_636, + 896_661_852_395_681, + 952_994_955_240_703, + 1_012_867_205_499_736, + 1_076_500_951_379_881, + 1_144_132_510_194_192, + 1_216_013_045_975_769, + 1_292_409_502_228_280, + 1_373_605_593_276_862, + 1_459_902_857_901_004, + 1_551_621_779_162_291, + 1_649_102_974_585_730, + 1_752_708_461_114_642, + 1_862_822_999_536_805, + 1_979_855_523_374_646, + 2_104_240_657_545_975, + 2_236_440_332_435_128, + 2_376_945_499_368_703, + 2_526_277_953_866_680, + 2_684_992_273_439_945, + 2_853_677_877_130_641, + 3_032_961_214_443_876, + 3_223_508_091_799_862, + 3_426_026_145_146_232, + 3_641_267_467_913_124, + 3_870_031_404_070_482, + 4_113_167_516_660_186, + 4_371_578_742_827_277, + 4_646_224_747_067_156, + 4_938_125_485_141_739, + 5_248_364_991_899_922, + 5_578_095_407_069_235, + 5_928_541_253_969_291, + 6_301_003_987_036_955, + 6_696_866_825_051_405, + 7_117_599_888_008_300, + 7_564_765_656_719_910, + 8_040_024_775_416_580, + 8_545_142_218_898_723, + 9_081_993_847_142_344, + 9_652_573_371_700_016, + 10_258_999_759_768_490, + 10_903_525_103_419_522, + 11_588_542_983_217_942, + 12_316_597_357_287_042, + 13_090_392_008_832_678, + 13_912_800_587_211_472, + 14_786_877_279_832_732, + 15_715_868_154_526_436, + 16_703_223_214_499_558, + 17_752_609_210_649_358, + 18_867_923_258_814_856, + 20_053_307_312_537_008, + 21_313_163_545_075_252, + 22_652_170_697_804_756, + 24_075_301_455_707_600, + 25_587_840_914_485_432, + 27_195_406_207_875_088, + 28_903_967_368_057_400, + 30_719_869_496_628_636, + 32_649_856_328_471_220, + 34_701_095_276_033_064, + 36_881_204_047_022_752, + 39_198_278_934_370_992, + 41_660_924_883_519_016, + 44_278_287_448_695_240, + 47_060_086_756_856_400, + 50_016_653_605_425_536, + 53_158_967_827_883_320, + 56_498_699_069_691_424, + 60_048_250_125_977_912, + 63_820_803_001_928_304, + 67_830_367_866_937_216, + 72_091_835_084_322_176, + 76_621_030_509_822_880, + 81_434_774_264_248_528, + 86_550_943_198_537_824, + 91_988_537_283_208_848, + 97_767_750_168_749_840, + 103_910_044_178_992_000, + 110_438_230_015_967_792, + 117_376_551_472_255_616, + 124_750_775_465_407_920, + 132_588_287_728_824_640, + 140_918_194_514_440_064, + 149_771_430_684_917_568, + 159_180_874_596_775_264, + 169_181_470_201_085_280, + 179_810_356_815_193_344, + 191_107_007_047_393_216, + 203_113_373_386_768_288, + 215_874_044_002_592_672, + 229_436_408_331_885_600, + 243_850_833_070_063_392, + 259_170_849_218_267_264, + 275_453_350_882_006_752, + 292_758_806_559_399_232, + 311_151_483_703_668_992, + 330_699_687_393_865_920, + 351_476_014_000_157_824, + 373_557_620_785_735_808, + 397_026_512_446_556_096, + 421_969_845_653_044_224, + 448_480_252_724_740_928, + 476_656_185_639_923_904, + 506_602_281_657_757_760, + 538_429_751_910_786_752, + 572_256_794_410_890_176, + 608_209_033_002_485_632, + 646_419_983_893_124_352, + 687_031_551_494_039_552, + 730_194_555_412_054_016, + 776_069_290_549_944_960, + 824_826_122_395_314_176, + 876_646_119_708_695_936, + 931_721_726_960_522_368, + 990_257_479_014_182_144, + 1_052_470_760_709_299_712, + 1_118_592_614_166_106_112, + 1_188_868_596_808_997_376, + 1_263_559_693_295_730_432, + 1_342_943_284_738_898_688, + 1_427_314_178_819_094_784, + 1_516_985_704_615_302_400, + 1_612_290_876_218_400_768, + 1_713_583_629_449_105_408, + 1_821_240_136_273_157_632, + 1_935_660_201_795_120_128, + 2_057_268_749_018_809_600, + 2_186_517_396_888_336_384, + 2_323_886_137_470_138_880, + 2_469_885_118_504_583_168, + 2_625_056_537_947_004_416, + 2_789_976_657_533_970_944, + 2_965_257_942_852_572_160, + 3_151_551_337_860_326_400, + 3_349_548_682_302_620_672, + 3_559_985_281_005_267_968, + 3_783_642_634_583_792_128, + 4_021_351_341_710_503_936, + 4_273_994_183_717_548_544, + 4_542_509_402_991_247_872, + 4_827_894_187_332_742_144, + 5_131_208_373_224_844_288, + 5_453_578_381_757_959_168, + 5_796_201_401_831_965_696, + 6_160_349_836_169_256_960, + 6_547_376_026_650_146_816, + 6_958_717_276_519_173_120, + 7_395_901_188_113_309_696, + 7_860_551_335_934_872_576, + 8_354_393_296_137_270_272, + 8_879_261_054_815_360_000, + 9_437_103_818_898_946_048, + 10_029_993_254_943_105_024, + 10_660_131_182_698_121_216, + 11_329_857_752_030_707_712, + 12_041_660_133_563_240_448, + 12_798_181_755_305_525_248, + 13_602_232_119_581_272_064, + 14_456_797_236_706_498_560, + 15_365_050_714_167_523_328, + 16_330_365_542_480_556_032, + 17_356_326_621_502_140_416, + 18_446_744_073_709_551_615, +]; + +// TODO(gpestana): generate target voter bag list with tooling. +/// Upper thresholds delimiting the targets bag list. +pub const TARGET_THRESHOLDS: [crate::Balance; 200] = [ 100_000_000_000_000, 106_282_535_907_434, 112_959_774_389_150, From 261e8ab5e771187589d3dd7dd6d2673994c38f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 17:17:22 +0100 Subject: [PATCH 052/133] stake-tracker cargo fix --- Cargo.lock | 1 - substrate/frame/staking/stake-tracker/Cargo.toml | 3 --- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce8a6c3a4550..d1e1a2f3b485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10745,7 +10745,6 @@ dependencies = [ name = "pallet-stake-tracker" version = "0.1.0" dependencies = [ - "frame-benchmarking", "frame-election-provider-support", "frame-support", "frame-system", diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 3b86a29dc308..80c431e08b8a 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -21,7 +21,6 @@ sp-std = { default-features = false, path = "../../../primitives/std" } sp-npos-elections = { path = "../../../primitives/npos-elections" } frame-election-provider-support = { default-features = false, path = "../../election-provider-support" } -frame-benchmarking = { default-features = false, optional = true, path = "../../benchmarking" } frame-support = { default-features = false, path = "../../support" } frame-system = { default-features = false, path = "../../system" } @@ -41,7 +40,6 @@ default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", @@ -53,7 +51,6 @@ std = [ ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", From 63f43f8e9fbdb789e22400b2945e05c39a13c8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 21:52:18 +0100 Subject: [PATCH 053/133] Fixes stake-tracker/no-std --- substrate/bin/node/runtime/Cargo.toml | 1 - .../test-staking-e2e/Cargo.toml | 2 +- substrate/frame/staking/Cargo.toml | 3 +++ substrate/frame/staking/stake-tracker/Cargo.toml | 15 ++++++++++----- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 8b5d6f39f848..749d03945bbe 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -402,7 +402,6 @@ try-runtime = [ "pallet-skip-feeless-payment/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", - "pallet-stake-tracker/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-statement/try-runtime", "pallet-sudo/try-runtime", diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 81998348e705..d8b3166d7294 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -35,7 +35,7 @@ frame-election-provider-support = { path = "../../election-provider-support" } pallet-election-provider-multi-phase = { path = ".." } pallet-staking = { path = "../../staking" } -pallet-stake-tracker = { path = "../../staking/stake-tracker" } +pallet-stake-tracker = { path = "../../staking/stake-tracker", default-features = false } pallet-bags-list = { path = "../../bags-list" } pallet-balances = { path = "../../balances" } pallet-timestamp = { path = "../../timestamp" } diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index bb4fa9d86e1d..a7d0181da055 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -65,6 +65,7 @@ std = [ "pallet-authorship/std", "pallet-bags-list/std", "pallet-balances/std", + "pallet-stake-tracker/std", "pallet-session/std", "pallet-timestamp/std", "scale-info/std", @@ -89,6 +90,7 @@ runtime-benchmarks = [ "rand_chacha", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", @@ -100,4 +102,5 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", + "pallet-stake-tracker/try-runtime", ] diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 80c431e08b8a..977fa90ddc17 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -19,7 +19,7 @@ sp-runtime = { default-features = false, path = "../../../primitives/runtime", f sp-staking = { default-features = false, path = "../../../primitives/staking", features = ["serde"] } sp-std = { default-features = false, path = "../../../primitives/std" } -sp-npos-elections = { path = "../../../primitives/npos-elections" } +sp-npos-elections = { default-features = false, path = "../../../primitives/npos-elections" } frame-election-provider-support = { default-features = false, path = "../../election-provider-support" } frame-support = { default-features = false, path = "../../support" } frame-system = { default-features = false, path = "../../system" } @@ -28,12 +28,12 @@ log = { version = "0.4.17", default-features = false } [dev-dependencies] sp-std = { default-features = false, path = "../../../primitives/std" } -sp-core = { path = "../../../primitives/core" } +sp-core = { default-features = false, path = "../../../primitives/core" } sp-io = { default-features = false, path = "../../../primitives/io" } sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } -sp-tracing = { path = "../../../primitives/tracing" } -pallet-bags-list = { path = "../../bags-list" } -pallet-balances = { path = "../../balances" } +sp-tracing = { default-features = false, path = "../../../primitives/tracing" } +pallet-bags-list = { default-features = false, path = "../../bags-list" } +pallet-balances = { default-features = false, path = "../../balances" } [features] default = ["std"] @@ -45,9 +45,14 @@ std = [ "scale-info/std", "sp-runtime/std", "sp-std/std", + "sp-staking/std", + "sp-runtime/std", + "sp-core/std", + "sp-tracing/std", "frame-election-provider-support/std", "pallet-balances/std", "pallet-bags-list/std", + "sp-npos-elections/std" ] runtime-benchmarks = [ diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 242b40e9569d..a0b2d7fa3dc0 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -91,7 +91,7 @@ use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; #[cfg(test)] mod mock; From bc2f2ce6bf6b882d2241d5f7dc21fece7c00d078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 22:13:41 +0100 Subject: [PATCH 054/133] Fixes feature dependencies --- substrate/bin/node/runtime/Cargo.toml | 2 ++ substrate/frame/staking/stake-tracker/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 749d03945bbe..ff4d31024642 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -325,6 +325,7 @@ runtime-benchmarks = [ "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -402,6 +403,7 @@ try-runtime = [ "pallet-skip-feeless-payment/try-runtime", "pallet-society/try-runtime", "pallet-staking/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-statement/try-runtime", "pallet-sudo/try-runtime", diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 977fa90ddc17..ee370c87e3d3 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -39,6 +39,7 @@ pallet-balances = { default-features = false, path = "../../balances" } default = ["std"] std = [ + "log/std", "codec/std", "frame-support/std", "frame-system/std", @@ -62,6 +63,7 @@ runtime-benchmarks = [ "frame-election-provider-support/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", + "sp-staking/runtime-benchmarks", ] try-runtime = [ From 50ea3d0265b93d57f5d7ea6cc1595bb8c3143b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 22:38:38 +0100 Subject: [PATCH 055/133] fmt cargo.toml --- substrate/bin/node/runtime/Cargo.toml | 6 ++-- substrate/frame/staking/Cargo.toml | 6 ++-- .../frame/staking/stake-tracker/Cargo.toml | 29 ++++++++++--------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index ff4d31024642..67298a717c3f 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -224,9 +224,9 @@ std = [ "pallet-session/std", "pallet-skip-feeless-payment/std", "pallet-society/std", + "pallet-stake-tracker/std", "pallet-staking-runtime-api/std", "pallet-staking/std", - "pallet-stake-tracker/std", "pallet-state-trie-migration/std", "pallet-statement/std", "pallet-sudo/std", @@ -324,8 +324,8 @@ runtime-benchmarks = [ "pallet-session-benchmarking/runtime-benchmarks", "pallet-skip-feeless-payment/runtime-benchmarks", "pallet-society/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", "pallet-stake-tracker/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -402,8 +402,8 @@ try-runtime = [ "pallet-session/try-runtime", "pallet-skip-feeless-payment/try-runtime", "pallet-society/try-runtime", - "pallet-staking/try-runtime", "pallet-stake-tracker/try-runtime", + "pallet-staking/try-runtime", "pallet-state-trie-migration/try-runtime", "pallet-statement/try-runtime", "pallet-sudo/try-runtime", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index a7d0181da055..ab7a6daaf54d 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -65,8 +65,8 @@ std = [ "pallet-authorship/std", "pallet-bags-list/std", "pallet-balances/std", - "pallet-stake-tracker/std", "pallet-session/std", + "pallet-stake-tracker/std", "pallet-timestamp/std", "scale-info/std", "serde/std", @@ -86,11 +86,11 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", - "pallet-stake-tracker/runtime-benchmarks", ] try-runtime = [ "frame-election-provider-support/try-runtime", @@ -100,7 +100,7 @@ try-runtime = [ "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", "pallet-session/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", - "pallet-stake-tracker/try-runtime", ] diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index ee370c87e3d3..660736253b70 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -39,38 +39,39 @@ pallet-balances = { default-features = false, path = "../../balances" } default = ["std"] std = [ - "log/std", "codec/std", + "frame-election-provider-support/std", "frame-support/std", "frame-system/std", + "log/std", + "pallet-bags-list/std", + "pallet-balances/std", "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-npos-elections/std", "sp-runtime/std", - "sp-std/std", - "sp-staking/std", "sp-runtime/std", - "sp-core/std", + "sp-staking/std", + "sp-std/std", "sp-tracing/std", - "frame-election-provider-support/std", - "pallet-balances/std", - "pallet-bags-list/std", - "sp-npos-elections/std" ] runtime-benchmarks = [ + "frame-election-provider-support/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", ] try-runtime = [ + "frame-election-provider-support/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", - "sp-runtime/try-runtime", - "frame-election-provider-support/try-runtime", - "pallet-balances/try-runtime", "pallet-bags-list/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", ] From 38e6616c07ec9b19340d39ba2356421a0861a815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Feb 2024 23:26:37 +0100 Subject: [PATCH 056/133] fixes westend/stake-tracker runtime config --- polkadot/runtime/westend/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 51ea324c5963..5626781fb91a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1721,7 +1721,6 @@ mod benches { // Substrate [pallet_bags_list, VoterList] [pallet_bags_list, TargetList] - [pallet_stake_tracker, StakeTracker] [pallet_balances, Balances] [pallet_conviction_voting, ConvictionVoting] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] From 5a5494a360e27b54f8b3b540b5f3ec39ed263800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 6 Feb 2024 00:03:15 +0100 Subject: [PATCH 057/133] impls max_exposure_page_size for mock (runtime-benchmarks) --- .../frame/staking/stake-tracker/src/mock.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 7e41fcf044fc..786d2c8b9888 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -232,16 +232,21 @@ impl StakingInterface for StakingMock { #[cfg(feature = "runtime-benchmarks")] fn add_era_stakers( - current_era: &sp_staking::EraIndex, - stash: &Self::AccountId, - exposures: Vec<(Self::AccountId, Self::Balance)>, + _current_era: &sp_staking::EraIndex, + _stash: &Self::AccountId, + _exposures: Vec<(Self::AccountId, Self::Balance)>, ) { - unreachable!(); + unimplemented!("method currently not used in testing") } #[cfg(feature = "runtime-benchmarks")] - fn set_current_era(era: sp_staking::EraIndex) { - unreachable!(); + fn set_current_era(_era: sp_staking::EraIndex) { + unimplemented!("method currently not used in testing") + } + + #[cfg(feature = "runtime-benchmarks")] + fn max_exposure_page_size() -> sp_staking::Page { + unimplemented!("method currently not used in testing") } } From 246c49a1e98f96c97c915fc0483a8a28c1a103e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 6 Feb 2024 10:40:17 +0100 Subject: [PATCH 058/133] fixes rust docs --- substrate/frame/staking/stake-tracker/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index a0b2d7fa3dc0..3d34a7a1c6d5 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -156,7 +156,8 @@ pub mod pallet { /// Something that provides an *always* sorted list of targets. /// /// This pallet is responsible to keep the score and sorting of this pallet up to date with - /// the state from [`Self::StakingInterface`]. + /// the correct approvals stakes of every target that is bouded or it has been bonded in the + /// past *and* it still has nominations from active voters. type TargetList: SortedListProvider< Self::AccountId, Score = ::Balance, @@ -508,7 +509,8 @@ impl OnStakingUpdate> for Pallet { /// Fired when someone removes their intention to nominate and is completely removed from the /// staking state. /// - /// Note: this may update the score of up to [`T::MaxNominations`] validators. + /// Note: the number of nodes that are updated is bounded by the maximum number of nominators, + /// which is defined in the staking pallet. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); From 41a00a34b9a16396478e25d90309fda07021d766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 7 Feb 2024 17:04:49 +0100 Subject: [PATCH 059/133] Adds throughout try-state checks and includes stake-tracker try-state checks in the staking pallet tests --- substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/mock.rs | 42 +++ substrate/frame/staking/src/pallet/impls.rs | 3 +- substrate/frame/staking/src/tests.rs | 58 ++-- .../frame/staking/stake-tracker/src/lib.rs | 292 ++++++++++++++---- .../frame/staking/stake-tracker/src/tests.rs | 1 + 6 files changed, 303 insertions(+), 95 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 09185a690be1..a8eee0a30b36 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -576,7 +576,6 @@ impl StakingLedger { if slash_amount.is_zero() { return Zero::zero() } - use sp_runtime::PerThing as _; let mut remaining_slash = slash_amount; let pre_slash_total = self.total; @@ -683,6 +682,7 @@ impl StakingLedger { self.unlocking.retain(|c| !c.value.is_zero()); let final_slashed_amount = pre_slash_total.saturating_sub(self.total); + T::EventListeners::on_slash( &self.stash, self.active, diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index e0873ad5a94c..8634cfbdb98e 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -368,6 +368,8 @@ pub(crate) type TestCall = ::RuntimeCall; parameter_types! { // if true, skips the try-state for the test running. pub static SkipTryStateCheck: bool = false; + // if true, skips the stake-tracker try-state for the tests running. + pub static SkipStakeTrackerTryStateCheck: bool = false; } pub struct ExtBuilder { @@ -483,6 +485,10 @@ impl ExtBuilder { SkipTryStateCheck::set(!enable); self } + pub fn stake_tracker_try_state(self, enable: bool) -> Self { + SkipStakeTrackerTryStateCheck::set(!enable); + self + } fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -621,6 +627,18 @@ impl ExtBuilder { }) .unwrap(); } + + // run the stake tracker try state checks too to leverage the test coverage of the + // staking pallet tests. + #[cfg(feature = "try-runtime")] + if !SkipStakeTrackerTryStateCheck::get() { + StakeTracker::do_try_state() + .map_err(|err| { + println!(" 🕵️‍♂️ StakeTracker try_state failure: {:?}", err); + err + }) + .unwrap() + } }); } } @@ -961,6 +979,30 @@ pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(Accoun ) } +#[allow(dead_code)] +pub(crate) fn print_lists_debug() { + use sp_staking::StakingInterface; + + println!("\nVoters:"); + let _ = voters_and_targets() + .0 + .iter() + .map(|v| { + println!(" {:?} -> {:?}", v, Staking::status(&v.0)); + }) + .collect::>(); + + println!("\nTargets:"); + let _ = voters_and_targets() + .1 + .iter() + .map(|v| { + println!(" {:?} -> {:?}", v, Staking::status(&v.0)); + }) + .collect::>(); + println!("\n"); +} + pub(crate) fn target_bags_events() -> Vec> { System::events() .into_iter() diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index cb3f885e857b..e8e039666048 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -952,7 +952,8 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - // target list also contains chilled/idle validators and unbonded ledgers. filter those. + // target list may contain chilled validators and dangling (i.e. unbonded) targets, filter + // those. let mut targets_iter = T::TargetList::iter() .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) .filter(|t| !Self::status(&t).is_err()); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 9662cf9ffe17..4d913b369d10 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -462,6 +462,7 @@ fn staking_should_work() { start_session(2); // add a new candidate for being a validator. account 3 controlled by 4. assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 1500, RewardDestination::Account(3))); + assert_ok!(Staking::validate(RuntimeOrigin::signed(3), ValidatorPrefs::default())); assert_ok!(Session::set_keys( RuntimeOrigin::signed(3), @@ -2193,32 +2194,35 @@ fn new_era_elects_correct_number_of_validators() { #[test] fn phragmen_should_not_overflow() { - ExtBuilder::default().nominate(false).build_and_execute(|| { - // This is the maximum value that we can have as the outcome of CurrencyToVote. - type Votes = u64; + ExtBuilder::default() + .stake_tracker_try_state(false) + .nominate(false) + .build_and_execute(|| { + // This is the maximum value that we can have as the outcome of CurrencyToVote. + type Votes = u64; - let _ = Staking::chill(RuntimeOrigin::signed(10)); - let _ = Staking::chill(RuntimeOrigin::signed(20)); + let _ = Staking::chill(RuntimeOrigin::signed(10)); + let _ = Staking::chill(RuntimeOrigin::signed(20)); - bond_validator(3, Votes::max_value() as Balance); - bond_validator(5, Votes::max_value() as Balance); + bond_validator(3, Votes::max_value() as Balance); + bond_validator(5, Votes::max_value() as Balance); - bond_nominator(7, Votes::max_value() as Balance, vec![3, 5]); - bond_nominator(9, Votes::max_value() as Balance, vec![3, 5]); + bond_nominator(7, Votes::max_value() as Balance, vec![3, 5]); + bond_nominator(9, Votes::max_value() as Balance, vec![3, 5]); - mock::start_active_era(1); + mock::start_active_era(1); - assert_eq_uvec!(validator_controllers(), vec![3, 5]); + assert_eq_uvec!(validator_controllers(), vec![3, 5]); - // We can safely convert back to values within [u64, u128]. - assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); - assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); - }) + // We can safely convert back to values within [u64, u128]. + assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); + }) } #[test] fn reward_validator_slashing_validator_does_not_overflow() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().stake_tracker_try_state(false).build_and_execute(|| { let stake = u64::MAX as Balance * 2; let reward_slash = u64::MAX as Balance * 2; @@ -5448,6 +5452,7 @@ mod election_data_provider { #[test] fn lazy_quota_npos_voters_works_above_quota() { ExtBuilder::default() + .stake_tracker_try_state(false) .nominate(false) .has_stakers(true) .add_staker( @@ -5480,6 +5485,7 @@ mod election_data_provider { #[test] fn nominations_quota_limits_size_work() { ExtBuilder::default() + .stake_tracker_try_state(false) .nominate(false) .has_stakers(true) .add_staker(71, 70, 333, StakerStatus::::Nominator(vec![11, 21, 31, 41])) @@ -6072,6 +6078,7 @@ fn change_of_absolute_max_nominations() { fn nomination_quota_max_changes_decoding() { use frame_election_provider_support::ElectionDataProvider; ExtBuilder::default() + .stake_tracker_try_state(false) .add_staker(60, 61, 10, StakerStatus::Nominator(vec![11])) .add_staker(70, 71, 10, StakerStatus::Nominator(vec![11, 21, 31])) .add_staker(30, 330, 10, StakerStatus::Nominator(vec![11, 21, 31, 41])) @@ -7757,7 +7764,9 @@ mod stake_tracker { // we immediately slash 11 with a 50% slash. let exposure = Staking::eras_stakers(active_era(), &11); let slash_percent = Perbill::from_percent(50); - let total_stake_to_slash = slash_percent * exposure.total; + let total_others_stake_to_slash = + exposure.others.iter().fold(0, |acc, s| acc + s.value); + on_offence_now( &[OffenceDetails { offender: (11, exposure.clone()), reporters: vec![] }], &[slash_percent], @@ -7770,9 +7779,11 @@ mod stake_tracker { assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); // and its balance has been updated based on the slash applied + chilling. let score_11_after = >::score(&11); + assert_eq!( score_11_after, - score_11_before - total_stake_to_slash - self_stake_11_before + score_11_before - + self_stake_11_before - (slash_percent * total_others_stake_to_slash), ); // self-stake of 11 has decreased by 50% due to slash. @@ -7801,22 +7812,19 @@ mod stake_tracker { // Although 11 is chilled, it is still part of the target list. assert_eq!( voters_and_targets().1, - [(21, score_21_after), (31, 500), (11, score_11_after)] + [(21, score_21_after), (11, score_11_after), (31, 500)] ); assert_eq!( target_bags_events(), [ BagsEvent::Rebagged { who: 11, from: 10000, to: 2000 }, BagsEvent::ScoreUpdated { who: 11, new_score: 1050 }, - BagsEvent::Rebagged { who: 11, from: 2000, to: 600 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 550 }, - BagsEvent::Rebagged { who: 11, from: 600, to: 500 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 465 }, + BagsEvent::Rebagged { who: 11, from: 2000, to: 1000 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 965 }, BagsEvent::Rebagged { who: 21, from: 10000, to: 2000 }, BagsEvent::ScoreUpdated { who: 21, new_score: 1965 }, BagsEvent::ScoreUpdated { who: 21, new_score: 1872 }, - BagsEvent::Rebagged { who: 11, from: 500, to: 400 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 372 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 872 }, ] ); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 3d34a7a1c6d5..ba694ba323f7 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -208,120 +208,275 @@ pub mod pallet { ) } + /// Returns whether a target should be removed from the target list. + /// + /// A target should be removed from the target list at any point IFF: + /// * it's approvals are 0 AND + /// * it's state is dangling (ledger unbonded). + pub(crate) fn should_remove_target(who: &T::AccountId, score: BalanceOf) -> bool { + score.is_zero() && T::Staking::status(&who).is_err() + } + /// Updates a target's score by increasing/decreasing an imbalance of the current score in /// the target list. pub(crate) fn update_target_score( who: &T::AccountId, imbalance: StakeImbalance, ) { - // there may be nominators who nominate a validator that is not bonded anymore. if - // that's the case, move on. This is an expected behaviour, so no defensive. + // if the target is not part of the list, check state of the target to update first. if !T::TargetList::contains(who) { - log!(debug, "update_score of {:?}, which is not a target", who); - return + match T::Staking::status(who) { + Err(_) | Ok(StakerStatus::Nominator(_)) => { + defensive!("update target score was called on an unbonded ledger or nominator, not expected."); + return + }, + Ok(StakerStatus::Validator) => { + defensive!( + "active validator was not part of the target list, something is wrong." + ); + return + }, + Ok(StakerStatus::Idle) => { + // if stash is idle and not part of the target list yet, initialize it and + // proceed. + T::TargetList::on_insert(who.clone(), Zero::zero()) + .expect("staker does not exist in the list as per check above; qed."); + }, + } } - match imbalance { + // update target score. + let removed = match imbalance { StakeImbalance::Positive(imbalance) => { let _ = T::TargetList::on_increase(who, Self::to_currency(imbalance)) .defensive_proof( "staker should exist in the list, otherwise returned earlier.", ); + false }, StakeImbalance::Negative(imbalance) => { if let Ok(current_score) = T::TargetList::get_score(who) { let balance = Self::to_vote_extended(current_score).saturating_sub(imbalance); - // the target is removed from the list IFF score is 0 and the ledger is not - // bonded in staking. - if balance.is_zero() && T::Staking::status(who).is_err() { + // the target is removed from the list IFF score is 0 and the target is + // dangling (i.e. not bonded). + if Self::should_remove_target(who, Self::to_currency(balance)) { let _ = T::TargetList::on_remove(who).defensive_proof( "staker exists in the list as per the check above; qed.", ); + true } else { // update the target score without removing it. let _ = T::TargetList::on_update(who, Self::to_currency(balance)) .defensive_proof( "staker exists in the list as per the check above; qed.", ); + false } } else { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); + false } }, - } + }; + + log!( + debug, + "update_score of {:?} by {:?}. removed target node? {}", + who, + imbalance, + removed + ); } - #[cfg(any(test, feature = "try-runtime"))] + /// Try-state checks for the stake-tracker pallet. + /// + /// 1. [`Self::do_try_state_approvals`]: checks the curent approval stake in the target list + /// compared with the staking state. + /// 2. [`Self::do_try_state_target_sorting`]: checks if the target list is sorted by score. + #[cfg(feature = "try-runtime")] pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - // Invariant. - // * The target score in the target list is the sum of self-stake and all stake from - // nominations. - // * All valid validators are part of the target list. - let mut map: BTreeMap, ExtendedBalance> = BTreeMap::new(); - - for nominator in T::VoterList::iter() { - if let Some(nominations) = ::nominations(&nominator) - { + Self::do_try_state_approvals()?; + Self::do_try_state_target_sorting() + } + + /// Try-state: checks if the approvals stake of the targets in the target list are correct. + /// + /// These try-state checks generate a map with approval stake of all the targets based on + /// the staking state of stakers in the voter and target lists. In doing so, we are able to + /// verify that the current voter and target lists and scores are in sync with the staking + /// data and perform other sanity checks as the approvals map is calculated. + /// + /// NOTE: this is an expensive state check since it iterates over all the nodes in the + /// target and voter list providers. + /// + /// Invariants: + /// + /// * Target List: + /// * The sum of the calculated approvals stake is the same as the current approvals in + /// the target list per target. + /// * The target score of an active validator is the sum of all of its nominators' stake + /// and the self-stake; + /// * The target score of an idle validator (i.e. chilled) is the sum of its nominator's + /// stake. An idle target may not be part of the target list, if it has no nominations. + /// * The target score of a "dangling" target (ie. idle AND unbonded validator) must + /// always be > 0. We expect the stake-tracker to have cleaned up dangling targets with 0 + /// score. + /// * The number of target nodes in the target list matches the number of + /// (active_validators + idle_validators + dangling_targets_score_with_score). + /// + /// * Voter List: + /// * The voter score is the same as the active stake of the corresponding stash. + /// * An active validator should also be part of the voter list. + /// * An idle validator should not be part of the voter list. + /// * A dangling target shoud not be part of the voter list. + #[cfg(any(test, feature = "try-runtime"))] + pub(crate) fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { + let mut approvals_map: BTreeMap, ExtendedBalance> = BTreeMap::new(); + + // build map of approvals stakes from the `VoterList` POV. + for voter in T::VoterList::iter() { + if let Some(nominations) = ::nominations(&voter) { let score = - >>::get_score(&nominator) + >>::get_score(&voter) .map_err(|_| "nominator score must exist in voter bags list")?; + // sanity check. + let active_stake = T::Staking::stake(&voter) + .map(|s| Self::weight_of(s.active)) + .expect("active voter has bonded stake; qed."); + ensure!( + active_stake == score, + "voter score must be the same as its active stake" + ); + for nomination in nominations { - if let Some(stake) = map.get_mut(&nomination) { + if let Some(stake) = approvals_map.get_mut(&nomination) { *stake += score as ExtendedBalance; } else { - map.insert(nomination, score.into()); + approvals_map.insert(nomination, score.into()); } } } } + + // add self-vote of active targets to calculated approvals from the `TargetList` POV. for target in T::TargetList::iter() { - let score = - >>::get_score(&target) - .map_err(|_| "target score must exist in voter bags list")?; + // also checks invariant: all active targets are also voters. + let maybe_self_stake = match T::Staking::status(&target) { + Err(_) => { + // if target is "dangling" (i.e unbonded but still in the `TargetList`), it + // should NOT be part of the voter list. + ensure!( + !T::VoterList::contains(&target), + "dangling target (i.e. unbonded) should not be part of the voter list" + ); + + // if target is dangling, its target score should > 0 (otherwise it should + // have been removed from the list). + ensure!( + T::TargetList::get_score(&target).expect("target must have score") > Zero::zero(), + "dangling target (i.e. unbonded) is part of the `TargetList` IFF it's approval voting > 0" + ); + // no self-stake and it should not be part of the target list. + None + }, + Ok(StakerStatus::Idle) => { + // target is idle and not part of the voter list. + ensure!( + !T::VoterList::contains(&target), + "chilled validator (idle target) should not be part of the voter list" + ); + + // no sef-stake but since it's chilling, it should be part of the TL even + // with score = 0. + Some(0) + }, + Ok(StakerStatus::Validator) => { + // active target should be part of the voter list. + ensure!( + T::VoterList::contains(&target), + "bonded and active validator should also be part of the voter list" + ); + // return self-stake (ie. active bonded). + let stake = + T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok(); + stake + }, + Ok(StakerStatus::Nominator(_)) => { + panic!( + "staker with nominator status should not be part of the target list" + ); + }, + }; - if let Some(stake) = map.get_mut(&target) { - *stake += score as ExtendedBalance; + if let Some(score) = maybe_self_stake { + if let Some(stake) = approvals_map.get_mut(&target) { + *stake += score as ExtendedBalance; + } else { + approvals_map.insert(target, score.into()); + } } else { - map.insert(target, score.into()); + // unbonded target: it does not have self-stake. } } - // compare final result with target list. - let mut valid_validators_count = 0; - for (target, stake) in map.into_iter() { - if let Ok(stake_in_list) = T::TargetList::get_score(&target) { - let stake_in_list = Self::to_vote_extended(stake_in_list); - - if stake != stake_in_list { - log!( - error, - "try-runtime: score of {:?} in list: {:?}, sum of all stake: {:?}", - target, - stake_in_list, - stake, - ); - return Err( - "target score in the target list is different than the expected".into() - ) - } + log!(trace, "try-state: calculated approvals map: {:?}", approvals_map); - valid_validators_count += 1; - } else { - // moot target nomination, do nothing. + // compare calculated approvals per target with target list state. + for (target, calculated_stake) in approvals_map.iter() { + let stake_in_list = + T::TargetList::get_score(&target).expect("target must exist; qed."); + let stake_in_list = Self::to_vote_extended(stake_in_list); + + if calculated_stake.clone() != stake_in_list { + log!( + error, + "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", + target, + stake_in_list, + calculated_stake, + ); + + return Err( + "target score in the target list is different than the expected".into() + ) } } - let count = T::TargetList::count() as usize; ensure!( - valid_validators_count == count, - "target list count is different from total of targets.", + approvals_map.keys().count() == T::TargetList::iter().count() as usize, + "calculated approvals count is different from total of target list.", ); Ok(()) } + + /// Try-state: checks if targets in the target list are sorted by score. + /// + /// Invariant: + /// * All targets in the target list are sorted by their score. + #[cfg(any(test, feature = "try-runtime"))] + pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { + let mut current_highest = None; + + for t in T::TargetList::iter() { + let target_score = T::TargetList::get_score(&t).expect("score must exist"); + + // first iter. + if current_highest.is_none() { + current_highest = Some(target_score); + } + + ensure!( + current_highest.expect("is set based on the above; qed.") >= target_score, + "target list is not sorted", + ); + } + + Ok(()) + } } } @@ -414,10 +569,21 @@ impl OnStakingUpdate> for Pallet { /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { - // target may exist in the list in case of re-enabling a chilled validator; + let self_stake = self_stake.unwrap_or_default().active; + if !T::TargetList::contains(who) { - T::TargetList::on_insert(who.clone(), self_stake.unwrap_or_default().active) + T::TargetList::on_insert(who.clone(), self_stake) .expect("staker does not exist in the list as per check above; qed."); + } else { + // if the target already exists in the list, it means that the target has been idle + // and/or dangling. + debug_assert!( + T::Staking::status(who) == Ok(StakerStatus::Idle) || + T::Staking::status(who).is_err() + ); + + let self_stake = Self::to_vote_extended(self_stake); + Self::update_target_score(who, StakeImbalance::Positive(self_stake)); } log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); @@ -568,23 +734,13 @@ impl OnStakingUpdate> for Pallet { /// Fired when a slash happens. /// - /// In practice, this only updates the score of the slashed validators, since the score of the - /// nominators and corresponding scores are updated through the `ledger.update` calls following - /// the slash. + /// In practice, this is a noop in the context of the stake tracker, since the score of the + /// voters and targets are updated through the `ledger.update` calls following the slash. fn on_slash( - stash: &T::AccountId, + _stash: &T::AccountId, _slashed_active: BalanceOf, _slashed_unlocking: &BTreeMap>, - slashed_total: BalanceOf, + _slashed_total: BalanceOf, ) { - let stake_imbalance = StakeImbalance::Negative(Self::to_vote_extended(slashed_total)); - - match T::Staking::status(stash).defensive_proof("called on_slash on a unbonded stash") { - Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) => - Self::update_target_score(stash, stake_imbalance), - // score of target impacted by nominators will be updated through ledger.update. - Ok(StakerStatus::Nominator(_)) => (), - Err(_) => (), // nothing to see here. - } } } diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index e7e829967c71..5b90795afa24 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -311,6 +311,7 @@ fn on_nominator_add_already_exists_works() { } #[test] +#[should_panic] fn on_validator_add_already_exists_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(TargetBagsList::contains(&10)); From 3ae6d11949115d4087ab5b87df0ce070d93841cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 8 Feb 2024 11:53:03 +0100 Subject: [PATCH 060/133] Update substrate/frame/staking/src/ledger.rs Co-authored-by: Liam Aharon --- substrate/frame/staking/src/ledger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 07a5dbdd1f8d..b5c1ce02a9ab 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -221,7 +221,7 @@ impl StakingLedger { /// /// Note: we assume that [`T::EventListeners::on_nominator_remove`] and/or /// [`T::EventListeners::on_validator_remove`] have been called and the stash is idle, prior to - /// call this method. This can be achieved by calling `[crate::Pallet::::kill_stash]` prior + /// call this method. This can be achieved by calling [`crate::Pallet::::kill_stash`] prior /// to this call. pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; From cf047db11f96c3428c496db85fabefecd82e218e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 8 Feb 2024 19:19:01 +0100 Subject: [PATCH 061/133] fixes clippy --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index ba694ba323f7..6baa03733ee4 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -214,7 +214,7 @@ pub mod pallet { /// * it's approvals are 0 AND /// * it's state is dangling (ledger unbonded). pub(crate) fn should_remove_target(who: &T::AccountId, score: BalanceOf) -> bool { - score.is_zero() && T::Staking::status(&who).is_err() + score.is_zero() && T::Staking::status(who).is_err() } /// Updates a target's score by increasing/decreasing an imbalance of the current score in From 6e5d0194f7f02592b7b845e03eb4ff101ff71af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 8 Feb 2024 19:51:32 +0100 Subject: [PATCH 062/133] clean up try-state code --- substrate/frame/staking/src/pallet/impls.rs | 24 +- .../frame/staking/stake-tracker/src/lib.rs | 301 +++++++++--------- 2 files changed, 157 insertions(+), 168 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index e8e039666048..dc02383fa8e5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1028,15 +1028,10 @@ impl Pallet { /// A chilled nominator is removed from the `Nominators` map, and the nominator's new state must /// be signalled to [`T::EventListeners`]. pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { - let outcome = if Nominators::::contains_key(who) { - T::EventListeners::on_nominator_idle(who, Self::nominations(who).unwrap_or_default()); - Nominators::::remove(who); + Nominators::::take(who).map_or(false, |nominations| { + T::EventListeners::on_nominator_idle(who, nominations.targets.into()); true - } else { - false - }; - - outcome + }) } /// This function will remove a nominator from the `Nominators` storage map, @@ -1101,12 +1096,13 @@ impl Pallet { /// /// A chilled validator is removed from the `Validators` map. pub(crate) fn do_chill_validator(who: &T::AccountId) -> bool { - if Validators::::contains_key(who) { - Validators::::remove(who); - T::EventListeners::on_validator_idle(who); - true - } else { - false + match Validators::::contains_key(who) { + true => { + Validators::::remove(who); + T::EventListeners::on_validator_idle(who); + true + }, + false => false, } } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 6baa03733ee4..3f4cd11ea293 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -289,149 +289,146 @@ pub mod pallet { removed ); } + } +} - /// Try-state checks for the stake-tracker pallet. - /// - /// 1. [`Self::do_try_state_approvals`]: checks the curent approval stake in the target list - /// compared with the staking state. - /// 2. [`Self::do_try_state_target_sorting`]: checks if the target list is sorted by score. - #[cfg(feature = "try-runtime")] - pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state_approvals()?; - Self::do_try_state_target_sorting() - } +#[cfg(any(test, feature = "try-runtime"))] +impl Pallet { + /// Try-state checks for the stake-tracker pallet. + /// + /// 1. [`Self::do_try_state_approvals`]: checks the curent approval stake in the target list + /// compared with the staking state. + /// 2. [`Self::do_try_state_target_sorting`]: checks if the target list is sorted by score. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state_approvals()?; + Self::do_try_state_target_sorting() + } - /// Try-state: checks if the approvals stake of the targets in the target list are correct. - /// - /// These try-state checks generate a map with approval stake of all the targets based on - /// the staking state of stakers in the voter and target lists. In doing so, we are able to - /// verify that the current voter and target lists and scores are in sync with the staking - /// data and perform other sanity checks as the approvals map is calculated. - /// - /// NOTE: this is an expensive state check since it iterates over all the nodes in the - /// target and voter list providers. - /// - /// Invariants: - /// - /// * Target List: - /// * The sum of the calculated approvals stake is the same as the current approvals in - /// the target list per target. - /// * The target score of an active validator is the sum of all of its nominators' stake - /// and the self-stake; - /// * The target score of an idle validator (i.e. chilled) is the sum of its nominator's - /// stake. An idle target may not be part of the target list, if it has no nominations. - /// * The target score of a "dangling" target (ie. idle AND unbonded validator) must - /// always be > 0. We expect the stake-tracker to have cleaned up dangling targets with 0 - /// score. - /// * The number of target nodes in the target list matches the number of - /// (active_validators + idle_validators + dangling_targets_score_with_score). - /// - /// * Voter List: - /// * The voter score is the same as the active stake of the corresponding stash. - /// * An active validator should also be part of the voter list. - /// * An idle validator should not be part of the voter list. - /// * A dangling target shoud not be part of the voter list. - #[cfg(any(test, feature = "try-runtime"))] - pub(crate) fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { - let mut approvals_map: BTreeMap, ExtendedBalance> = BTreeMap::new(); - - // build map of approvals stakes from the `VoterList` POV. - for voter in T::VoterList::iter() { - if let Some(nominations) = ::nominations(&voter) { - let score = - >>::get_score(&voter) - .map_err(|_| "nominator score must exist in voter bags list")?; - - // sanity check. - let active_stake = T::Staking::stake(&voter) - .map(|s| Self::weight_of(s.active)) - .expect("active voter has bonded stake; qed."); - ensure!( - active_stake == score, - "voter score must be the same as its active stake" - ); + /// Try-state: checks if the approvals stake of the targets in the target list are correct. + /// + /// These try-state checks generate a map with approval stake of all the targets based on + /// the staking state of stakers in the voter and target lists. In doing so, we are able to + /// verify that the current voter and target lists and scores are in sync with the staking + /// data and perform other sanity checks as the approvals map is calculated. + /// + /// NOTE: this is an expensive state check since it iterates over all the nodes in the + /// target and voter list providers. + /// + /// Invariants: + /// + /// * Target List: + /// * The sum of the calculated approvals stake is the same as the current approvals in + /// the target list per target. + /// * The target score of an active validator is the sum of all of its nominators' stake + /// and the self-stake; + /// * The target score of an idle validator (i.e. chilled) is the sum of its nominator's + /// stake. An idle target may not be part of the target list, if it has no nominations. + /// * The target score of a "dangling" target (ie. idle AND unbonded validator) must + /// always be > 0. We expect the stake-tracker to have cleaned up dangling targets with 0 + /// score. + /// * The number of target nodes in the target list matches the number of + /// (active_validators + idle_validators + dangling_targets_score_with_score). + /// + /// * Voter List: + /// * The voter score is the same as the active stake of the corresponding stash. + /// * An active validator should also be part of the voter list. + /// * An idle validator should not be part of the voter list. + /// * A dangling target shoud not be part of the voter list. + pub(crate) fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { + let mut approvals_map: BTreeMap, ExtendedBalance> = BTreeMap::new(); + + // build map of approvals stakes from the `VoterList` POV. + for voter in T::VoterList::iter() { + if let Some(nominations) = ::nominations(&voter) { + let score = >>::get_score(&voter) + .map_err(|_| "nominator score must exist in voter bags list")?; + + // sanity check. + let active_stake = T::Staking::stake(&voter) + .map(|s| Self::weight_of(s.active)) + .expect("active voter has bonded stake; qed."); + frame_support::ensure!( + active_stake == score, + "voter score must be the same as its active stake" + ); - for nomination in nominations { - if let Some(stake) = approvals_map.get_mut(&nomination) { - *stake += score as ExtendedBalance; - } else { - approvals_map.insert(nomination, score.into()); - } + for nomination in nominations { + if let Some(stake) = approvals_map.get_mut(&nomination) { + *stake += score as ExtendedBalance; + } else { + approvals_map.insert(nomination, score.into()); } } } + } - // add self-vote of active targets to calculated approvals from the `TargetList` POV. - for target in T::TargetList::iter() { - // also checks invariant: all active targets are also voters. - let maybe_self_stake = match T::Staking::status(&target) { - Err(_) => { - // if target is "dangling" (i.e unbonded but still in the `TargetList`), it - // should NOT be part of the voter list. - ensure!( - !T::VoterList::contains(&target), - "dangling target (i.e. unbonded) should not be part of the voter list" - ); + // add self-vote of active targets to calculated approvals from the `TargetList` POV. + for target in T::TargetList::iter() { + // also checks invariant: all active targets are also voters. + let maybe_self_stake = match T::Staking::status(&target) { + Err(_) => { + // if target is "dangling" (i.e unbonded but still in the `TargetList`), it + // should NOT be part of the voter list. + frame_support::ensure!( + !T::VoterList::contains(&target), + "dangling target (i.e. unbonded) should not be part of the voter list" + ); - // if target is dangling, its target score should > 0 (otherwise it should - // have been removed from the list). - ensure!( + // if target is dangling, its target score should > 0 (otherwise it should + // have been removed from the list). + frame_support::ensure!( T::TargetList::get_score(&target).expect("target must have score") > Zero::zero(), "dangling target (i.e. unbonded) is part of the `TargetList` IFF it's approval voting > 0" ); - // no self-stake and it should not be part of the target list. - None - }, - Ok(StakerStatus::Idle) => { - // target is idle and not part of the voter list. - ensure!( - !T::VoterList::contains(&target), - "chilled validator (idle target) should not be part of the voter list" - ); + // no self-stake and it should not be part of the target list. + None + }, + Ok(StakerStatus::Idle) => { + // target is idle and not part of the voter list. + frame_support::ensure!( + !T::VoterList::contains(&target), + "chilled validator (idle target) should not be part of the voter list" + ); - // no sef-stake but since it's chilling, it should be part of the TL even - // with score = 0. - Some(0) - }, - Ok(StakerStatus::Validator) => { - // active target should be part of the voter list. - ensure!( - T::VoterList::contains(&target), - "bonded and active validator should also be part of the voter list" - ); - // return self-stake (ie. active bonded). - let stake = - T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok(); - stake - }, - Ok(StakerStatus::Nominator(_)) => { - panic!( - "staker with nominator status should not be part of the target list" - ); - }, - }; + // no sef-stake but since it's chilling, it should be part of the TL even + // with score = 0. + Some(0) + }, + Ok(StakerStatus::Validator) => { + // active target should be part of the voter list. + frame_support::ensure!( + T::VoterList::contains(&target), + "bonded and active validator should also be part of the voter list" + ); + // return self-stake (ie. active bonded). + let stake = T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok(); + stake + }, + Ok(StakerStatus::Nominator(_)) => { + panic!("staker with nominator status should not be part of the target list"); + }, + }; - if let Some(score) = maybe_self_stake { - if let Some(stake) = approvals_map.get_mut(&target) { - *stake += score as ExtendedBalance; - } else { - approvals_map.insert(target, score.into()); - } + if let Some(score) = maybe_self_stake { + if let Some(stake) = approvals_map.get_mut(&target) { + *stake += score as ExtendedBalance; } else { - // unbonded target: it does not have self-stake. + approvals_map.insert(target, score.into()); } + } else { + // unbonded target: it does not have self-stake. } + } - log!(trace, "try-state: calculated approvals map: {:?}", approvals_map); + log!(trace, "try-state: calculated approvals map: {:?}", approvals_map); - // compare calculated approvals per target with target list state. - for (target, calculated_stake) in approvals_map.iter() { - let stake_in_list = - T::TargetList::get_score(&target).expect("target must exist; qed."); - let stake_in_list = Self::to_vote_extended(stake_in_list); + // compare calculated approvals per target with target list state. + for (target, calculated_stake) in approvals_map.iter() { + let stake_in_list = T::TargetList::get_score(&target).expect("target must exist; qed."); + let stake_in_list = Self::to_vote_extended(stake_in_list); - if calculated_stake.clone() != stake_in_list { - log!( + if calculated_stake.clone() != stake_in_list { + log!( error, "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", target, @@ -439,44 +436,40 @@ pub mod pallet { calculated_stake, ); - return Err( - "target score in the target list is different than the expected".into() - ) - } + return Err("target score in the target list is different than the expected".into()) } + } - ensure!( - approvals_map.keys().count() == T::TargetList::iter().count() as usize, - "calculated approvals count is different from total of target list.", - ); + frame_support::ensure!( + approvals_map.keys().count() == T::TargetList::iter().count() as usize, + "calculated approvals count is different from total of target list.", + ); - Ok(()) - } + Ok(()) + } - /// Try-state: checks if targets in the target list are sorted by score. - /// - /// Invariant: - /// * All targets in the target list are sorted by their score. - #[cfg(any(test, feature = "try-runtime"))] - pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { - let mut current_highest = None; - - for t in T::TargetList::iter() { - let target_score = T::TargetList::get_score(&t).expect("score must exist"); - - // first iter. - if current_highest.is_none() { - current_highest = Some(target_score); - } + /// Try-state: checks if targets in the target list are sorted by score. + /// + /// Invariant + /// * All targets in the target list are sorted by their score. + pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { + let mut current_highest = None; - ensure!( - current_highest.expect("is set based on the above; qed.") >= target_score, - "target list is not sorted", - ); + for t in T::TargetList::iter() { + let target_score = T::TargetList::get_score(&t).expect("score must exist"); + + // first iter. + if current_highest.is_none() { + current_highest = Some(target_score); } - Ok(()) + frame_support::ensure!( + current_highest.expect("is set based on the above; qed.") >= target_score, + "target list is not sorted", + ); } + + Ok(()) } } From a1b16c7d733493a7218cadf27e695512503b0e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 8 Feb 2024 21:14:18 +0100 Subject: [PATCH 063/133] clippy nits --- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/tests.rs | 1 + substrate/frame/staking/stake-tracker/src/lib.rs | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d816933f103c..205c0fb50c47 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -233,7 +233,7 @@ impl Pallet { .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; - // Input data seems good, no errors allowed after this point + // Input data seems good, no errors allowed after the ledger is successfully updated. ledger.update()?; // Get Era reward points. It has TOTAL and INDIVIDUAL diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 4d913b369d10..3d255ee2960e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1779,6 +1779,7 @@ fn reward_to_stake_works() { .set_status(41, StakerStatus::Idle) .set_stake(21, 2000) .try_state(false) + .stake_tracker_try_state(false) .build_and_execute(|| { assert_eq!(Staking::validator_count(), 2); // Confirm account 10 and 20 are validators diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 3f4cd11ea293..1bd802a06f72 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -300,8 +300,8 @@ impl Pallet { /// compared with the staking state. /// 2. [`Self::do_try_state_target_sorting`]: checks if the target list is sorted by score. pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state_approvals()?; - Self::do_try_state_target_sorting() + Self::do_try_state_approvals() + //Self::do_try_state_target_sorting() } /// Try-state: checks if the approvals stake of the targets in the target list are correct. @@ -401,8 +401,7 @@ impl Pallet { "bonded and active validator should also be part of the voter list" ); // return self-stake (ie. active bonded). - let stake = T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok(); - stake + T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok() }, Ok(StakerStatus::Nominator(_)) => { panic!("staker with nominator status should not be part of the target list"); @@ -424,10 +423,10 @@ impl Pallet { // compare calculated approvals per target with target list state. for (target, calculated_stake) in approvals_map.iter() { - let stake_in_list = T::TargetList::get_score(&target).expect("target must exist; qed."); + let stake_in_list = T::TargetList::get_score(target).expect("target must exist; qed."); let stake_in_list = Self::to_vote_extended(stake_in_list); - if calculated_stake.clone() != stake_in_list { + if *calculated_stake != stake_in_list { log!( error, "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", @@ -441,7 +440,7 @@ impl Pallet { } frame_support::ensure!( - approvals_map.keys().count() == T::TargetList::iter().count() as usize, + approvals_map.keys().count() == T::TargetList::iter().count(), "calculated approvals count is different from total of target list.", ); @@ -452,6 +451,7 @@ impl Pallet { /// /// Invariant /// * All targets in the target list are sorted by their score. + #[allow(dead_code)] // TODO(remove) pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { let mut current_highest = None; From f48c7dee737621d301e24db83b1547eb1463ac4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 8 Feb 2024 23:07:12 +0100 Subject: [PATCH 064/133] Add try-runtime gated method in sorted list provider to help with checks --- substrate/frame/bags-list/src/lib.rs | 9 +++ .../test-staking-e2e/Cargo.toml | 1 + .../election-provider-support/src/lib.rs | 6 ++ substrate/frame/staking/src/pallet/impls.rs | 8 +++ substrate/frame/staking/src/pallet/mod.rs | 6 -- .../frame/staking/stake-tracker/src/lib.rs | 61 ++++++++++--------- 6 files changed, 55 insertions(+), 36 deletions(-) diff --git a/substrate/frame/bags-list/src/lib.rs b/substrate/frame/bags-list/src/lib.rs index 8e3d4cc1f012..07ac8b80584a 100644 --- a/substrate/frame/bags-list/src/lib.rs +++ b/substrate/frame/bags-list/src/lib.rs @@ -446,6 +446,15 @@ impl, I: 'static> SortedListProvider for Pallet List::::unsafe_regenerate(all, score_of) } + #[cfg(feature = "try-runtime")] + fn in_position(id: &T::AccountId) -> Result { + List::::get_score(id).and_then(|score| { + Ok(!ListNodes::::try_get(id) + .expect("if score exists, node exists; qed.") + .is_misplaced(score)) + }) + } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), TryRuntimeError> { Self::do_try_state() diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 8013c252d513..80e260d6cae5 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -53,6 +53,7 @@ try-runtime = [ "pallet-nomination-pools/try-runtime", "pallet-session/try-runtime", "pallet-staking/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", ] diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 2e9ee3b8a48b..1d64504c6189 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -566,6 +566,12 @@ pub trait SortedListProvider { /// unbounded amount of storage accesses. fn unsafe_clear(); + /// Returns whether the `id` is in the correct bag, given its score. + /// + /// Returns a boolean and it is only available in the context of `try-runtime` checks. + #[cfg(feature = "try-runtime")] + fn in_position(id: &AccountId) -> Result; + /// Check internal state of the list. Only meant for debugging. #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), TryRuntimeError>; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 205c0fb50c47..b7408ee17edf 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1648,6 +1648,10 @@ impl SortedListProvider for UseValidatorsMap { 0 } #[cfg(feature = "try-runtime")] + fn in_position(_: &T::AccountId) -> Result { + unimplemented!() + } + #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), TryRuntimeError> { Ok(()) } @@ -1724,6 +1728,10 @@ impl SortedListProvider for UseNominatorsAndValidatorsM 0 } + #[cfg(feature = "try-runtime")] + fn in_position(_: &T::AccountId) -> Result { + unimplemented!() + } #[cfg(feature = "try-runtime")] fn try_state() -> Result<(), TryRuntimeError> { Ok(()) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 228e8c3ee92d..ff30de61e69f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1088,12 +1088,6 @@ pub mod pallet { ledger.update()?; - // TODO(gpestana): this should not be here bu rather on the ledger.rs - // update this staker in the sorted list, if they exist in it. - if T::VoterList::contains(&stash) { - let _ = T::VoterList::on_update(&stash, Self::weight_of(&stash)).defensive(); - } - Self::deposit_event(Event::::Unbonded { stash, amount: value }); } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 1bd802a06f72..f9b08878b62c 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -223,7 +223,8 @@ pub mod pallet { who: &T::AccountId, imbalance: StakeImbalance, ) { - // if the target is not part of the list, check state of the target to update first. + // ensure that the target list node exists if it does not yet and perform a few + // defensive checks. if !T::TargetList::contains(who) { match T::Staking::status(who) { Err(_) | Ok(StakerStatus::Nominator(_)) => { @@ -296,12 +297,13 @@ pub mod pallet { impl Pallet { /// Try-state checks for the stake-tracker pallet. /// - /// 1. [`Self::do_try_state_approvals`]: checks the curent approval stake in the target list - /// compared with the staking state. - /// 2. [`Self::do_try_state_target_sorting`]: checks if the target list is sorted by score. + /// 1. `do_try_state_approvals`: checks the curent approval stake in the target list compared + /// with the staking state. + /// 2. `do_try_state_target_sorting`: checks if the target list is sorted by score. pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + #[cfg(feature = "try-runtime")] + Self::do_try_state_target_sorting()?; Self::do_try_state_approvals() - //Self::do_try_state_target_sorting() } /// Try-state: checks if the approvals stake of the targets in the target list are correct. @@ -451,21 +453,17 @@ impl Pallet { /// /// Invariant /// * All targets in the target list are sorted by their score. - #[allow(dead_code)] // TODO(remove) + /// + /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if + /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we + /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the + /// correct position in the list (bag or otherwise), given its score. + #[cfg(feature = "try-runtime")] pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { - let mut current_highest = None; - for t in T::TargetList::iter() { - let target_score = T::TargetList::get_score(&t).expect("score must exist"); - - // first iter. - if current_highest.is_none() { - current_highest = Some(target_score); - } - frame_support::ensure!( - current_highest.expect("is set based on the above; qed.") >= target_score, - "target list is not sorted", + T::TargetList::in_position(&t).expect("target exists"), + "target list is not sorted" ); } @@ -476,7 +474,8 @@ impl Pallet { impl OnStakingUpdate> for Pallet { /// Fired when the stake amount of some staker updates. /// - /// When a nominator's stake is updated, all the nominated targets must be updated accordingly. + /// When a nominator's stake is updated, all the nominated targets must be updated + /// accordingly. /// /// Note: it is assumed that `who`'s staking ledger state is updated *before* this method is /// called. @@ -533,8 +532,8 @@ impl OnStakingUpdate> for Pallet { nominations, ); - // updates vote weight of nominated targets accordingly. Note: this will update - // the score of up to `T::MaxNominations` validators. + // updates vote weight of nominated targets accordingly. Note: this will + // update the score of up to `T::MaxNominations` validators. for target in nominations.into_iter() { Self::update_target_score(&target, stake_imbalance); } @@ -542,6 +541,7 @@ impl OnStakingUpdate> for Pallet { StakerStatus::Validator => { // validator is both a target and a voter. let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); + Self::update_target_score(who, stake_imbalance); let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( @@ -589,7 +589,8 @@ impl OnStakingUpdate> for Pallet { /// /// While chilled, the target node remains in the target list. /// - /// While idling, the target node is not removed from the target list but its score is updated. + /// While idling, the target node is not removed from the target list but its score is + /// updated. fn on_validator_idle(who: &T::AccountId) { let self_stake = Self::weight_of(Self::active_vote_of(who)); Self::update_target_score(who, StakeImbalance::Negative(self_stake.into())); @@ -600,8 +601,8 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_validator_idle: {:?}, decreased self-stake {}", who, self_stake); } - /// Fired when someone removes their intention to validate and has been completely removed from - /// the staking state. + /// Fired when someone removes their intention to validate and has been completely removed + /// from the staking state. /// /// The node is removed from the target list IFF its score is 0. fn on_validator_remove(who: &T::AccountId) { @@ -665,11 +666,11 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_remove(who, nominations); } - /// Fired when someone removes their intention to nominate and is completely removed from the - /// staking state. + /// Fired when someone removes their intention to nominate and is completely removed from + /// the staking state. /// - /// Note: the number of nodes that are updated is bounded by the maximum number of nominators, - /// which is defined in the staking pallet. + /// Note: the number of nodes that are updated is bounded by the maximum number of + /// nominators, which is defined in the staking pallet. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); @@ -692,9 +693,9 @@ impl OnStakingUpdate> for Pallet { /// Fired when an existing nominator updates their nominations. /// - /// This is called when a nominator updates their nominations. The nominator's stake remains the - /// same (updates to the nominator's stake should emit [`Self::on_stake_update`] instead). - /// However, the score of the nominated targets must be updated accordingly. + /// This is called when a nominator updates their nominations. The nominator's stake remains + /// the same (updates to the nominator's stake should emit [`Self::on_stake_update`] + /// instead). However, the score of the nominated targets must be updated accordingly. /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. From 4ac7fcf1256e2f928378464ed05142b5b7c639e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 9 Feb 2024 03:13:42 +0100 Subject: [PATCH 065/133] Adds the callable drop_dangling_nomination to allow permissionless dropping dangling nominations --- .../test-staking-e2e/src/mock.rs | 2 + substrate/frame/staking/src/mock.rs | 2 + .../frame/staking/stake-tracker/src/lib.rs | 87 ++++++++++++++++++- .../frame/staking/stake-tracker/src/mock.rs | 70 +++++++++++++-- .../frame/staking/stake-tracker/src/tests.rs | 75 ++++++++++++++++ .../staking/stake-tracker/src/weights.rs | 41 +++++++++ 6 files changed, 269 insertions(+), 8 deletions(-) create mode 100644 substrate/frame/staking/stake-tracker/src/weights.rs diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index adb50e887176..ce2972d1a9b4 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -264,9 +264,11 @@ impl pallet_bags_list::Config for Runtime { impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; + type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type WeightInfo = (); } pub struct BalanceToU256; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 8634cfbdb98e..dbb80f5a9a0b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -306,9 +306,11 @@ impl OnStakingUpdate for SlashListenerMock { impl pallet_stake_tracker::Config for Test { type Currency = Balances; + type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type WeightInfo = (); } impl crate::pallet::pallet::Config for Test { diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index f9b08878b62c..90fce1e0b74d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -98,6 +98,10 @@ mod mock; #[cfg(test)] mod tests; +mod weights; + +use weights::WeightInfo; + pub(crate) const LOG_TARGET: &str = "runtime::stake-tracker"; // syntactic sugar for logging. @@ -130,7 +134,10 @@ pub mod pallet { use crate::*; use frame_election_provider_support::{ExtendedBalance, VoteWeight}; use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::BlockNumberFor; + use frame_system::{ + ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, + }; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -141,8 +148,12 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + /// The stake balance. type Currency: FnInspect>; + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// The staking interface. type Staking: StakingInterface; @@ -162,6 +173,28 @@ pub mod pallet { Self::AccountId, Score = ::Balance, >; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// A dangling nomination has been successfully dropped. + /// + /// A dangling nomination is a nomination to an unbonded target. + DanglingNominationDropped { voter: AccountIdOf, target: AccountIdOf }, + } + + #[pallet::error] + pub enum Error { + /// Target is not dangling. + /// + /// A dandling target is a target that is part of the target list but is unbonded. + NotDanglingTarget, + /// Not a voter/nominator. + NotVoter, } #[pallet::hooks] @@ -172,6 +205,58 @@ pub mod pallet { } } + #[pallet::call] + impl Pallet { + /// Removes nomination from a chilled and unbonded target. + /// + /// In the case that an unboded target still has nominations lingering, the approvals stake + /// for the "dangling" target needs to remain in the target list. This extrinsic allows + /// nominations of dangling targets to be removed. + /// + /// A danling nomination may be removed IFF: + /// * The `target` is unbonded and it exists in the target list. + /// * The `voter` is nominating `target`. + /// + /// Emits `DanglingNominationDropped`. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::drop_dangling_nomination())] + pub fn drop_dangling_nomination( + origin: OriginFor, + voter: AccountIdOf, + target: AccountIdOf, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + ensure!( + T::Staking::status(&target).is_err() && T::TargetList::contains(&target), + Error::::NotDanglingTarget + ); + + match T::Staking::status(&voter) { + Ok(StakerStatus::Nominator(nominations)) => { + let count_before = nominations.len(); + + let nominations_after = + nominations.into_iter().filter(|n| *n != target).collect::>(); + + if nominations_after.len() != count_before { + T::Staking::nominate(&voter, nominations_after)?; + + Self::deposit_event(Event::::DanglingNominationDropped { + voter, + target, + }); + + Ok(Pays::No.into()) + } else { + Ok(Pays::Yes.into()) + } + }, + _ => Err(Error::::NotVoter.into()), + } + } + } + impl Pallet { /// Returns the balance of a staker based on its current *active* stake, as returned by /// the staking interface. diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 786d2c8b9888..f33937e2472f 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -96,10 +96,11 @@ impl pallet_bags_list::Config for Test { impl pallet_stake_tracker::Config for Test { type Currency = Balances; - + type RuntimeEvent = RuntimeEvent; type Staking = StakingMock; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type WeightInfo = (); } pub struct StakingMock {} @@ -148,8 +149,13 @@ impl StakingInterface for StakingMock { (false, true, true) => Ok(StakerStatus::Nominator(nominators.get(who).expect("exists").1.clone())), (false, false, true) => Ok(StakerStatus::Idle), - (false, false, false) => Err("not a staker".into()), - _ => Err("mock: inconsistent data".into()), + (false, false, false) => + if TargetBagsList::contains(who) { + Err("dangling".into()) + } else { + Err("not a staker".into()) + }, + _ => Err("bad state".into()), } } @@ -189,10 +195,12 @@ impl StakingInterface for StakingMock { } fn nominate( - _who: &Self::AccountId, - _validators: Vec, + who: &Self::AccountId, + validators: Vec, ) -> sp_runtime::DispatchResult { - unreachable!(); + update_nominations_of(*who, validators); + + Ok(()) } fn chill(_who: &Self::AccountId) -> sp_runtime::DispatchResult { @@ -285,6 +293,43 @@ pub(crate) fn add_nominator(who: AccountId, stake: Balance) { >::on_nominator_add(&who, vec![]); } +pub(crate) fn add_dangling_target_with_nominators(target: AccountId, nominators: Vec) { + // add new validator. + add_validator(target, 10); + + // update nominations. + for n in nominators { + let mut nominations = StakingMock::nominations(&n).unwrap(); + nominations.push(target); + update_nominations_of(n, nominations); + } + + // remove self-stake/unbond. + let stake = ::stake(&target).unwrap(); + let mut stake_after_unbond = stake.clone(); + stake_after_unbond.active -= 10; + stake_after_unbond.total -= 10; + + // now remove all the self-stake score from the validator. + >::on_stake_update( + &target, + Some(stake), + stake_after_unbond, + ); + + Bonded::mutate(|b| { + b.retain(|s| s != &target); + }); + + TestValidators::mutate(|v| { + v.remove(&target); + }); + + TestNominators::mutate(|n| { + n.remove(&target); + }); +} + pub(crate) fn stake_of(who: AccountId) -> Option> { StakingMock::stake(&who).ok() } @@ -303,7 +348,6 @@ pub(crate) fn add_nominator_with_nominations( // add new nominator (called at `fn bond` in staking) add_nominator(who, stake); - // add nominations (called at `fn nominate` in staking) TestNominators::mutate(|n| { n.insert(who, (Stake:: { active: stake, total: stake }, nominations.clone())); }); @@ -449,6 +493,11 @@ impl ExtBuilder { self } + pub fn try_state(self, enable: bool) -> Self { + DisableTryRuntimeChecks::set(!enable); + self + } + pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -479,3 +528,10 @@ impl ExtBuilder { } } } + +pub(crate) fn assert_last_event(generic_event: RuntimeEvent) { + let events = frame_system::Pallet::::events(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events.last().expect("Event expected"); + assert_eq!(event, &generic_event); +} diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 5b90795afa24..5c697114f667 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -381,6 +381,81 @@ fn on_validator_remove_defensive_works() { }) } +mod extrinsics { + use super::*; + use crate::{Error, Event}; + + use frame_support::assert_noop; + + #[test] + fn drop_dangling_nomination_works() { + ExtBuilder::default().populate_lists().try_state(false).build_and_execute(|| { + // target is dangling with nominations from 1 and 2. + add_dangling_target_with_nominators(42, vec![1, 2]); + + // 1 is now nominating 42.. + assert_ok!(StakingMock::status(&1), StakerStatus::Nominator(vec![10, 42])); + // .. which is unbonded.. + assert!(StakingMock::status(&42).is_err()); + // .. and still part of the target list (thus dangling). + assert!(TargetBagsList::contains(&42)); + + // remove 1 as dangling nomination. + assert_ok!(StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 1, 42)); + + assert_last_event( + Event::::DanglingNominationDropped { voter: 1, target: 42 }.into(), + ); + + // now, 1 is not nominating 42 anymore. + assert_ok!(StakingMock::status(&1), StakerStatus::Nominator(vec![10])); + // but 42 is still dangling because 2 is still nominating it + assert!(TargetBagsList::contains(&42)); + assert_ok!(StakingMock::status(&2), StakerStatus::Nominator(vec![10, 11, 42])); + + // when the last dangling nomination is removed, the danling target is removed. + assert_ok!(StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 2, 42)); + + assert_ok!(StakingMock::status(&2), StakerStatus::Nominator(vec![10, 11])); + assert!(!TargetBagsList::contains(&42)); + + assert_last_event( + Event::::DanglingNominationDropped { voter: 2, target: 42 }.into(), + ); + }) + } + + #[test] + fn drop_dangling_nomination_failures_work() { + ExtBuilder::default().populate_lists().try_state(false).build_and_execute(|| { + // target is not dangling since it does not exist in the target list. + assert!(StakingMock::status(&42).is_err()); + assert!(!TargetBagsList::contains(&42)); + + assert_noop!( + StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), + Error::::NotDanglingTarget, + ); + + // target is not dangling since it is still bonded. + assert!(StakingMock::status(&10) == Ok(StakerStatus::Validator)); + assert_noop!( + StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), + Error::::NotDanglingTarget, + ); + + // target is dangling but voter is not nominating it. + assert!(StakingMock::status(&1) == Ok(StakerStatus::Nominator(vec![10]))); + add_dangling_target_with_nominators(42, vec![1]); + assert!(StakingMock::status(&42).is_err()); + assert_noop!( + StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), + Error::::NotVoter, + ); + }) + } +} + mod staking_integration { use super::*; diff --git a/substrate/frame/staking/stake-tracker/src/weights.rs b/substrate/frame/staking/stake-tracker/src/weights.rs new file mode 100644 index 000000000000..f280d0f24d6c --- /dev/null +++ b/substrate/frame/staking/stake-tracker/src/weights.rs @@ -0,0 +1,41 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::marker::PhantomData; +use frame_support::weights::Weight; + +/// Weight functions needed for `pallet_stake_tracker`. +pub trait WeightInfo { + fn drop_dangling_nomination() -> Weight; +} + +/// Weights for `pallet_stake_tracker` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn drop_dangling_nomination() -> Weight { + // TODO(gpestana): benchmarks. + Weight::default() + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + fn drop_dangling_nomination() -> Weight { + // TODO(gpestana): benchmarks. + Weight::default() + } +} From 2fdb67397bc5433d10856afb58b2fe1785f68604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 9 Feb 2024 03:30:39 +0100 Subject: [PATCH 066/133] clippy --- polkadot/runtime/westend/src/lib.rs | 4 +++- substrate/bin/node/runtime/src/lib.rs | 2 ++ .../election-provider-multi-phase/test-staking-e2e/Cargo.toml | 2 +- substrate/frame/staking/stake-tracker/src/mock.rs | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 34ec027dfaff..04bab07c304a 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -643,9 +643,11 @@ impl pallet_bags_list::Config for Runtime { impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; + type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterList; type TargetList = TargetList; + type WeightInfo = (); } pallet_staking_reward_curve::build! { @@ -1471,7 +1473,7 @@ construct_runtime! { TargetList: pallet_bags_list::::{Pallet, Call, Storage, Event} = 103, // Stake tracker for staking. - StakeTracker: pallet_stake_tracker::{Pallet, Storage} = 104, + StakeTracker: pallet_stake_tracker::{Pallet, Call, Storage, Event} = 104, // Nomination pools for staking. NominationPools: pallet_nomination_pools = 29, diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a16dceb338cb..6c6d90186e9e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -695,9 +695,11 @@ impl pallet_staking::Config for Runtime { impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; + type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterList; type TargetList = TargetList; + type WeightInfo = (); } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml index 80e260d6cae5..e50302ebd94b 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/Cargo.toml @@ -52,8 +52,8 @@ try-runtime = [ "pallet-election-provider-multi-phase/try-runtime", "pallet-nomination-pools/try-runtime", "pallet-session/try-runtime", - "pallet-staking/try-runtime", "pallet-stake-tracker/try-runtime", + "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", ] diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index f33937e2472f..0cbd41dc5b57 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -306,7 +306,7 @@ pub(crate) fn add_dangling_target_with_nominators(target: AccountId, nominators: // remove self-stake/unbond. let stake = ::stake(&target).unwrap(); - let mut stake_after_unbond = stake.clone(); + let mut stake_after_unbond = stake; stake_after_unbond.active -= 10; stake_after_unbond.total -= 10; From e5ca2339e91ed2ffcdc513ada05d116dcf847462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 9 Feb 2024 04:03:51 +0100 Subject: [PATCH 067/133] doc fixes --- substrate/frame/staking/stake-tracker/src/lib.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 90fce1e0b74d..9e4cb521d52d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -57,9 +57,14 @@ //! approvals score (nominations + self-stake) is kept up to date as the target list's score. //! * A [`sp_staking::StakerStatus::Idle`] may have a target list's score while other stakers //! nominate the idle validator. -//! * A staker which is not recognized by staking (i.e. not bonded) may still have an associated -//! target list score, in case there are other nominators nominating it. The list's node will -//! automatically be removed onced all the voters stop nominating the unbonded account. +//! * A "dangling" target, which is not an active staker anymore (i.e. not bonded), may still have +//! an associated target list score. This may happen when active nominators are still nominating +//! the target after the validator unbonded. The target list's node and score will automatically +//! be removed onced all the voters stop nominating the unbonded account (i.e. the target's score +//! drops to 0). +//! +//! For further details on the target list invariantes, refer to [`Self`::do_try_state_approvals`] +//! and [`Self::do_try_state_target_sorting`]. //! //! ## Domain-specific consideration on [`Config::VoterList`] and [`Config::TargetList`] //! From 786dbf5e7b4a75a6a62f12377829178058488b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 11 Feb 2024 21:42:21 +0100 Subject: [PATCH 068/133] simplifies staking imbalance calculation; addresses reviews --- substrate/frame/staking/src/ledger.rs | 8 ++ .../frame/staking/stake-tracker/src/lib.rs | 97 +++++++++---------- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index b5c1ce02a9ab..3ff07d855703 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -163,6 +163,9 @@ impl StakingLedger { /// Bonds the ledger if it is not bonded yet, signalling that this is a new ledger. The staking /// locks of the stash account are updated accordingly. /// + /// Emits: + /// * [`OnStakeUpdate::on_stake_update`] + /// /// Note: To ensure lock consistency, all the [`Ledger`] storage updates should be made through /// this helper function. pub(crate) fn update(self) -> Result<(), Error> { @@ -219,6 +222,9 @@ impl StakingLedger { /// Clears all data related to a staking ledger and its bond in both [`Ledger`] and [`Bonded`] /// storage items and updates the stash staking lock. /// + /// Emits: + /// * [`OnStakingUpdate::on_unstake`] + /// /// Note: we assume that [`T::EventListeners::on_nominator_remove`] and/or /// [`T::EventListeners::on_validator_remove`] have been called and the stash is idle, prior to /// call this method. This can be achieved by calling [`crate::Pallet::::kill_stash`] prior @@ -235,6 +241,8 @@ impl StakingLedger { >::remove(&stash); >::remove(&stash); + T::EventListeners::on_unstake(stash); + Ok(()) })? } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 9e4cb521d52d..28a35ca2576e 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -91,7 +91,6 @@ use frame_support::{ defensive, traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; -use sp_npos_elections::ExtendedBalance; use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, @@ -134,6 +133,16 @@ pub enum StakeImbalance { Positive(Balance), } +impl StakeImbalance { + fn from(prev_balance: Balance, new_balance: Balance) -> Self { + if prev_balance > new_balance { + StakeImbalance::Negative(prev_balance.defensive_saturating_sub(new_balance)) + } else { + StakeImbalance::Positive(new_balance.defensive_saturating_sub(prev_balance)) + } + } +} + #[frame_support::pallet] pub mod pallet { use crate::*; @@ -427,7 +436,8 @@ impl Pallet { /// * An idle validator should not be part of the voter list. /// * A dangling target shoud not be part of the voter list. pub(crate) fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { - let mut approvals_map: BTreeMap, ExtendedBalance> = BTreeMap::new(); + let mut approvals_map: BTreeMap, sp_npos_elections::ExtendedBalance> = + BTreeMap::new(); // build map of approvals stakes from the `VoterList` POV. for voter in T::VoterList::iter() { @@ -446,7 +456,7 @@ impl Pallet { for nomination in nominations { if let Some(stake) = approvals_map.get_mut(&nomination) { - *stake += score as ExtendedBalance; + *stake += score as sp_npos_elections::ExtendedBalance; } else { approvals_map.insert(nomination, score.into()); } @@ -502,7 +512,7 @@ impl Pallet { if let Some(score) = maybe_self_stake { if let Some(stake) = approvals_map.get_mut(&target) { - *stake += score as ExtendedBalance; + *stake += score as sp_npos_elections::ExtendedBalance; } else { approvals_map.insert(target, score.into()); } @@ -557,13 +567,18 @@ impl Pallet { ); } + for v in T::VoterList::iter() { + frame_support::ensure!( + T::VoterList::in_position(&v).expect("voter exists"), + "voter list is not sorted" + ); + } + Ok(()) } } impl OnStakingUpdate> for Pallet { - /// Fired when the stake amount of some staker updates. - /// /// When a nominator's stake is updated, all the nominated targets must be updated /// accordingly. /// @@ -574,28 +589,6 @@ impl OnStakingUpdate> for Pallet { prev_stake: Option>>, stake: Stake>, ) { - // closure to calculate the stake imbalance of a staker. - let stake_imbalance_of = |prev_stake: Option>>, - voter_weight: ExtendedBalance| { - if let Some(prev_stake) = prev_stake { - let prev_voter_weight = Self::to_vote_extended(prev_stake.active); - - if prev_voter_weight > voter_weight { - StakeImbalance::Negative( - prev_voter_weight.defensive_saturating_sub(voter_weight), - ) - } else { - StakeImbalance::Positive( - voter_weight.defensive_saturating_sub(prev_voter_weight), - ) - } - } else { - // if staker had no stake before update, then add all the voter weight - // to the target's score. - StakeImbalance::Positive(voter_weight) - } - }; - if T::Staking::status(who) .and(T::Staking::stake(who)) .defensive_proof( @@ -612,7 +605,10 @@ impl OnStakingUpdate> for Pallet { with staking.", ); - let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), + voter_weight.into(), + ); log!( debug, @@ -630,7 +626,10 @@ impl OnStakingUpdate> for Pallet { }, StakerStatus::Validator => { // validator is both a target and a voter. - let stake_imbalance = stake_imbalance_of(prev_stake, voter_weight.into()); + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), + voter_weight.into(), + ); Self::update_target_score(who, stake_imbalance); @@ -644,8 +643,6 @@ impl OnStakingUpdate> for Pallet { } } - /// Fired when someone sets their intention to validate. - /// /// A validator is also considered a voter with self-vote and should also be added to /// [`Config::VoterList`]. // @@ -675,9 +672,7 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_add(who, vec![]) } - /// Fired when a validator becomes idle (i.e. chilling). - /// - /// While chilled, the target node remains in the target list. + /// A validator has been chilled. The target node remains in the target list. /// /// While idling, the target node is not removed from the target list but its score is /// updated. @@ -691,10 +686,9 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_validator_idle: {:?}, decreased self-stake {}", who, self_stake); } - /// Fired when someone removes their intention to validate and has been completely removed - /// from the staking state. - /// - /// The node is removed from the target list IFF its score is 0. + /// A validator has been set as inactive/removed from the staking POV. The target node is + /// removed from the target list IFF its score is 0. Otherwise, its score should be kept up to + /// date as if the validator was active. fn on_validator_remove(who: &T::AccountId) { log!(debug, "on_validator_remove: {:?}", who,); @@ -718,8 +712,6 @@ impl OnStakingUpdate> for Pallet { } } - /// Fired when someone sets their intention to nominate. - /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is /// called. fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { @@ -746,9 +738,8 @@ impl OnStakingUpdate> for Pallet { log!(debug, "on_nominator_add: {:?}. role: {:?}", who, T::Staking::status(who),); } - /// Fired when a nominator becomes idle (i.e. chilling). - /// - /// From the `T::VotertList` PoV, chilling a nominator is the same as removing it. + /// A nominator has been idle. From the `T::VotertList` PoV, chilling a nominator is the same as + /// removing it. /// /// Note: it is assumed that `who`'s staking ledger and `nominations` are up to date before /// calling this method. @@ -781,8 +772,6 @@ impl OnStakingUpdate> for Pallet { .defensive_proof("the nominator exists in the list as per the contract with staking."); } - /// Fired when an existing nominator updates their nominations. - /// /// This is called when a nominator updates their nominations. The nominator's stake remains /// the same (updates to the nominator's stake should emit [`Self::on_stake_update`] /// instead). However, the score of the nominated targets must be updated accordingly. @@ -816,10 +805,18 @@ impl OnStakingUpdate> for Pallet { } } - /// Fired when a slash happens. - /// - /// In practice, this is a noop in the context of the stake tracker, since the score of the - /// voters and targets are updated through the `ledger.update` calls following the slash. + // no-op events. + + /// The score of the staker `who` is updated through the `on_stake_update` calls following the + /// full unstake (ledger kill). + fn on_unstake(_who: &T::AccountId) {} + + /// The score of the staker `who` is updated through the `on_stake_update` calls following the + /// withdraw. + fn on_withdraw(_who: &T::AccountId, _amount: BalanceOf) {} + + /// The score of the staker `who` is updated through the `on_stake_update` calls following the + /// slash. fn on_slash( _stash: &T::AccountId, _slashed_active: BalanceOf, From bfa02dcb16968c3c6149b0cfcc10c7bac0d94a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 12 Feb 2024 12:24:11 +0100 Subject: [PATCH 069/133] Update substrate/frame/staking/stake-tracker/src/lib.rs Co-authored-by: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 28a35ca2576e..6b871a9af7ec 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -634,7 +634,7 @@ impl OnStakingUpdate> for Pallet { Self::update_target_score(who, stake_imbalance); let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( - "the staker should exit in VoterList, as per the \ + "the staker should exist in VoterList, as per the \ contract with staking.", ); }, From 44f44efee239269e9a8354c705610a3a25d84300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 12 Feb 2024 13:17:40 +0100 Subject: [PATCH 070/133] addresses PR comments & simplifies stake-tracker code --- .../frame/staking/stake-tracker/src/lib.rs | 106 ++++++++---------- .../frame/staking/stake-tracker/src/tests.rs | 2 +- 2 files changed, 49 insertions(+), 59 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 6b871a9af7ec..742b71c3bb3d 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -589,57 +589,47 @@ impl OnStakingUpdate> for Pallet { prev_stake: Option>>, stake: Stake>, ) { - if T::Staking::status(who) - .and(T::Staking::stake(who)) - .defensive_proof( - "staker should exist when calling on_stake_update and have a valid status", - ) - .is_ok() - { - let voter_weight = Self::weight_of(stake.active); - - match T::Staking::status(who).expect("status checked above; qed.") { - StakerStatus::Nominator(nominations) => { - let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( - "staker should exist in VoterList, as per the contract \ - with staking.", - ); + match T::Staking::stake(who).and(T::Staking::status(who)) { + Ok(StakerStatus::Nominator(nominations)) => { + let voter_weight = Self::weight_of(stake.active); - let stake_imbalance = StakeImbalance::from( - prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), - voter_weight.into(), - ); + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( + "staker should exist in VoterList, as per the contract \ + with staking.", + ); - log!( - debug, - "on_stake_update: {:?} with {:?}. impacting nominations {:?}", - who, - stake_imbalance, - nominations, - ); + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), + voter_weight.into(), + ); - // updates vote weight of nominated targets accordingly. Note: this will - // update the score of up to `T::MaxNominations` validators. - for target in nominations.into_iter() { - Self::update_target_score(&target, stake_imbalance); - } - }, - StakerStatus::Validator => { - // validator is both a target and a voter. - let stake_imbalance = StakeImbalance::from( - prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), - voter_weight.into(), - ); + // updates vote weight of nominated targets accordingly. Note: this will + // update the score of up to `T::MaxNominations` validators. + for target in nominations.into_iter() { + Self::update_target_score(&target, stake_imbalance); + } + }, + Ok(StakerStatus::Validator) => { + let voter_weight = Self::weight_of(stake.active); + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), + voter_weight.into(), + ); - Self::update_target_score(who, stake_imbalance); + Self::update_target_score(who, stake_imbalance); - let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( - "the staker should exist in VoterList, as per the \ + // validator is both a target and a voter. + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( + "the staker should exist in VoterList, as per the \ contract with staking.", - ); - }, - StakerStatus::Idle => (), // nothing to see here. - } + ); + }, + Ok(StakerStatus::Idle) => (), // nothing to see here. + Err(_) => { + defensive!( + "staker should exist when calling `on_stake_update` and have a valid status" + ); + }, } } @@ -651,19 +641,19 @@ impl OnStakingUpdate> for Pallet { fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { let self_stake = self_stake.unwrap_or_default().active; - if !T::TargetList::contains(who) { - T::TargetList::on_insert(who.clone(), self_stake) - .expect("staker does not exist in the list as per check above; qed."); - } else { - // if the target already exists in the list, it means that the target has been idle - // and/or dangling. - debug_assert!( - T::Staking::status(who) == Ok(StakerStatus::Idle) || - T::Staking::status(who).is_err() - ); + match T::TargetList::on_insert(who.clone(), self_stake) { + Ok(_) => (), + Err(_) => { + // if the target already exists in the list, it means that the target has been idle + // and/or dangling. + debug_assert!( + T::Staking::status(who) == Ok(StakerStatus::Idle) || + T::Staking::status(who).is_err() + ); - let self_stake = Self::to_vote_extended(self_stake); - Self::update_target_score(who, StakeImbalance::Positive(self_stake)); + let self_stake = Self::to_vote_extended(self_stake); + Self::update_target_score(who, StakeImbalance::Positive(self_stake)); + }, } log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); @@ -781,7 +771,7 @@ impl OnStakingUpdate> for Pallet { fn on_nominator_update( who: &T::AccountId, prev_nominations: Vec, - nominations: Vec>, + nominations: Vec, ) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 5c697114f667..3b0323a9a5c8 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -248,7 +248,7 @@ fn on_stake_update_defensive_not_in_list_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: Other(\"not a staker\"): \"staker should exist when calling on_stake_update and have a valid status\""] +#[should_panic = "Defensive failure has been triggered!: \"staker should exist when calling `on_stake_update` and have a valid status\""] fn on_stake_update_defensive_not_staker_works() { ExtBuilder::default().build_and_execute(|| { assert!(!VoterBagsList::contains(&1)); From ff8ee33885fd9533f66d7af35bfdb9d4b16cd5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 12 Feb 2024 13:58:24 +0100 Subject: [PATCH 071/133] add a couple more checks to try-state when building the approvals map --- substrate/frame/staking/stake-tracker/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 742b71c3bb3d..5bfad6930bcd 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -461,6 +461,17 @@ impl Pallet { approvals_map.insert(nomination, score.into()); } } + } else { + // if it is in the voter list but it's not a nominator, it should be a validator + // and part of the target list. + frame_support::ensure!( + T::Staking::status(&voter) == Ok(StakerStatus::Validator), + "wrong state of voter" + ); + frame_support::ensure!( + T::TargetList::contains(&voter), + "if voter is in voter list and it's not a nominator, it must be a target" + ); } } From 740565b734c3bdc9ded23fc816d9a6d1c0de71bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 13 Feb 2024 15:22:33 +0100 Subject: [PATCH 072/133] ensures OnStakingUpdate events are triggered at the correct places and tests --- substrate/frame/staking/Cargo.toml | 1 + substrate/frame/staking/src/mock.rs | 98 ++++++++- substrate/frame/staking/src/pallet/impls.rs | 23 +-- substrate/frame/staking/src/tests.rs | 210 ++++++++++++++++++++ substrate/primitives/staking/Cargo.toml | 1 + substrate/primitives/staking/src/lib.rs | 63 +++++- 6 files changed, 374 insertions(+), 22 deletions(-) diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index ab7a6daaf54d..b3b15b78a8f5 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -52,6 +52,7 @@ substrate-test-utils = { path = "../../test-utils" } frame-benchmarking = { path = "../benchmarking" } frame-election-provider-support = { path = "../election-provider-support" } rand_chacha = { version = "0.2" } +sp-staking = { path = "../../primitives/staking", default-features = false, features = ["serde", "test-utils"] } [features] default = ["std"] diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index dbb80f5a9a0b..49410c3e579a 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -41,7 +41,7 @@ use sp_runtime::{ }; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - OnStakingUpdate, + OnStakingUpdate, OnStakingUpdateEvent, Stake, }; pub const INIT_TIMESTAMP: u64 = 30_000; @@ -290,6 +290,7 @@ parameter_types! { pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub static EventsEmitted: Vec> = vec![]; } pub struct SlashListenerMock; @@ -304,6 +305,83 @@ impl OnStakingUpdate for SlashListenerMock { } } +pub struct EventTracker; +impl OnStakingUpdate for EventTracker { + fn on_stake_update(who: &AccountId, prev_stake: Option>, stake: Stake) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::StakeUpdate { who: *who, prev_stake, stake }); + }) + } + fn on_nominator_add(who: &AccountId, nominations: Vec) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::NominatorAdd { who: *who, nominations }); + }) + } + fn on_nominator_update( + who: &AccountId, + prev_nominations: Vec, + nominations: Vec, + ) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::NominatorUpdate { + who: *who, + prev_nominations, + nominations, + }); + }) + } + fn on_nominator_idle(who: &AccountId, prev_nominations: Vec) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::NominatorIdle { who: *who, prev_nominations }); + }) + } + fn on_nominator_remove(who: &AccountId, nominations: Vec) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::NominatorRemove { who: *who, nominations }); + }) + } + fn on_validator_add(who: &AccountId, self_stake: Option>) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::ValidatorAdd { who: *who, self_stake }); + }) + } + fn on_validator_update(who: &AccountId, self_stake: Option>) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::ValidatorUpdate { who: *who, self_stake }); + }) + } + fn on_validator_idle(who: &AccountId) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::ValidatorIdle { who: *who }); + }) + } + fn on_validator_remove(who: &AccountId) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::ValidatorRemove { who: *who }); + }) + } + fn on_withdraw(who: &AccountId, amount: Balance) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::Withdraw { who: *who, amount }); + }) + } + fn on_unstake(who: &AccountId) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::Unstake { who: *who }); + }) + } + fn on_slash( + who: &AccountId, + slashed_active: Balance, + _slashed_unlocking: &BTreeMap, + slashed_total: Balance, + ) { + EventsEmitted::mutate(|v| { + v.push(OnStakingUpdateEvent::Slash { who: *who, slashed_active, slashed_total }); + }) + } +} + impl pallet_stake_tracker::Config for Test { type Currency = Balances; type RuntimeEvent = RuntimeEvent; @@ -340,7 +418,7 @@ impl crate::pallet::pallet::Config for Test { type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; - type EventListeners = (StakeTracker, SlashListenerMock); + type EventListeners = (StakeTracker, SlashListenerMock, EventTracker); type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); } @@ -912,6 +990,22 @@ pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } +// this helper method also cleans the current state of `EventsEmtted`. +pub(crate) fn ensure_on_staking_updates_emitted( + expected: Vec>, +) { + assert_eq!( + EventsEmitted::get(), + expected, + "`OnStakingUpdate` events not as expected: {:?} != {:?}", + EventsEmitted::get(), + expected + ); + + // reset events emitted. + EventsEmitted::set(vec![]); +} + /// Similar to the try-state checks of the stake-tracker pallet, but works without `try-runtime` /// feature enabled. pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b7408ee17edf..017c24469589 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1032,7 +1032,7 @@ impl Pallet { /// be signalled to [`T::EventListeners`]. pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { Nominators::::take(who).map_or(false, |nominations| { - T::EventListeners::on_nominator_idle(who, nominations.targets.into()); + T::EventListeners::on_nominator_remove(who, nominations.clone().targets.into()); true }) } @@ -1046,18 +1046,12 @@ impl Pallet { /// to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { let outcome = match Self::status(who) { - Ok(StakerStatus::Nominator(nominations)) => { + Ok(StakerStatus::Nominator(_)) | Ok(StakerStatus::Validator) => { let outcome = Self::do_chill_nominator(who); - T::EventListeners::on_nominator_remove(who, nominations); outcome }, - Ok(StakerStatus::Validator) => { - let outcome = Self::do_chill_nominator(who); - T::EventListeners::on_nominator_remove(who, vec![]); - outcome - }, - // not an active nomination, do nothing. - _ => false, + // not an active nominator, do nothing. + Err(_) | Ok(StakerStatus::Idle) => false, }; debug_assert_eq!( @@ -1124,10 +1118,6 @@ impl Pallet { T::EventListeners::on_validator_remove(who); outcome }, - Ok(StakerStatus::Nominator(_)) => { - defensive!("called do_validator_remove on a nominator stash."); - false - }, Ok(StakerStatus::Idle) | Err(_) if T::TargetList::contains(who) => { // try to remove "dangling" target. A dangling target does not have a bonded stash // but is still part of the target list because a previously removed stash still has @@ -1135,10 +1125,7 @@ impl Pallet { T::EventListeners::on_validator_remove(who); false }, - _ => { - // validator has been already removed. - false - }, + _ => false, }; debug_assert_eq!( diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 3d255ee2960e..ee57ed5241b9 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6959,6 +6959,216 @@ mod staking_interface { } } +mod on_staking_update_events { + use super::*; + + use sp_staking::{OnStakingUpdateEvent::*, Stake}; + + #[test] + fn on_nominator_lifecycle_emit_works() { + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + // no events yet. + ensure_on_staking_updates_emitted(vec![]); + + // bond validator 11 and 12. + bond_validator(11, 100); + bond_validator(12, 100); + ensure_on_staking_updates_emitted(vec![ + StakeUpdate { who: 11, prev_stake: None, stake: Stake { total: 100, active: 100 } }, + ValidatorAdd { who: 11, self_stake: Some(Stake { total: 100, active: 100 }) }, + StakeUpdate { who: 12, prev_stake: None, stake: Stake { total: 100, active: 100 } }, + ValidatorAdd { who: 12, self_stake: Some(Stake { total: 100, active: 100 }) }, + ]); + + // bond staker 21. + bond(21, 100); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 21, + prev_stake: None, + stake: Stake { total: 100, active: 100 }, + }]); + + // staker 21 nominates 11. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(21), vec![11])); + ensure_on_staking_updates_emitted(vec![NominatorAdd { + who: 21, + nominations: vec![11], + }]); + + // 21 updates nominations. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(21), vec![12])); + ensure_on_staking_updates_emitted(vec![NominatorUpdate { + who: 21, + prev_nominations: vec![11], + nominations: vec![12], + }]); + + // 21 unbonds half of its stake. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 50)); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 21, + prev_stake: Some(Stake { total: 100, active: 100 }), + // 50 unlocking, 50 active. + stake: Stake { total: 100, active: 50 }, + }]); + + // 21 chills. + assert_ok!(Staking::chill(RuntimeOrigin::signed(21))); + ensure_on_staking_updates_emitted(vec![NominatorRemove { + who: 21, + nominations: vec![12], + }]); + + // 21 unbnonds completely. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(21), 50)); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 21, + prev_stake: Some(Stake { total: 100, active: 50 }), + stake: Stake { total: 100, active: 0 }, + }]); + + // roll to era where full withdraw can happen. + start_active_era(current_era() + BondingDuration::get()); + + // 21 withdraws all unlocked funds to kill the stash/ unstake. + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(21), 0)); + ensure_on_staking_updates_emitted(vec![ + Unstake { who: 21 }, + Withdraw { who: 21, amount: 100 }, + ]); + }) + } + + #[test] + fn on_validator_lifecycle_emit_works() { + ExtBuilder::default().build_and_execute(|| { + // reset `OnStakingUpdate` events from genesis. + EventsEmitted::set(vec![]); + ensure_on_staking_updates_emitted(vec![]); + + // bond validator 42. + bond_validator(42, 100); + ensure_on_staking_updates_emitted(vec![ + StakeUpdate { who: 42, prev_stake: None, stake: Stake { total: 100, active: 100 } }, + ValidatorAdd { who: 42, self_stake: Some(Stake { total: 100, active: 100 }) }, + ]); + + // 42 bonds 50 extra. + let _ = Balances::make_free_balance_be(&42, 500); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(42), 50)); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 42, + prev_stake: Some(Stake { total: 100, active: 100 }), + stake: Stake { total: 150, active: 150 }, + }]); + + // 42 unbonds 50. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(42), 50)); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 42, + prev_stake: Some(Stake { total: 150, active: 150 }), + stake: Stake { total: 150, active: 100 }, + }]); + + // 101 nominates 42. + let prev_nominations = Staking::nominations(&101).unwrap(); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![42])); + ensure_on_staking_updates_emitted(vec![NominatorUpdate { + who: 101, + prev_nominations, + nominations: vec![42], + }]); + + // 42 chills. + assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); + ensure_on_staking_updates_emitted(vec![ValidatorIdle { who: 42 }]); + + // 42 unbounds completely. + assert_ok!(Staking::unbond(RuntimeOrigin::signed(42), 100)); + ensure_on_staking_updates_emitted(vec![StakeUpdate { + who: 42, + prev_stake: Some(Stake { total: 150, active: 100 }), + stake: Stake { total: 150, active: 0 }, + }]); + + // roll to era where full withdraw can happen. + start_active_era(current_era() + BondingDuration::get()); + + // 11 withdraws all unlocked funds to kill the stash/ unstake. + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(42), 0)); + ensure_on_staking_updates_emitted(vec![ + ValidatorRemove { who: 42 }, + Unstake { who: 42 }, + Withdraw { who: 42, amount: 150 }, + ]); + }) + } + + #[test] + fn force_unstake_emit_works() { + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + // set stakers + bond_validator(11, 100); + bond_nominator(101, 100, vec![11]); + + // reset `OnStakingUpdate` events up to now. + EventsEmitted::set(vec![]); + ensure_on_staking_updates_emitted(vec![]); + + // force unstake of a validator. + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 0)); + ensure_on_staking_updates_emitted(vec![ + ValidatorIdle { who: 11 }, + ValidatorRemove { who: 11 }, + Unstake { who: 11 }, + ]); + + // force unstake of a nominator. + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 101, 0)); + ensure_on_staking_updates_emitted(vec![ + NominatorRemove { who: 101, nominations: vec![11] }, + Unstake { who: 101 }, + ]); + }) + } + + #[test] + fn slash_emit_works() { + ExtBuilder::default().has_stakers(false).nominate(false).build_and_execute(|| { + // set stakers + bond_validator(11, 100); + bond_nominator(101, 100, vec![11]); + + // reset `OnStakingUpdate` events up to now. + EventsEmitted::set(vec![]); + ensure_on_staking_updates_emitted(vec![]); + + // progress a few eras and then slash 11. + start_active_era(5); + add_slash(&11); + + ensure_on_staking_updates_emitted(vec![ + // disabling/chilling validator at slash. + ValidatorIdle { who: 11 }, + Slash { who: 11, slashed_active: 90, slashed_total: 10 }, + // slash applied on the validator stake. + StakeUpdate { + who: 11, + prev_stake: Some(Stake { total: 100, active: 100 }), + stake: Stake { total: 90, active: 90 }, + }, + Slash { who: 101, slashed_active: 90, slashed_total: 10 }, + // slash applied on the nominator stake. + StakeUpdate { + who: 101, + prev_stake: Some(Stake { total: 100, active: 100 }), + stake: Stake { total: 90, active: 90 }, + }, + ]); + }) + } +} + mod ledger { use super::*; diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index e1ab87bef099..8cd908963371 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -36,3 +36,4 @@ std = [ "sp-std/std", ] runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] +test-utils = [] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 67dbb31cb430..69be25892fdb 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -153,6 +153,9 @@ pub trait OnStakingUpdate { /// Fired when someone removes their intention to validate, either due to chill or nominating. fn on_validator_remove(_who: &AccountId) {} + /// Fired when a portion of a staker's balance has been withdrawn. + fn on_withdraw(_stash: &AccountId, _amount: Balance) {} + /// Fired when someone is fully unstaked. fn on_unstake(_who: &AccountId) {} @@ -170,9 +173,65 @@ pub trait OnStakingUpdate { _slashed_total: Balance, ) { } +} - /// Fired when a portion of a staker's balance has been withdrawn. - fn on_withdraw(_stash: &AccountId, _amount: Balance) {} +/// Representation of the `OnStakingUpdate` events. +/// +/// Represents the events that may be emitted by the `OnStakingUpdate` trait, maps 1-1 to the +/// trait's method signatures. +/// +/// Only used for testing in external crates. +#[cfg(feature = "test-utils")] +#[derive(PartialEq, Clone, Debug)] +pub enum OnStakingUpdateEvent { + StakeUpdate { + who: AccountId, + prev_stake: Option>, + stake: Stake, + }, + NominatorAdd { + who: AccountId, + nominations: Vec, + }, + NominatorUpdate { + who: AccountId, + prev_nominations: Vec, + nominations: Vec, + }, + NominatorIdle { + who: AccountId, + prev_nominations: Vec, + }, + NominatorRemove { + who: AccountId, + nominations: Vec, + }, + ValidatorAdd { + who: AccountId, + self_stake: Option>, + }, + ValidatorUpdate { + who: AccountId, + self_stake: Option>, + }, + ValidatorIdle { + who: AccountId, + }, + ValidatorRemove { + who: AccountId, + }, + Withdraw { + who: AccountId, + amount: Balance, + }, + Unstake { + who: AccountId, + }, + Slash { + who: AccountId, + slashed_active: Balance, + slashed_total: Balance, + }, } /// A generic representation of a staking implementation. From 8c8d004e0da03ae9c4c31561d6855b780c29b112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 14 Feb 2024 00:03:50 +0100 Subject: [PATCH 073/133] updates comments; ensures that voter list is also always sorted + tests; PR reviews --- substrate/frame/staking/src/mock.rs | 58 ------------ substrate/frame/staking/src/pallet/mod.rs | 12 +-- substrate/frame/staking/src/tests.rs | 15 --- .../frame/staking/stake-tracker/Cargo.toml | 2 +- .../frame/staking/stake-tracker/src/lib.rs | 91 +++++++++---------- .../frame/staking/stake-tracker/src/mock.rs | 8 +- .../frame/staking/stake-tracker/src/tests.rs | 5 +- 7 files changed, 54 insertions(+), 137 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 49410c3e579a..9286c8e4965b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -1006,64 +1006,6 @@ pub(crate) fn ensure_on_staking_updates_emitted( EventsEmitted::set(vec![]); } -/// Similar to the try-state checks of the stake-tracker pallet, but works without `try-runtime` -/// feature enabled. -pub(crate) fn stake_tracker_sanity_tests() -> Result<(), &'static str> { - use sp_staking::StakingInterface; - - assert_eq!( - Nominators::::count() + Validators::::count(), - VoterBagsList::iter() - .filter(|v| Staking::status(&v) != Ok(StakerStatus::Idle)) - .count() as u32, - ); - - // recalculate the target's stake based on voter's nominations and compare with the score in the - // target list. - let mut map: BTreeMap = BTreeMap::new(); - for nominator in VoterBagsList::iter() { - if let Some(nominations) = ::nominations(&nominator) { - let score = >::get_score(&nominator) - .map_err(|_| "nominator score must exist in voter bags list")?; - - for nomination in nominations { - if let Some(stake) = map.get_mut(&nomination) { - *stake += score as u128; - } else { - map.insert(nomination, score.into()); - } - } - } - } - for target in TargetBagsList::iter() { - let score = >::get_score(&target) - .map_err(|_| "target score must exist in voter bags list")?; - if let Some(stake) = map.get_mut(&target) { - *stake += score as u128; - } else { - map.insert(target, score.into()); - } - } - - // compare final result with target list. - let mut valid_validators_count = 0; - for (target, stake) in map.into_iter() { - if let Ok(stake_in_list) = TargetBagsList::get_score(&target) { - assert_eq!( - stake, stake_in_list, - "target list score of {:?} is not correct. expected {:?}, got {:?}", - target, stake, stake_in_list - ); - valid_validators_count += 1; - } else { - // moot target nomination, do nothing. - } - } - assert_eq!(valid_validators_count, TargetBagsList::count() as usize); - - Ok(()) -} - pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(AccountId, Balance)>) { ( VoterBagsList::iter() diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index ff30de61e69f..30b3605b5a4d 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -223,8 +223,8 @@ pub mod pallet { /// After the threshold is reached a new era will be forced. type OffendingValidatorsThreshold: Get; - /// Something that provides a best-effort sorted list of voters (aka electing nominators), - /// used for NPoS election. + /// Something that provides a sorted list of voters (aka electing nominators), used for + /// NPoS election. /// /// The changes to nominators are reported to this. Moreover, each validator's self-vote is /// also reported as one independent vote. @@ -232,10 +232,6 @@ pub mod pallet { /// Voters will be removed from this list when their ledger is killed or the nominator is /// chilled. /// - /// To keep the load off the chain as much as possible, changes made to the staked amount - /// via rewards and slashes are not reported and thus need to be manually fixed by the - /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. - /// /// Invariant: what comes out of this list will always be an active nominator. type VoterList: SortedListProvider; @@ -250,10 +246,6 @@ pub mod pallet { /// 3. The nominations of a voter are updated. /// 4. A nominator or validator ledger is removed from the staking system. /// - /// Unlike `VoterList`, the values in this list are always kept up to date with both the - /// voter and target ledger's state at all the time (even upon rewards, slashes, etc) and - /// thus it represent an accurate approval stake of all target accounts in the system. - /// /// Chilled validators will *not* be removed from this list. Even when chilled, the target's /// approval voting must be kept up to date. In case a chilled validator re-validates their /// intention to be a validator again, their target score is up to date with the nominations diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index ee57ed5241b9..a0c01aaa7c90 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2512,7 +2512,6 @@ fn reporters_receive_their_slice() { ExtBuilder::default().build_and_execute(|| { // The reporters' reward is calculated from the total exposure. let initial_balance = 1375; - assert_ok!(stake_tracker_sanity_tests()); assert_eq!(Staking::eras_stakers(active_era(), &11).total, initial_balance); @@ -7564,9 +7563,6 @@ mod stake_tracker { ); assert_eq!(>::get_score(&1), Ok(300)); - // 11 has self-stake and nominated stake from 1, so total score is 400. - assert_ok!(stake_tracker_sanity_tests()); - // rebag in the target list happened as expected. assert_eq!( target_bags_events(), @@ -7582,7 +7578,6 @@ mod stake_tracker { // chill nominator 1. assert_ok!(Staking::chill(RuntimeOrigin::signed(1))); - assert_ok!(stake_tracker_sanity_tests()); // the target list is sorted by stake, similar to before nomination: [(12, 150), (11, // 100)] assert_eq!(voters_and_targets().1, [(12, 150), (11, 100)]); @@ -7618,8 +7613,6 @@ mod stake_tracker { assert_ok!(Staking::bond(RuntimeOrigin::signed(61), 500, RewardDestination::Staked)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![31])); - assert_ok!(stake_tracker_sanity_tests()); - let score_31 = >::score(&31); let self_stake_31 = Staking::ledger(Stash(31)).unwrap().active; let self_stake_61 = Staking::ledger(Stash(61)).unwrap().active; @@ -7639,7 +7632,6 @@ mod stake_tracker { // now we unbond a portion of the stake of 61. assert_ok!(Staking::unbond(RuntimeOrigin::signed(61), 250)); - assert_ok!(stake_tracker_sanity_tests()); // score of 61 was updated after unbonding. assert_eq!(>::score(&31), score_31 - 250); @@ -7672,7 +7664,6 @@ mod stake_tracker { ); // target list is sorted by score. - assert_ok!(stake_tracker_sanity_tests()); assert_eq!( voters_and_targets().1, [(11, 1500), (21, 1500), (31, own_stake + other_stake)] @@ -7868,8 +7859,6 @@ mod stake_tracker { BagsEvent::ScoreUpdated { who: 21, new_score: 1000 } ] ); - - assert_ok!(stake_tracker_sanity_tests()); }) } @@ -7908,9 +7897,6 @@ mod stake_tracker { // stake of nominator 101 increased since it was exposed to payout. assert!(Staking::ledger(Stash(101)).unwrap().active > stake_101_before); - // current bags list, nominators and validators state are OK. - assert_ok!(stake_tracker_sanity_tests()); - // overview of the target list is as expected: 11 and 21 have increased the score after // the payout as they were directly and indirectly exposed to the payout. assert_eq!(voters_and_targets().1, [(11, 12575), (21, 4520), (31, 500)]); @@ -7949,7 +7935,6 @@ mod stake_tracker { // checks the current targets' score and list sorting. assert_eq!(voters_and_targets().1, [(21, 2050), (11, 2050), (31, 500)]); - assert_ok!(stake_tracker_sanity_tests()); // get the bonded stake of the nominators that will be affected by the slash. let stake_101_before = Staking::ledger(Stash(101)).unwrap().active; diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 660736253b70..c7b930146ed9 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -32,7 +32,7 @@ sp-core = { default-features = false, path = "../../../primitives/core" } sp-io = { default-features = false, path = "../../../primitives/io" } sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } sp-tracing = { default-features = false, path = "../../../primitives/tracing" } -pallet-bags-list = { default-features = false, path = "../../bags-list" } +pallet-bags-list = { default-features = false, path = "../../bags-list", features = ["try-runtime"] } pallet-balances = { default-features = false, path = "../../balances" } [features] diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 5bfad6930bcd..1625e48a3057 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -25,8 +25,9 @@ //! The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] //! trait and, based on those events, ensures that the score of nodes in the lists //! [`Config::VoterList`] and [`Config::TargetList`] are kept up to date with the staker's bonds -//! and nominations in the system. In addition, the pallet also ensures that [`Config::TargetList`] -//! is *strictly sorted* based on the targets' approvals. +//! and nominations in the system. In addition, the pallet also ensures that both the +//! [`Config::TargetList`] and [`Config::VoterList`] are *strictly sorted* by +//! [`SortedListProvider::Score`]. //! //! ## Goals //! @@ -34,25 +35,26 @@ //! //! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals //! (which include self-vote and nominations' stake). -//! * The [`Config::VoterList`] keeps a semi-sorted list of voters, loosely sorted by bonded stake. -//! This pallet does nothing to ensure that the voter list sorting is correct. +//! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new //! nomination updates, nominator/validator slashes and rewards. This pallet *must* ensure that the -//! scores of the targets are always up to date *and* the targets are sorted by score at all time. +//! scores of the targets and voters are always up to date and thus, that the targets and voters in +//! the lists are sorted by score at all time. //! //! Note that from the POV of this pallet, all events will result in one or multiple updates to //! [`Config::VoterList`] and/or [`Config::TargetList`] state. If a set of staking updates require -//! too much weight to process (e.g. at nominator's rewards payout or at nominator's slashes), the -//! event emitter should handle that in some way (e.g. buffering events and implementing a -//! multi-block event emitter). +//! too much weight to execute (e.g. at nominator's rewards payout or at slashes), the event emitter +//! should handle that in some way (e.g. buffering events and implementing a multi-block event +//! emitter). //! //! ## Staker status and list invariants //! -//! There are a few list invariants that depend on the staker's (nominator or validator) state, as +//! There are a few invariants that depend on the staker's (nominator or validator) state, as //! exposed by the [`Config::Staking`] interface: //! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the -//! voter list's score. +//! voter list's score. In addition, the voters' scores are up to date with the current stake +//! returned by [`T::Staking::stake`]. //! * A [`sp_staking::StakerStatus::Validator`] is part of both voter and target list. And its //! approvals score (nominations + self-stake) is kept up to date as the target list's score. //! * A [`sp_staking::StakerStatus::Idle`] may have a target list's score while other stakers @@ -66,16 +68,6 @@ //! For further details on the target list invariantes, refer to [`Self`::do_try_state_approvals`] //! and [`Self::do_try_state_target_sorting`]. //! -//! ## Domain-specific consideration on [`Config::VoterList`] and [`Config::TargetList`] -//! -//! In the context of Polkadot's staking system, both the voter and target lists will be implemented -//! by a bags-list pallet, which implements the -//! [`frame_election_provider_support::SortedListProvider`] trait. -//! -//! Note that the score provider of the target's bags-list is the list itself. This, coupled with -//! the fact that the target list sorting must be always up to date, makes this pallet resposible -//! for ensuring that the score of the targets in the `TargetList` is *always* kept up to date. -//! //! ## Event emitter ordering and staking ledger state updates //! //! It is important to ensure that the events are emitted from staking (i.e. the calls into @@ -171,18 +163,10 @@ pub mod pallet { /// The staking interface. type Staking: StakingInterface; - /// Something that provides a *best-effort* sorted list of voters. - /// - /// To keep the load off the chain as much as possible, changes made to the staked amount - /// via rewards and slashes are dropped and thus need to be manually updated through - /// extrinsics. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. + /// Something that provides an *always* sorted list of voters. type VoterList: SortedListProvider; - /// Something that provides an *always* sorted list of targets. - /// - /// This pallet is responsible to keep the score and sorting of this pallet up to date with - /// the correct approvals stakes of every target that is bouded or it has been bonded in the - /// past *and* it still has nominations from active voters. + /// Something that provides an *always* sorted list of targets by their approval stake. type TargetList: SortedListProvider< Self::AccountId, Score = ::Balance, @@ -398,11 +382,14 @@ impl Pallet { /// /// 1. `do_try_state_approvals`: checks the curent approval stake in the target list compared /// with the staking state. - /// 2. `do_try_state_target_sorting`: checks if the target list is sorted by score. + /// 2. `do_try_state_target_sorting`: checks if the target list is sorted by score (approvals). + /// 3. `do_try_state_voter_sorting`: checks if the voter list is sorted by score (stake). pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - #[cfg(feature = "try-runtime")] + Self::do_try_state_approvals()?; Self::do_try_state_target_sorting()?; - Self::do_try_state_approvals() + Self::do_try_state_voter_sorting()?; + + Ok(()) } /// Try-state: checks if the approvals stake of the targets in the target list are correct. @@ -563,13 +550,12 @@ impl Pallet { /// Try-state: checks if targets in the target list are sorted by score. /// /// Invariant - /// * All targets in the target list are sorted by their score. + /// * All targets in the target list are sorted by their score (approvals). /// /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the /// correct position in the list (bag or otherwise), given its score. - #[cfg(feature = "try-runtime")] pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { for t in T::TargetList::iter() { frame_support::ensure!( @@ -578,9 +564,22 @@ impl Pallet { ); } - for v in T::VoterList::iter() { + Ok(()) + } + + /// Try-state: checks if voters in the voter list are sorted by score (stake). + /// + /// Invariant + /// * All voters in the voter list are sorted by their score. + /// + /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if + /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we + /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the + /// correct position in the list (bag or otherwise), given its score. + pub fn do_try_state_voter_sorting() -> Result<(), sp_runtime::TryRuntimeError> { + for t in T::VoterList::iter() { frame_support::ensure!( - T::VoterList::in_position(&v).expect("voter exists"), + T::VoterList::in_position(&t).expect("voter exists"), "voter list is not sorted" ); } @@ -709,7 +708,8 @@ impl OnStakingUpdate> for Pallet { // remove from target list IIF score is zero. if T::TargetList::get_score(who).unwrap_or_default().is_zero() { - T::TargetList::on_remove(who).expect("target exists as per the check above; qed."); + let _ = T::TargetList::on_remove(who) + .defensive_proof("target exists as per the check above; qed."); } } @@ -718,13 +718,9 @@ impl OnStakingUpdate> for Pallet { fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { let nominator_vote = Self::weight_of(Self::active_vote_of(who)); - // voter may exist in the list in case of re-enabling a chilled nominator; - if T::VoterList::contains(who) { - return - } - - let _ = T::VoterList::on_insert(who.clone(), nominator_vote) - .defensive_proof("staker does not exist in the list as per check above; qed."); + let _ = T::VoterList::on_insert(who.clone(), nominator_vote).defensive_proof( + "the nominator must not exist in the list as per the contract with staking.", + ); // If who is a nominator, update the vote weight of the nominations if they exist. Note: // this will update the score of up to `T::MaxNominations` validators. @@ -769,8 +765,9 @@ impl OnStakingUpdate> for Pallet { Self::update_target_score(t, StakeImbalance::Negative(nominator_vote.into())) } - let _ = T::VoterList::on_remove(who) - .defensive_proof("the nominator exists in the list as per the contract with staking."); + let _ = T::VoterList::on_remove(who).defensive_proof( + "the nominator must exist in the list as per the contract with staking.", + ); } /// This is called when a nominator updates their nominations. The nominator's stake remains diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 0cbd41dc5b57..f3316cb255c1 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -34,10 +34,10 @@ frame_support::construct_runtime!( pub enum Test { System: frame_system, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, - TargetBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, - StakeTracker: crate, + Balances: pallet_balances, + VoterBagsList: pallet_bags_list::, + TargetBagsList: pallet_bags_list::, + StakeTracker: pallet_stake_tracker, } ); diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 3b0323a9a5c8..f203b0717e36 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -289,7 +289,8 @@ fn on_validator_add_works() { } #[test] -fn on_nominator_add_already_exists_works() { +#[should_panic = "Defensive failure has been triggered!: Duplicate: \"the nominator must not exist in the list as per the contract with staking.\""] +fn on_nominator_add_already_exists_defensive_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::count(), 4); @@ -358,7 +359,7 @@ fn on_nominator_remove_works() { } #[test] -#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the nominator exists in the list as per the contract with staking.\""] +#[should_panic = "Defensive failure has been triggered!: NodeNotFound: \"the nominator must exist in the list as per the contract with staking.\""] fn on_nominator_remove_defensive_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { assert!(VoterBagsList::contains(&1)); From 639edafc7f6197e068de6f4feb6fd205e15e454b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 15 Feb 2024 20:44:35 +0100 Subject: [PATCH 074/133] nits and address comments --- substrate/frame/staking/src/ledger.rs | 17 ++++----- substrate/frame/staking/src/pallet/impls.rs | 36 ++++++++++--------- .../frame/staking/stake-tracker/src/lib.rs | 7 ++-- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 3ff07d855703..1d422ed44436 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -42,12 +42,6 @@ use crate::{ BalanceOf, Bonded, Config, Error, Ledger, Payee, RewardDestination, StakingLedger, STAKING_ID, }; -impl Into>> for StakingLedger { - fn into(self) -> Stake> { - Stake { total: self.total, active: self.active } - } -} - impl StakingLedger { #[cfg(any(feature = "runtime-benchmarks", test))] pub fn default_from(stash: T::AccountId) -> Self { @@ -81,6 +75,10 @@ impl StakingLedger { } } + pub fn stake(&self) -> Stake> { + Stake { total: self.total, active: self.active } + } + /// Returns the paired account, if any. /// /// A "pair" refers to the tuple (stash, controller). If the input is a @@ -179,16 +177,13 @@ impl StakingLedger { })?; // previous stake is the current stake in storage. - let prev_stake: Option> = match Ledger::::get(&controller) { - Some(current_ledger) => Some(current_ledger.into()), - None => None, - }; + let prev_stake = Ledger::::get(&controller).map(|ledger| ledger.stake()); T::Currency::set_lock(STAKING_ID, &self.stash, self.total, WithdrawReasons::all()); Ledger::::insert(controller, &self); // fire `on_stake_update` if there was a stake update. - let new_stake: Stake<_> = self.clone().into(); + let new_stake: Stake<_> = self.stake(); if new_stake != prev_stake.unwrap_or_default() { T::EventListeners::on_stake_update(&self.stash, prev_stake, new_stake); } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 017c24469589..1db07fd6479b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -957,9 +957,10 @@ impl Pallet { // target list may contain chilled validators and dangling (i.e. unbonded) targets, filter // those. - let mut targets_iter = T::TargetList::iter() - .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) - .filter(|t| !Self::status(&t).is_err()); + let mut targets_iter = T::TargetList::iter().filter(|t| match Self::status(&t) { + Ok(StakerStatus::Idle) | Err(_) => false, + Ok(_) => true, + }); while all_targets.len() < final_predicted_len as usize && targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) @@ -1007,15 +1008,15 @@ impl Pallet { Nominators::::insert(who, nominations); T::EventListeners::on_nominator_add(who, nomination_accounts); }, + (true, false) => { + defensive!("unexpected state."); + }, (_, true) => { // update nominations or un-chill nominator. let prev_nominations = Self::nominations(who).unwrap_or_default(); Nominators::::insert(who, nominations); T::EventListeners::on_nominator_update(who, prev_nominations, nomination_accounts); }, - (true, false) => { - defensive!("unexpected state."); - }, }; debug_assert_eq!( @@ -1030,6 +1031,8 @@ impl Pallet { /// /// A chilled nominator is removed from the `Nominators` map, and the nominator's new state must /// be signalled to [`T::EventListeners`]. + /// + /// Returns `true` if the nominator was successfully chilled, `false` otherwise. pub(crate) fn do_chill_nominator(who: &T::AccountId) -> bool { Nominators::::take(who).map_or(false, |nominations| { T::EventListeners::on_nominator_remove(who, nominations.clone().targets.into()); @@ -1046,10 +1049,8 @@ impl Pallet { /// to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { let outcome = match Self::status(who) { - Ok(StakerStatus::Nominator(_)) | Ok(StakerStatus::Validator) => { - let outcome = Self::do_chill_nominator(who); - outcome - }, + Ok(StakerStatus::Nominator(_)) | Ok(StakerStatus::Validator) => + Self::do_chill_nominator(who), // not an active nominator, do nothing. Err(_) | Ok(StakerStatus::Idle) => false, }; @@ -1092,14 +1093,15 @@ impl Pallet { /// Tries to chill a validator. /// /// A chilled validator is removed from the `Validators` map. + /// + /// Returns `true` if the validator was successfully chilled, `false` otherwise. pub(crate) fn do_chill_validator(who: &T::AccountId) -> bool { - match Validators::::contains_key(who) { - true => { - Validators::::remove(who); - T::EventListeners::on_validator_idle(who); - true - }, - false => false, + if Validators::::contains_key(who) { + Validators::::remove(who); + T::EventListeners::on_validator_idle(who); + true + } else { + false } } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 1625e48a3057..2e2be4f6c477 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -690,7 +690,7 @@ impl OnStakingUpdate> for Pallet { /// removed from the target list IFF its score is 0. Otherwise, its score should be kept up to /// date as if the validator was active. fn on_validator_remove(who: &T::AccountId) { - log!(debug, "on_validator_remove: {:?}", who,); + log!(debug, "on_validator_remove: {:?} with status {:?}", who, T::Staking::status(who)); // validator must be idle before removing completely. match T::Staking::status(who) { @@ -706,10 +706,11 @@ impl OnStakingUpdate> for Pallet { }, }; - // remove from target list IIF score is zero. + // remove from target list IIF score is zero. If `score != 0`, the target still has active + // nominations, thus we keep it in the target list with corresponding approval stake. if T::TargetList::get_score(who).unwrap_or_default().is_zero() { let _ = T::TargetList::on_remove(who) - .defensive_proof("target exists as per the check above; qed."); + .defensive_proof("target exists as the target score exists; qed."); } } From 9af11229f6e808fde4b8f442d46d3cd7fa1199ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 15 Feb 2024 21:22:23 +0100 Subject: [PATCH 075/133] defensive instead of err in case of killing a stash that is not Idle --- substrate/frame/staking/src/ledger.rs | 7 +++++-- substrate/frame/staking/src/tests.rs | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 1d422ed44436..b41a861c2337 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -32,7 +32,7 @@ //! state consistency. use frame_support::{ - defensive, ensure, + defensive, traits::{LockableCurrency, WithdrawReasons}, }; use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingAccount, StakingInterface}; @@ -227,7 +227,10 @@ impl StakingLedger { pub(crate) fn kill(stash: &T::AccountId) -> Result<(), Error> { let controller = >::get(stash).ok_or(Error::::NotStash)?; - ensure!(crate::Pallet::::status(stash) == Ok(StakerStatus::Idle), Error::::BadState); + debug_assert!( + crate::Pallet::::status(stash) == Ok(StakerStatus::Idle), + "ledger being killed before set as Idle" + ); >::get(&controller).ok_or(Error::::NotController).map(|ledger| { T::Currency::remove_lock(STAKING_ID, &ledger.stash); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a0c01aaa7c90..84d3f35d2169 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -141,12 +141,14 @@ fn kill_stash_works() { } #[test] +#[should_panic = "ledger being killed before set as Idle"] fn kill_ledger_preconditions_works() { ExtBuilder::default().build_and_execute(|| { // Account 11 (also controller) is stashed and locked assert_eq!(Staking::bonded(&11), Some(11)); - // Trying to call `Ledger::kill` directly will fail. - assert!(StakingLedger::::kill(&11).is_err()); + // Trying to call `Ledger::kill` directly without chilling the staker before go through but + // raise alert. + assert!(StakingLedger::::kill(&11).is_ok()); }) } From 7dd813b085c4eddaf53ecbc1669da76cc2dd2ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 16 Feb 2024 11:37:07 +0100 Subject: [PATCH 076/133] Adds stake-tracker benchs --- Cargo.lock | 1 + polkadot/runtime/westend/src/lib.rs | 1 + substrate/bin/node/runtime/src/lib.rs | 1 + .../frame/staking/stake-tracker/Cargo.toml | 6 ++ .../staking/stake-tracker/src/benchmarking.rs | 59 +++++++++++++++++++ .../frame/staking/stake-tracker/src/lib.rs | 6 +- 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 substrate/frame/staking/stake-tracker/src/benchmarking.rs diff --git a/Cargo.lock b/Cargo.lock index 9e3c32fac1a1..a7aa14361911 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10800,6 +10800,7 @@ dependencies = [ name = "pallet-stake-tracker" version = "0.1.0" dependencies = [ + "frame-benchmarking", "frame-election-provider-support", "frame-support", "frame-system", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 2fdf6a00293d..07f11aa0037c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1743,6 +1743,7 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] + [pallet_stake_tracker, StakeTracker] [pallet_sudo, Sudo] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d91efa5691bf..bb78e40915e5 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2408,6 +2408,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_society, Society] [pallet_staking, Staking] + [pallet_stake_tracker, StakeTracker] [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index c7b930146ed9..cd694293d150 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -26,6 +26,9 @@ frame-system = { default-features = false, path = "../../system" } log = { version = "0.4.17", default-features = false } +# Optional imports for benchmarking +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } + [dev-dependencies] sp-std = { default-features = false, path = "../../../primitives/std" } sp-core = { default-features = false, path = "../../../primitives/core" } @@ -34,12 +37,14 @@ sp-runtime = { default-features = false, path = "../../../primitives/runtime", f sp-tracing = { default-features = false, path = "../../../primitives/tracing" } pallet-bags-list = { default-features = false, path = "../../bags-list", features = ["try-runtime"] } pallet-balances = { default-features = false, path = "../../balances" } +frame-benchmarking = { path = "../../benchmarking" } [features] default = ["std"] std = [ "codec/std", + "frame-benchmarking?/std", "frame-election-provider-support/std", "frame-support/std", "frame-system/std", @@ -58,6 +63,7 @@ std = [ ] runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", "frame-election-provider-support/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/substrate/frame/staking/stake-tracker/src/benchmarking.rs b/substrate/frame/staking/stake-tracker/src/benchmarking.rs new file mode 100644 index 000000000000..fec33c8107e5 --- /dev/null +++ b/substrate/frame/staking/stake-tracker/src/benchmarking.rs @@ -0,0 +1,59 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! StakeTracker pallet benchmarking. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{mock::add_dangling_target_with_nominators, *}; +pub use frame_benchmarking::v1::{ + account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, +}; +use frame_system::RawOrigin; + +const SEED: u32 = 0; + +// returns the target and voter account IDs. +fn add_dangling_target() -> (T::AccountId, T::AccountId) { + let target = account("target", 0, SEED); + let voter = account("voter", 0, SEED); + + add_dangling_target_with_nominators(target, vec![voter]); + + (target, voter) +} + +benchmarks! { + drop_dangling_nomination { + let caller = account("caller", 0, SEED); + whitelist_account!(caller); + + let (target, voter) = add_dangling_target::(); + + }: _(RawOrigin::Signed(caller), voter, target) + verify { + // voter is not nominating validator anymore + // target is not in the target list + } + + impl_benchmark_test_suite!( + StakeTracker, + crate::mock::ExtBuilder::default(), + crate::mock::Test, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 2e2be4f6c477..4405d240d44e 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -89,8 +89,10 @@ use sp_staking::{ }; use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; -#[cfg(test)] -mod mock; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; +#[cfg(any(feature = "runtime-benchmarks", test))] +pub(crate) mod mock; #[cfg(test)] mod tests; From ab802b5b9a960f39fbe2e02d8e6ac7907a77ca2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 19 Feb 2024 22:44:36 +0100 Subject: [PATCH 077/133] Removes the need for staking to check the state of the target and voter list --- substrate/frame/staking/src/pallet/impls.rs | 60 +++++++++---------- substrate/frame/staking/src/tests.rs | 1 + .../frame/staking/stake-tracker/src/lib.rs | 19 +++--- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 2f367668313a..cd1b583c9bf9 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -729,8 +729,24 @@ impl Pallet { slashing::clear_stash_metadata::(&stash, num_slashing_spans)?; // note: these must be called *before* cleaning up the staking ledger storage with fn kill. - Self::do_remove_validator(&stash); - Self::do_remove_nominator(&stash); + match Self::status(stash) { + Ok(StakerStatus::Validator) => { + // validator is both a nominator and validator. + Self::do_remove_validator(&stash); + Self::do_remove_nominator(&stash); + }, + Ok(StakerStatus::Nominator(_)) => { + Self::do_remove_nominator(&stash); + }, + Ok(StakerStatus::Idle) => { + // we keep track of chilled (`Idle`) validators in the TargetList as well, so we + // may need to remove them. + Self::do_remove_validator(&stash); + }, + Err(_) => { + // do nothing; it will fail below when trying to kill the stash. + }, + } // and finally, it removes controller from `Bonded` and staking ledger from `Ledger`, as // well as reward setting of the stash in `Payee`. @@ -1011,22 +1027,21 @@ impl Pallet { pub fn do_add_nominator(who: &T::AccountId, nominations: Nominations) { let nomination_accounts = nominations.targets.to_vec(); - match (Nominators::::contains_key(who), T::VoterList::contains(who)) { - (false, false) => { + match Self::status(who) { + Ok(StakerStatus::Idle) => { // new nomination Nominators::::insert(who, nominations); T::EventListeners::on_nominator_add(who, nomination_accounts); }, - (true, false) => { - defensive!("unexpected state."); - }, - (_, true) => { + Ok(StakerStatus::Nominator(prev_nominations)) => { // update nominations or un-chill nominator. - let prev_nominations = Self::nominations(who).unwrap_or_default(); Nominators::::insert(who, nominations); T::EventListeners::on_nominator_update(who, prev_nominations, nomination_accounts); }, - }; + _ => { + defensive!("calling add_nominator on a validator or unbonded stash."); + }, + } debug_assert_eq!( Nominators::::count() + Validators::::count(), @@ -1057,12 +1072,7 @@ impl Pallet { /// NOTE: you must ALWAYS use this function to remove a nominator from the system. Any access /// to `Nominators` or `VoterList` outside of this function is almost certainly wrong. pub fn do_remove_nominator(who: &T::AccountId) -> bool { - let outcome = match Self::status(who) { - Ok(StakerStatus::Nominator(_)) | Ok(StakerStatus::Validator) => - Self::do_chill_nominator(who), - // not an active nominator, do nothing. - Err(_) | Ok(StakerStatus::Idle) => false, - }; + let outcome = Self::do_chill_nominator(who); debug_assert_eq!( Nominators::::count() + Validators::::count(), @@ -1122,22 +1132,8 @@ impl Pallet { /// `Validators` or `VoterList` outside of this function is almost certainly /// wrong. pub fn do_remove_validator(who: &T::AccountId) -> bool { - let outcome = match Self::status(who) { - Ok(StakerStatus::Validator) => { - // make sure the validator is chilled before removing it. - let outcome = Self::do_chill_validator(who); - T::EventListeners::on_validator_remove(who); - outcome - }, - Ok(StakerStatus::Idle) | Err(_) if T::TargetList::contains(who) => { - // try to remove "dangling" target. A dangling target does not have a bonded stash - // but is still part of the target list because a previously removed stash still has - // nominations from active nominators. - T::EventListeners::on_validator_remove(who); - false - }, - _ => false, - }; + let outcome = Self::do_chill_validator(who); + T::EventListeners::on_validator_remove(who); debug_assert_eq!( Nominators::::count() + Validators::::count(), diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index edb429fc6967..35ec6ba9f3f2 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7114,6 +7114,7 @@ mod on_staking_update_events { // 21 withdraws all unlocked funds to kill the stash/ unstake. assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(21), 0)); ensure_on_staking_updates_emitted(vec![ + ValidatorRemove { who: 21 }, Unstake { who: 21 }, Withdraw { who: 21, amount: 100 }, ]); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 4405d240d44e..e3cc6475f8b7 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -694,7 +694,7 @@ impl OnStakingUpdate> for Pallet { fn on_validator_remove(who: &T::AccountId) { log!(debug, "on_validator_remove: {:?} with status {:?}", who, T::Staking::status(who)); - // validator must be idle before removing completely. + // validator must be idle before removing completely. Perform some sanity checks too. match T::Staking::status(who) { Ok(StakerStatus::Idle) => (), // proceed Ok(StakerStatus::Validator) => Self::on_validator_idle(who), @@ -708,12 +708,17 @@ impl OnStakingUpdate> for Pallet { }, }; - // remove from target list IIF score is zero. If `score != 0`, the target still has active - // nominations, thus we keep it in the target list with corresponding approval stake. - if T::TargetList::get_score(who).unwrap_or_default().is_zero() { - let _ = T::TargetList::on_remove(who) - .defensive_proof("target exists as the target score exists; qed."); - } + if let Ok(score) = T::TargetList::get_score(who) { + // remove from target list IIF score is zero. If `score != 0`, the target still has + // active nominations, thus we keep it in the target list with corresponding approval + // stake. + if score.is_zero() { + let _ = T::TargetList::on_remove(who).expect("target exists as per above; qed"); + } + } else { + // target is not part of the list. Given the contract with staking and the checks above, + // this may actually be called. So do nothing and skip defensive warns. + }; } /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is From 12fce2431b60c930cf1c8a6956ad37a81e71c82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 19 Feb 2024 23:16:10 +0100 Subject: [PATCH 078/133] cargo-clippy fix --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index e3cc6475f8b7..59f2a5390d95 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -713,7 +713,7 @@ impl OnStakingUpdate> for Pallet { // active nominations, thus we keep it in the target list with corresponding approval // stake. if score.is_zero() { - let _ = T::TargetList::on_remove(who).expect("target exists as per above; qed"); + T::TargetList::on_remove(who).expect("target exists as per above; qed"); } } else { // target is not part of the list. Given the contract with staking and the checks above, From afeddd25cd78d9aae85845eed3f252228df16f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 15 Apr 2024 23:27:42 +0100 Subject: [PATCH 079/133] Update substrate/frame/staking/stake-tracker/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 59f2a5390d95..c7cd4d5a2ae6 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -217,7 +217,7 @@ pub mod pallet { /// * The `target` is unbonded and it exists in the target list. /// * The `voter` is nominating `target`. /// - /// Emits `DanglingNominationDropped`. + /// Emits [`Event::DanglingNominationDropped`]. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::drop_dangling_nomination())] pub fn drop_dangling_nomination( From 56ecb62b54444bd5ba816f54e1246abd6cba00a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 19 Apr 2024 18:35:37 +0200 Subject: [PATCH 080/133] starts adding mmb for target list --- Cargo.lock | 1 + substrate/frame/staking/Cargo.toml | 4 + substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/migrations/mod.rs | 25 +++++ .../single_block.rs} | 11 +- .../v13_stake_tracker/benchmarks.rs | 51 +++++++++ .../src/migrations/v13_stake_tracker/mod.rs | 102 ++++++++++++++++++ .../src/migrations/v13_stake_tracker/tests.rs | 60 +++++++++++ .../migrations/v13_stake_tracker/weights.rs | 36 +++++++ substrate/frame/staking/src/mock.rs | 35 +++++- .../frame/staking/stake-tracker/src/lib.rs | 4 +- substrate/primitives/staking/src/lib.rs | 6 ++ 12 files changed, 326 insertions(+), 11 deletions(-) create mode 100644 substrate/frame/staking/src/migrations/mod.rs rename substrate/frame/staking/src/{migrations.rs => migrations/single_block.rs} (97%) create mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs create mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs create mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs create mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs diff --git a/Cargo.lock b/Cargo.lock index e6b32b238049..615ae01d5acd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11427,6 +11427,7 @@ dependencies = [ "pallet-authorship", "pallet-bags-list", "pallet-balances", + "pallet-migrations", "pallet-session", "pallet-stake-tracker", "pallet-staking-reward-curve", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 4832b91052e6..fce8156bce9c 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -48,6 +48,7 @@ pallet-timestamp = { path = "../timestamp" } pallet-stake-tracker = { path = "./stake-tracker" } pallet-staking-reward-curve = { path = "reward-curve" } pallet-bags-list = { path = "../bags-list" } +pallet-migrations = { path = "../migrations" } substrate-test-utils = { path = "../../test-utils" } frame-benchmarking = { path = "../benchmarking" } frame-election-provider-support = { path = "../election-provider-support" } @@ -66,6 +67,7 @@ std = [ "pallet-authorship/std", "pallet-bags-list/std", "pallet-balances/std", + "pallet-migrations/std", "pallet-session/std", "pallet-stake-tracker/std", "pallet-timestamp/std", @@ -87,6 +89,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-stake-tracker/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", @@ -100,6 +103,7 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", + "pallet-migrations/try-runtime", "pallet-session/try-runtime", "pallet-stake-tracker/try-runtime", "pallet-timestamp/try-runtime", diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 484b66a04a14..822db2b1e874 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -291,7 +291,7 @@ pub mod benchmarking; pub mod testing_utils; #[cfg(test)] -pub(crate) mod mock; +pub mod mock; #[cfg(test)] mod tests; diff --git a/substrate/frame/staking/src/migrations/mod.rs b/substrate/frame/staking/src/migrations/mod.rs new file mode 100644 index 000000000000..0ce27b99d8e1 --- /dev/null +++ b/substrate/frame/staking/src/migrations/mod.rs @@ -0,0 +1,25 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Single-block migrations. +pub mod single_block; + +/// v13 MMB stake-tracker migrations. +pub mod v13_stake_tracker; + +/// The unique identifier for the pallet-staking MMBs +pub const PALLET_MIGRATIONS_ID: &[u8; 18] = b"pallet-staking-mmb"; diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations/single_block.rs similarity index 97% rename from substrate/frame/staking/src/migrations.rs rename to substrate/frame/staking/src/migrations/single_block.rs index d5b18421d5b6..76d70ebca327 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations/single_block.rs @@ -14,16 +14,21 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -//! Storage migrations for the Staking pallet. The changelog for this is maintained at +//! Single-block storage migrations for the Staking pallet. The changelog for this is maintained at //! [CHANGELOG.md](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/staking/CHANGELOG.md). -use super::*; +use crate::{log, slashing, Config, EraIndex, Nominators, Pallet, UnappliedSlashes, Validators}; use frame_election_provider_support::SortedListProvider; use frame_support::{ - pallet_prelude::ValueQuery, + pallet_prelude::{Get, ValueQuery}, storage_alias, traits::{GetStorageVersion, OnRuntimeUpgrade}, + weights::Weight, }; +use sp_runtime::{traits::Zero, RuntimeDebug}; + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; #[cfg(feature = "try-runtime")] use frame_support::ensure; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs new file mode 100644 index 000000000000..54e846c6f2f9 --- /dev/null +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs @@ -0,0 +1,51 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and + +//! Benchmark the v13 multi-block-migrations + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{ + migrations::{v13_stake_tracker, v13_stake_tracker::*}, + Config, Pallet, +}; +use frame_benchmarking::v2::*; +use frame_support::{migrations::SteppedMigration, weights::WeightMeter}; + +#[benchmarks] +mod benches { + use super::*; + + /// Benchmark a simple step of the v13 multi-block migration. + #[benchmark] + fn step() { + let mut meter = WeightMeter::new(); + + #[block] + { + v13_stake_tracker::MigrationV13::>::step(None, &mut meter).unwrap(); + } + + // TODO: after benchmarks sanity checks. + } + + impl_benchmark_test_suite!( + Staking, + crate::mock::ExtBuilder::default().has_stakers(true), + crate::mock::Test, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs new file mode 100644 index 000000000000..c98e1e20a343 --- /dev/null +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -0,0 +1,102 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and + +//! # Multi-Block Migration v13 +//! +//! Implements the multi-block migrations to support the `pallet-stake-tracker` and a strictly +//! sorted list of targets with a bags-list. + +use core::marker::PhantomData; + +use frame_support::{ + migrations::{MigrationId, SteppedMigration}, + traits::Defensive, +}; + +use super::PALLET_MIGRATIONS_ID; +use crate::{log, BalanceOf, Config, Nominators, Pallet, Validators}; +use frame_election_provider_support::SortedListProvider; +use sp_runtime::Saturating; +use sp_staking::StakingInterface; + +mod benchmarks; +#[cfg(test)] +mod tests; +pub mod weights; + +pub struct MigrationV13(PhantomData<(T, W)>); +impl SteppedMigration for MigrationV13 { + type Cursor = T::AccountId; + type Identifier = MigrationId<18>; + + /// Identifier of this migration which should be globally unique. + fn id() -> Self::Identifier { + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 12, version_to: 13 } + } + + fn step( + mut cursor: Option, + meter: &mut frame_support::weights::WeightMeter, + ) -> Result, frame_support::migrations::SteppedMigrationError> { + let required = W::step(); + + // If there's no enough weight left in the block for a migration step, return an error. + if meter.remaining().any_lt(required) { + return Err(frame_support::migrations::SteppedMigrationError::InsufficientWeight { + required, + }); + } + + // Do as much progress as possible per step. + while meter.try_consume(required).is_ok() { + // 1. get next validator in the Validators map. + let mut iter = if let Some(ref last_val) = cursor { + Validators::::iter_from(Validators::::hashed_key_for(last_val)) + } else { + // first step, start from beginning of the validator's map. + Validators::::iter() + }; + + if let Some((target, _)) = iter.next() { + log!( + info, + "multi-block migrations: processing target {:?}. remaining {} targets to migrate.", + target, + iter.count()); + + // 2. calculate target's stake which consits of self-stake + all of its nominator's + // stake. + let self_stake = Pallet::::stake(&target).defensive_unwrap_or_default().total; + + let total_stake = Nominators::::iter() + .filter(|(_v, noms)| noms.targets.contains(&target)) + .map(|(v, _)| Pallet::::stake(&v).defensive_unwrap_or_default()) + .fold(self_stake, |sum: BalanceOf, stake| stake.total.saturating_add(sum)); + + // 3. insert (validator, score = total_stake) to the target bags list. + let _ = T::TargetList::on_insert(target.clone(), total_stake).defensive(); + + // 4. progress cursor. + cursor = Some(target) + } else { + // done, return earlier. + return Ok(None) + } + } + + Ok(cursor) + } +} diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs new file mode 100644 index 000000000000..729ba574f3c9 --- /dev/null +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -0,0 +1,60 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and + +use crate::{ + migrations::v13_stake_tracker::weights::{SubstrateWeight, WeightInfo as _}, + mock::{ + clear_target_list, run_to_block, AllPalletsWithSystem, ExtBuilder, MigratorServiceWeight, + Staking, System, Test as T, TargetBagsList, + }, + Validators, +}; +use frame_support::traits::OnRuntimeUpgrade; +use frame_election_provider_support::SortedListProvider; +use pallet_migrations::WeightInfo as _; + +#[test] +fn mb_migration_target_list_simple_works() { + ExtBuilder::default().build_and_execute(|| { + // simulates an empty target list which is the case before the migrations. + clear_target_list(); + // try state fails since the target list count != number of validators. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // Give it enough weight to do 2 target migrations per block. + let limit = ::WeightInfo::progress_mbms_none() + + pallet_migrations::Pallet::::exec_migration_max_weight() + + SubstrateWeight::::step() * 2; + MigratorServiceWeight::set(&limit); + + // start stepped migrations. + System::set_block_number(1); + AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs + + // 1 step, should migrate 2 targets. + run_to_block(2); + assert_eq!(TargetBagsList::iter().count(), 2); + // migration not completed yet, the one target missing. + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // next step completes migration. + run_to_block(3); + assert_eq!(TargetBagsList::iter().count() as u32, Validators::::count()); + + // migration done, try state checks pass. + assert!(Staking::do_try_state(System::block_number()).is_ok()); + }) +} diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs new file mode 100644 index 000000000000..b69150bf46d2 --- /dev/null +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs @@ -0,0 +1,36 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and + +// TODO: all manual for now for testing. use benchmarking instead. +use core::marker::PhantomData; +use frame_support::weights::Weight; + +pub trait WeightInfo { + fn step() -> Weight; +} + +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn step() -> Weight { + 1000000000.into() + } +} + +impl WeightInfo for () { + fn step() -> Weight { + 1000000000.into() + } +} diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index dd4ca11c1d09..1e76ed420af8 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -23,14 +23,16 @@ use frame_election_provider_support::{ onchain, SequentialPhragmen, SortedListProvider, VoteWeight, }; use frame_support::{ - assert_ok, derive_impl, ord_parameter_types, parameter_types, + assert_ok, derive_impl, + migrations::MultiStepMigrator, + ord_parameter_types, parameter_types, traits::{ ConstU64, Currency, EitherOfDiverse, FindAuthor, Get, Hooks, Imbalance, LockableCurrency, OnUnbalanced, OneSessionHandler, WithdrawReasons, }, weights::constants::RocksDbWeight, }; -use frame_system::{EnsureRoot, EnsureSignedBy}; +use frame_system::{limits::BlockWeights, EnsureRoot, EnsureSignedBy}; use sp_io; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ @@ -97,6 +99,7 @@ frame_support::construct_runtime!( StakeTracker: pallet_stake_tracker, VoterBagsList: pallet_bags_list::, TargetBagsList: pallet_bags_list::, + Migrator: pallet_migrations, } ); @@ -125,6 +128,7 @@ impl frame_system::Config for Test { type DbWeight = RocksDbWeight; type Block = Block; type AccountData = pallet_balances::AccountData; + type MultiBlockMigrator = Migrator; } impl pallet_balances::Config for Test { type MaxLocks = frame_support::traits::ConstU32<1024>; @@ -396,6 +400,23 @@ impl crate::pallet::pallet::Config for Test { type WeightInfo = (); } +parameter_types! { + static BnWeights: BlockWeights = ::BlockWeights::get(); + pub storage MigratorServiceWeight: Weight = BnWeights::get().max_block; +} + +#[derive_impl(pallet_migrations::config_preludes::TestDefaultConfig)] +impl pallet_migrations::Config for Test { + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = crate::migrations::v13_stake_tracker::MigrationV13< + Test, + crate::migrations::v13_stake_tracker::weights::SubstrateWeight, + >; + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type MaxServiceWeight = MigratorServiceWeight; +} + pub struct WeightedNominationsQuota; impl NominationsQuota for WeightedNominationsQuota where @@ -736,9 +757,8 @@ pub(crate) fn run_to_block(n: BlockNumber) { Session::on_initialize(b); >::on_initialize(b); Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); - if b != n { - Staking::on_finalize(System::block_number()); - } + Staking::on_finalize(System::block_number()); + ::MultiBlockMigrator::step(); } } @@ -1072,6 +1092,11 @@ pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(Accoun ) } +pub(crate) fn clear_target_list() { + TargetBagsList::unsafe_clear(); + assert!(TargetBagsList::iter().count() == 0); +} + #[allow(dead_code)] pub(crate) fn print_lists_debug() { use sp_staking::StakingInterface; diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index c7cd4d5a2ae6..bd46da102911 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -656,8 +656,8 @@ impl OnStakingUpdate> for Pallet { match T::TargetList::on_insert(who.clone(), self_stake) { Ok(_) => (), Err(_) => { - // if the target already exists in the list, it means that the target has been idle - // and/or dangling. + // if the target already exists in the list, it means that the target is idle + // and/or is dangling. debug_assert!( T::Staking::status(who) == Ok(StakerStatus::Idle) || T::Staking::status(who).is_err() diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index f9d4f7f58b0c..2602bccbc11e 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -92,6 +92,12 @@ pub struct Stake { pub active: Balance, } +impl From for Stake { + fn from(balance: Balance) -> Self { + Self { total: balance, active: balance } + } +} + /// A generic staking event listener. /// /// Note that the interface is designed in a way that the events are fired post-action, so any From 595022ea0da4d58d44cef1bbb73c7a7e7e7c6830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 20 Apr 2024 12:55:32 +0200 Subject: [PATCH 081/133] moves drop_dangling_target extrinsic from stake-tracker to staking --- substrate/frame/staking/src/benchmarking.rs | 23 +++++ .../v13_stake_tracker/benchmarks.rs | 6 +- .../src/migrations/v13_stake_tracker/mod.rs | 6 +- .../src/migrations/v13_stake_tracker/tests.rs | 10 +-- substrate/frame/staking/src/mock.rs | 45 +++++++++- substrate/frame/staking/src/pallet/impls.rs | 1 + substrate/frame/staking/src/pallet/mod.rs | 59 ++++++++++++- substrate/frame/staking/src/tests.rs | 79 +++++++++++++++++ substrate/frame/staking/src/weights.rs | 11 +++ .../staking/stake-tracker/src/benchmarking.rs | 59 ------------- .../frame/staking/stake-tracker/src/lib.rs | 86 +------------------ .../frame/staking/stake-tracker/src/mock.rs | 46 +--------- .../frame/staking/stake-tracker/src/tests.rs | 75 ---------------- .../staking/stake-tracker/src/weights.rs | 41 --------- 14 files changed, 231 insertions(+), 316 deletions(-) delete mode 100644 substrate/frame/staking/stake-tracker/src/benchmarking.rs delete mode 100644 substrate/frame/staking/stake-tracker/src/weights.rs diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 3ed33ffea422..b214200c1622 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -141,6 +141,17 @@ pub fn create_validator_with_nominators( Ok((v_stash, nominators)) } +// returns the target and voter account IDs. +fn add_dangling_target() -> (T::AccountId, T::AccountId) { + let target = account("target", 0, SEED); + let voter = account("voter", 0, SEED); + + // TODO: add to mock. + //add_dangling_target_with_nominators(target, vec![voter]); + + (target, voter) +} + struct ListScenario { /// Stash that is expected to be moved. origin_stash1: T::AccountId, @@ -962,6 +973,18 @@ benchmarks! { assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); } + drop_dangling_nomination { + let caller = account("caller", 0, SEED); + whitelist_account!(caller); + + let (target, voter) = add_dangling_target::(); + + }: _(RawOrigin::Signed(caller), voter, target) + verify { + // voter is not nominating validator anymore + // target is not in the target list + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs index 54e846c6f2f9..1b8f9e8ce3eb 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs @@ -20,6 +20,7 @@ use crate::{ migrations::{v13_stake_tracker, v13_stake_tracker::*}, + mock::Staking, Config, Pallet, }; use frame_benchmarking::v2::*; @@ -36,7 +37,10 @@ mod benches { #[block] { - v13_stake_tracker::MigrationV13::>::step(None, &mut meter).unwrap(); + v13_stake_tracker::MigrationV13::>::step( + None, &mut meter, + ) + .unwrap(); } // TODO: after benchmarks sanity checks. diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index c98e1e20a343..92e9677518f5 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -32,7 +32,9 @@ use frame_election_provider_support::SortedListProvider; use sp_runtime::Saturating; use sp_staking::StakingInterface; -mod benchmarks; +// TODO +//#[cfg(feature = "runtime-benchmarks")] +//mod benchmarks; #[cfg(test)] mod tests; pub mod weights; @@ -92,7 +94,7 @@ impl SteppedMigration for MigrationV13 // 4. progress cursor. cursor = Some(target) } else { - // done, return earlier. + // done, return earlier. return Ok(None) } } diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 729ba574f3c9..1f3921b589da 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -18,12 +18,12 @@ use crate::{ migrations::v13_stake_tracker::weights::{SubstrateWeight, WeightInfo as _}, mock::{ clear_target_list, run_to_block, AllPalletsWithSystem, ExtBuilder, MigratorServiceWeight, - Staking, System, Test as T, TargetBagsList, + Staking, System, TargetBagsList, Test as T, }, Validators, }; -use frame_support::traits::OnRuntimeUpgrade; use frame_election_provider_support::SortedListProvider; +use frame_support::traits::OnRuntimeUpgrade; use pallet_migrations::WeightInfo as _; #[test] @@ -46,13 +46,13 @@ fn mb_migration_target_list_simple_works() { // 1 step, should migrate 2 targets. run_to_block(2); - assert_eq!(TargetBagsList::iter().count(), 2); + assert_eq!(TargetBagsList::iter().count(), 2); // migration not completed yet, the one target missing. assert!(Staking::do_try_state(System::block_number()).is_err()); - // next step completes migration. + // next step completes migration. run_to_block(3); - assert_eq!(TargetBagsList::iter().count() as u32, Validators::::count()); + assert_eq!(TargetBagsList::iter().count() as u32, Validators::::count()); // migration done, try state checks pass. assert!(Staking::do_try_state(System::block_number()).is_ok()); diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 1e76ed420af8..86240e5e647d 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -37,7 +37,7 @@ use sp_io; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}, - OnStakingUpdate, OnStakingUpdateEvent, Stake, + OnStakingUpdate, OnStakingUpdateEvent, Stake, StakingInterface, }; pub const INIT_TIMESTAMP: u64 = 30_000; @@ -365,7 +365,6 @@ impl pallet_stake_tracker::Config for Test { type Staking = Staking; type VoterList = VoterBagsList; type TargetList = TargetBagsList; - type WeightInfo = (); } impl crate::pallet::pallet::Config for Test { @@ -1014,6 +1013,46 @@ pub(crate) fn setup_double_bonded_ledgers() { assert_eq!(Ledger::::get(777).unwrap().stash, 555); } +pub(crate) fn setup_dangling_target_for_nominators(target: AccountId, nominators: Vec) { + // update nominations. + for n in nominators { + let mut nominations = Staking::nominations(&n).unwrap(); + nominations.push(target); + + let nominations: BoundedVec<_, MaxNominationsOf> = + BoundedVec::truncate_from(nominations); + + // update nominations. + let prev_nominations = Nominators::::get(&n).unwrap(); + Nominators::::insert( + n, + Nominations { targets: nominations.clone(), submitted_in: 0, suppressed: false }, + ); + >::on_nominator_update( + &n, + prev_nominations.targets.to_vec(), + nominations.to_vec(), + ); + } + + // remove self-stake/unbond. + let stake = Staking::stake(&target).unwrap(); + let mut stake_after_unbond = stake; + stake_after_unbond.active -= 10; + stake_after_unbond.total -= 10; + + // now remove all the self-stake score from the validator. + >::on_stake_update( + &target, + Some(stake), + stake_after_unbond, + ); + + Bonded::::remove(target); + Validators::::remove(target); + Nominators::::remove(target); +} + #[macro_export] macro_rules! assert_session_era { ($session:expr, $era:expr) => { @@ -1099,8 +1138,6 @@ pub(crate) fn clear_target_list() { #[allow(dead_code)] pub(crate) fn print_lists_debug() { - use sp_staking::StakingInterface; - println!("\nVoters:"); let _ = voters_and_targets() .0 diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 488dc5545066..d5ed9192b4a1 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1077,6 +1077,7 @@ impl Pallet { }, } + #[cfg(not(test))] debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::iter() diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 11fc0e606ba4..f3485440f915 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -37,7 +37,7 @@ use sp_runtime::{ }; use sp_staking::{ - EraIndex, OnStakingUpdate, Page, SessionIndex, + EraIndex, OnStakingUpdate, Page, SessionIndex, StakerStatus, StakingAccount::{self, Controller, Stash}, StakingInterface, }; @@ -789,6 +789,8 @@ pub mod pallet { ForceEra { mode: Forcing }, /// Report of a controller batch deprecation. ControllerBatchDeprecated { failures: u32 }, + /// A dangling nomination has been successfully dropped. + DanglingNominationDropped { nominator: T::AccountId, target: T::AccountId }, } #[pallet::error] @@ -854,6 +856,12 @@ pub mod pallet { ControllerDeprecated, /// Cannot reset a ledger. CannotRestoreLedger, + /// Target is not dangling. + /// + /// A dandling target is a target that is part of the target list but is unbonded. + NotDanglingTarget, + /// Not a nominator. + NotNominator, } #[pallet::hooks] @@ -2081,6 +2089,55 @@ pub mod pallet { ); Ok(()) } + + /// Removes nomination from a chilled and unbonded target. + /// + /// In the case that an unboded target still has nominations lingering, the approvals stake + /// for the "dangling" target needs to remain in the target list. This extrinsic allows + /// nominations of dangling targets to be removed. + /// + /// A danling nomination may be removed IFF: + /// * The `target` is unbonded and it exists in the target list. + /// * The `voter` is nominating `target`. + /// + /// Emits [`Event::DanglingNominationDropped`]. + #[pallet::call_index(30)] + #[pallet::weight(T::WeightInfo::drop_dangling_nomination())] + pub fn drop_dangling_nomination( + origin: OriginFor, + nominator: T::AccountId, + target: T::AccountId, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + ensure!( + Self::status(&target).is_err() && T::TargetList::contains(&target), + Error::::NotDanglingTarget + ); + + match Self::status(&nominator) { + Ok(StakerStatus::Nominator(nominations)) => { + let count_before = nominations.len(); + + let nominations_after = + nominations.into_iter().filter(|n| *n != target).collect::>(); + + if nominations_after.len() != count_before { + ::nominate(&nominator, nominations_after)?; + + Self::deposit_event(Event::::DanglingNominationDropped { + nominator, + target, + }); + + Ok(Pays::No.into()) + } else { + Ok(Pays::Yes.into()) + } + }, + _ => Err(Error::::NotNominator.into()), + } + } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0188b0ad34f2..7c87b1077675 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8696,4 +8696,83 @@ mod stake_tracker { ); }) } + + #[test] + fn drop_dangling_nomination_works() { + ExtBuilder::default().try_state(false).build_and_execute(|| { + // setup. + bond_validator(42, 10); + + assert_ok!(Staking::bond(RuntimeOrigin::signed(90), 500, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); + + // target is dangling with nominations from 101 and 90. + setup_dangling_target_for_nominators(42, vec![101, 90]); + + // 101 is now nominating 42.. + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + // .. which is unbonded.. + assert!(Staking::status(&42).is_err()); + // .. and still part of the target list (thus dangling). + assert!(TargetBagsList::contains(&42)); + + // remove 90 as dangling nomination. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); + + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationDropped { nominator: 90, target: 42 }.into(), + ); + + // now, 90 is not nominating 42 anymore. + assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![11])); + // but 42 is still dangling because 101 is still nominating it + assert!(TargetBagsList::contains(&42)); + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + + // when the last dangling nomination is removed, the danling target is removed. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 101, 42)); + + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11])); + assert!(!TargetBagsList::contains(&42)); + + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationDropped { nominator: 101, target: 42 }.into(), + ); + }) + } + + #[test] + fn drop_dangling_nomination_failures_work() { + ExtBuilder::default().try_state(false).build_and_execute(|| { + // target is not dangling since it does not exist in the target list. + assert!(Staking::status(&42).is_err()); + assert!(!TargetBagsList::contains(&42)); + + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), + Error::::NotDanglingTarget, + ); + + // target is not dangling since it is still bonded. + assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), + Error::::NotDanglingTarget, + ); + + // target is dangling but voter is not nominating it. + bond_validator(42, 10); + + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + setup_dangling_target_for_nominators(42, vec![101]); + assert!(Staking::status(&42).is_err()); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), + Error::::NotNominator, + ); + }) + } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index cd4e7f973ce3..154b0dd7baa8 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -83,6 +83,7 @@ pub trait WeightInfo { fn force_apply_min_commission() -> Weight; fn set_min_commission() -> Weight; fn restore_ledger() -> Weight; + fn drop_dangling_nomination() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -834,6 +835,11 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } + + fn drop_dangling_nomination() -> Weight { + // TODO(gpestana): run benchmarks. + Weight::default() + } } // For backwards compatibility and tests. @@ -1584,4 +1590,9 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } + + fn drop_dangling_nomination() -> Weight { + // TODO(gpestana): run benchmarks. + Weight::default() + } } diff --git a/substrate/frame/staking/stake-tracker/src/benchmarking.rs b/substrate/frame/staking/stake-tracker/src/benchmarking.rs deleted file mode 100644 index fec33c8107e5..000000000000 --- a/substrate/frame/staking/stake-tracker/src/benchmarking.rs +++ /dev/null @@ -1,59 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! StakeTracker pallet benchmarking. - -#![cfg(feature = "runtime-benchmarks")] - -use crate::{mock::add_dangling_target_with_nominators, *}; -pub use frame_benchmarking::v1::{ - account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, -}; -use frame_system::RawOrigin; - -const SEED: u32 = 0; - -// returns the target and voter account IDs. -fn add_dangling_target() -> (T::AccountId, T::AccountId) { - let target = account("target", 0, SEED); - let voter = account("voter", 0, SEED); - - add_dangling_target_with_nominators(target, vec![voter]); - - (target, voter) -} - -benchmarks! { - drop_dangling_nomination { - let caller = account("caller", 0, SEED); - whitelist_account!(caller); - - let (target, voter) = add_dangling_target::(); - - }: _(RawOrigin::Signed(caller), voter, target) - verify { - // voter is not nominating validator anymore - // target is not in the target list - } - - impl_benchmark_test_suite!( - StakeTracker, - crate::mock::ExtBuilder::default(), - crate::mock::Test, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index bd46da102911..1a1bf0a0dc03 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -89,17 +89,11 @@ use sp_staking::{ }; use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(test)] pub(crate) mod mock; #[cfg(test)] mod tests; -mod weights; - -use weights::WeightInfo; - pub(crate) const LOG_TARGET: &str = "runtime::stake-tracker"; // syntactic sugar for logging. @@ -142,10 +136,7 @@ pub mod pallet { use crate::*; use frame_election_provider_support::{ExtendedBalance, VoteWeight}; use frame_support::pallet_prelude::*; - use frame_system::{ - ensure_signed, - pallet_prelude::{BlockNumberFor, OriginFor}, - }; + use frame_system::pallet_prelude::BlockNumberFor; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -173,29 +164,10 @@ pub mod pallet { Self::AccountId, Score = ::Balance, >; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; } #[pallet::event] - #[pallet::generate_deposit(pub(crate) fn deposit_event)] - pub enum Event { - /// A dangling nomination has been successfully dropped. - /// - /// A dangling nomination is a nomination to an unbonded target. - DanglingNominationDropped { voter: AccountIdOf, target: AccountIdOf }, - } - - #[pallet::error] - pub enum Error { - /// Target is not dangling. - /// - /// A dandling target is a target that is part of the target list but is unbonded. - NotDanglingTarget, - /// Not a voter/nominator. - NotVoter, - } + pub enum Event {} #[pallet::hooks] impl Hooks> for Pallet { @@ -205,58 +177,6 @@ pub mod pallet { } } - #[pallet::call] - impl Pallet { - /// Removes nomination from a chilled and unbonded target. - /// - /// In the case that an unboded target still has nominations lingering, the approvals stake - /// for the "dangling" target needs to remain in the target list. This extrinsic allows - /// nominations of dangling targets to be removed. - /// - /// A danling nomination may be removed IFF: - /// * The `target` is unbonded and it exists in the target list. - /// * The `voter` is nominating `target`. - /// - /// Emits [`Event::DanglingNominationDropped`]. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::drop_dangling_nomination())] - pub fn drop_dangling_nomination( - origin: OriginFor, - voter: AccountIdOf, - target: AccountIdOf, - ) -> DispatchResultWithPostInfo { - let _ = ensure_signed(origin)?; - - ensure!( - T::Staking::status(&target).is_err() && T::TargetList::contains(&target), - Error::::NotDanglingTarget - ); - - match T::Staking::status(&voter) { - Ok(StakerStatus::Nominator(nominations)) => { - let count_before = nominations.len(); - - let nominations_after = - nominations.into_iter().filter(|n| *n != target).collect::>(); - - if nominations_after.len() != count_before { - T::Staking::nominate(&voter, nominations_after)?; - - Self::deposit_event(Event::::DanglingNominationDropped { - voter, - target, - }); - - Ok(Pays::No.into()) - } else { - Ok(Pays::Yes.into()) - } - }, - _ => Err(Error::::NotVoter.into()), - } - } - } - impl Pallet { /// Returns the balance of a staker based on its current *active* stake, as returned by /// the staking interface. diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index f3316cb255c1..d93553439089 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -100,7 +100,6 @@ impl pallet_stake_tracker::Config for Test { type Staking = StakingMock; type VoterList = VoterBagsList; type TargetList = TargetBagsList; - type WeightInfo = (); } pub struct StakingMock {} @@ -293,43 +292,6 @@ pub(crate) fn add_nominator(who: AccountId, stake: Balance) { >::on_nominator_add(&who, vec![]); } -pub(crate) fn add_dangling_target_with_nominators(target: AccountId, nominators: Vec) { - // add new validator. - add_validator(target, 10); - - // update nominations. - for n in nominators { - let mut nominations = StakingMock::nominations(&n).unwrap(); - nominations.push(target); - update_nominations_of(n, nominations); - } - - // remove self-stake/unbond. - let stake = ::stake(&target).unwrap(); - let mut stake_after_unbond = stake; - stake_after_unbond.active -= 10; - stake_after_unbond.total -= 10; - - // now remove all the self-stake score from the validator. - >::on_stake_update( - &target, - Some(stake), - stake_after_unbond, - ); - - Bonded::mutate(|b| { - b.retain(|s| s != &target); - }); - - TestValidators::mutate(|v| { - v.remove(&target); - }); - - TestNominators::mutate(|n| { - n.remove(&target); - }); -} - pub(crate) fn stake_of(who: AccountId) -> Option> { StakingMock::stake(&who).ok() } @@ -493,6 +455,7 @@ impl ExtBuilder { self } + #[allow(dead_code)] pub fn try_state(self, enable: bool) -> Self { DisableTryRuntimeChecks::set(!enable); self @@ -528,10 +491,3 @@ impl ExtBuilder { } } } - -pub(crate) fn assert_last_event(generic_event: RuntimeEvent) { - let events = frame_system::Pallet::::events(); - // compare to the last event record - let frame_system::EventRecord { event, .. } = &events.last().expect("Event expected"); - assert_eq!(event, &generic_event); -} diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index f203b0717e36..cd3df32ab1c5 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -382,81 +382,6 @@ fn on_validator_remove_defensive_works() { }) } -mod extrinsics { - use super::*; - use crate::{Error, Event}; - - use frame_support::assert_noop; - - #[test] - fn drop_dangling_nomination_works() { - ExtBuilder::default().populate_lists().try_state(false).build_and_execute(|| { - // target is dangling with nominations from 1 and 2. - add_dangling_target_with_nominators(42, vec![1, 2]); - - // 1 is now nominating 42.. - assert_ok!(StakingMock::status(&1), StakerStatus::Nominator(vec![10, 42])); - // .. which is unbonded.. - assert!(StakingMock::status(&42).is_err()); - // .. and still part of the target list (thus dangling). - assert!(TargetBagsList::contains(&42)); - - // remove 1 as dangling nomination. - assert_ok!(StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 1, 42)); - - assert_last_event( - Event::::DanglingNominationDropped { voter: 1, target: 42 }.into(), - ); - - // now, 1 is not nominating 42 anymore. - assert_ok!(StakingMock::status(&1), StakerStatus::Nominator(vec![10])); - // but 42 is still dangling because 2 is still nominating it - assert!(TargetBagsList::contains(&42)); - assert_ok!(StakingMock::status(&2), StakerStatus::Nominator(vec![10, 11, 42])); - - // when the last dangling nomination is removed, the danling target is removed. - assert_ok!(StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 2, 42)); - - assert_ok!(StakingMock::status(&2), StakerStatus::Nominator(vec![10, 11])); - assert!(!TargetBagsList::contains(&42)); - - assert_last_event( - Event::::DanglingNominationDropped { voter: 2, target: 42 }.into(), - ); - }) - } - - #[test] - fn drop_dangling_nomination_failures_work() { - ExtBuilder::default().populate_lists().try_state(false).build_and_execute(|| { - // target is not dangling since it does not exist in the target list. - assert!(StakingMock::status(&42).is_err()); - assert!(!TargetBagsList::contains(&42)); - - assert_noop!( - StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), - Error::::NotDanglingTarget, - ); - - // target is not dangling since it is still bonded. - assert!(StakingMock::status(&10) == Ok(StakerStatus::Validator)); - assert_noop!( - StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), - Error::::NotDanglingTarget, - ); - - // target is dangling but voter is not nominating it. - assert!(StakingMock::status(&1) == Ok(StakerStatus::Nominator(vec![10]))); - add_dangling_target_with_nominators(42, vec![1]); - assert!(StakingMock::status(&42).is_err()); - assert_noop!( - StakeTracker::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), - Error::::NotVoter, - ); - }) - } -} - mod staking_integration { use super::*; diff --git a/substrate/frame/staking/stake-tracker/src/weights.rs b/substrate/frame/staking/stake-tracker/src/weights.rs deleted file mode 100644 index f280d0f24d6c..000000000000 --- a/substrate/frame/staking/stake-tracker/src/weights.rs +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use core::marker::PhantomData; -use frame_support::weights::Weight; - -/// Weight functions needed for `pallet_stake_tracker`. -pub trait WeightInfo { - fn drop_dangling_nomination() -> Weight; -} - -/// Weights for `pallet_stake_tracker` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - fn drop_dangling_nomination() -> Weight { - // TODO(gpestana): benchmarks. - Weight::default() - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - fn drop_dangling_nomination() -> Weight { - // TODO(gpestana): benchmarks. - Weight::default() - } -} From fa7edf1ffdda514402fc9cbfd8247e77f2302f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 21 Apr 2024 12:27:29 +0200 Subject: [PATCH 082/133] finishes dangling nomination benchs --- substrate/frame/staking/src/benchmarking.rs | 42 +++++++++++++------- substrate/frame/staking/src/pallet/impls.rs | 38 ++++++++++++++++++ substrate/frame/staking/src/testing_utils.rs | 12 ++++++ 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index b214200c1622..3353c79f7a69 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -32,11 +32,12 @@ use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, Perbill, Percent, Saturating, }; -use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex}; +use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex, StakingInterface}; use sp_std::prelude::*; pub use frame_benchmarking::v1::{ account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, + BenchmarkError, }; use frame_system::RawOrigin; @@ -141,17 +142,6 @@ pub fn create_validator_with_nominators( Ok((v_stash, nominators)) } -// returns the target and voter account IDs. -fn add_dangling_target() -> (T::AccountId, T::AccountId) { - let target = account("target", 0, SEED); - let voter = account("voter", 0, SEED); - - // TODO: add to mock. - //add_dangling_target_with_nominators(target, vec![voter]); - - (target, voter) -} - struct ListScenario { /// Stash that is expected to be moved. origin_stash1: T::AccountId, @@ -977,12 +967,34 @@ benchmarks! { let caller = account("caller", 0, SEED); whitelist_account!(caller); - let (target, voter) = add_dangling_target::(); + let mut targets = create_validators_with_nominators_for_era::(2, 1, 2, false, None)?; + let dangling_target = T::Lookup::lookup(targets.pop().expect("target_exists.")) + .map_err(|_| "error looking up validator account")?; + let other_target = T::Lookup::lookup(targets.pop().expect("target_exists.")) + .map_err(|_| "error looking up validator account")?; + let voter = nominators_of::(dangling_target.clone())?.pop().expect("voter exists"); + + assert_eq!(Staking::::status(&dangling_target), Ok(StakerStatus::Validator)); + Pallet::::setup_dangling_target(dangling_target.clone(), voter.clone()); + + // now dangling_target is not validating anymore. + assert!(Staking::::status(&dangling_target).is_err()); + // but the voter is still nominating it. + assert!(nominators_of::(dangling_target.clone())?.contains(&voter)); + // and the target is still part of the TargetList (thus dangling). + assert!(T::TargetList::contains(&dangling_target)); + + assert_eq!( + Staking::::status(&voter), + Ok(StakerStatus::Nominator(vec![dangling_target.clone(), other_target.clone()])) + ); - }: _(RawOrigin::Signed(caller), voter, target) + }: _(RawOrigin::Signed(caller), voter.clone(), dangling_target.clone()) verify { // voter is not nominating validator anymore - // target is not in the target list + assert_eq!(Staking::::status(&voter), Ok(StakerStatus::Nominator(vec![other_target]))); + // target is not in the target list anymore. + assert!(!T::TargetList::contains(&dangling_target)); } impl_benchmark_test_suite!( diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d5ed9192b4a1..c0d95d2934cd 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -880,6 +880,44 @@ impl Pallet { SlashRewardFraction::::put(fraction); } + #[cfg(feature = "runtime-benchmarks")] + pub fn setup_dangling_target(target: T::AccountId, nominator: T::AccountId) { + let nominations = Self::nominations(&nominator).unwrap(); + let nominations: BoundedVec<_, MaxNominationsOf> = + BoundedVec::truncate_from(nominations); + + let prev_nominations = Nominators::::get(&nominator).unwrap(); + + Nominators::::insert( + nominator.clone(), + Nominations { targets: nominations.clone(), submitted_in: 0, suppressed: false }, + ); + + T::EventListeners::on_nominator_update( + &nominator, + prev_nominations.targets.into_iter().map(|t| t.into()).collect::>(), + nominations.into_iter().map(|n| n.into()).collect::>(), + ); + + let nominator_stake = Self::stake(&nominator).unwrap(); + + let prev_stake = Self::stake(&target).unwrap(); + let stake_after_unbond = Stake { + total: prev_stake.total - nominator_stake.total, + active: prev_stake.active - nominator_stake.active, + }; + + T::EventListeners::on_stake_update( + &target.clone().into(), + Some(prev_stake), + stake_after_unbond, + ); + + Bonded::::remove(target.clone()); + Validators::::remove(target.clone()); + Nominators::::remove(target); + } + /// Get all of the voters that are eligible for the npos election. /// /// `maybe_max_len` can imposes a cap on the number of voters returned; diff --git a/substrate/frame/staking/src/testing_utils.rs b/substrate/frame/staking/src/testing_utils.rs index 28e08230d701..b3e077bd3b7f 100644 --- a/substrate/frame/staking/src/testing_utils.rs +++ b/substrate/frame/staking/src/testing_utils.rs @@ -234,6 +234,18 @@ pub fn create_validators_with_nominators_for_era( Ok(validator_chosen) } +/// Returns all the nominations associated with an account. +pub fn nominators_of( + validator: T::AccountId, +) -> Result, &'static str> { + //let acc = T::Lookup::lookup(validator).map_err(|_| "error looking up validator account")?; + + Ok(Nominators::::iter() + .filter(|(_, noms)| noms.targets.contains(&validator)) + .map(|(n, _)| n) + .collect::>()) +} + /// get the current era. pub fn current_era() -> EraIndex { >::current_era().unwrap_or(0) From b4f9e90cc9592826444bd309a0a26514d3b06ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 21 Apr 2024 12:56:47 +0200 Subject: [PATCH 083/133] fixes BadTarget error in benchmarks --- substrate/frame/staking/src/benchmarking.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 3353c79f7a69..74d5c53e3eb0 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -168,21 +168,26 @@ impl ListScenario { fn new(origin_weight: BalanceOf, is_increase: bool) -> Result { ensure!(!origin_weight.is_zero(), "origin weight must be greater than 0"); + // validator to nominate. + let validator = create_validators_with_seed::(1, 100, 42)? + .pop() + .expect("validator should exist"); + // burn the entire issuance. let i = T::Currency::burn(T::Currency::total_issuance()); sp_std::mem::forget(i); // create accounts with the origin weight - let (origin_stash1, origin_controller1) = create_stash_controller_with_balance::( USER_SEED + 2, origin_weight, RewardDestination::Staked, )?; + Staking::::nominate( RawOrigin::Signed(origin_controller1.clone()).into(), - // NOTE: these don't really need to be validators. - vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], + // NOTE: these *do* really need to be validators. + vec![validator.clone()], )?; let (_origin_stash2, origin_controller2) = create_stash_controller_with_balance::( @@ -190,9 +195,10 @@ impl ListScenario { origin_weight, RewardDestination::Staked, )?; + Staking::::nominate( RawOrigin::Signed(origin_controller2).into(), - vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], + vec![validator.clone()], )?; // find a destination weight that will trigger the worst case scenario @@ -210,10 +216,7 @@ impl ListScenario { dest_weight, RewardDestination::Staked, )?; - Staking::::nominate( - RawOrigin::Signed(dest_controller1).into(), - vec![T::Lookup::unlookup(account("random_validator", 0, SEED))], - )?; + Staking::::nominate(RawOrigin::Signed(dest_controller1).into(), vec![validator])?; Ok(ListScenario { origin_stash1, origin_controller1, dest_weight }) } From 803f148a9f59c0cd378320ab37f8817064133e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 21 Apr 2024 21:18:32 +0200 Subject: [PATCH 084/133] Adds v13 mmb migration benchmarks and tests --- substrate/bin/node/runtime/src/lib.rs | 2 - substrate/frame/staking/Cargo.toml | 1 - substrate/frame/staking/src/benchmarking.rs | 21 ++++++- .../v13_stake_tracker/benchmarks.rs | 55 ------------------- .../src/migrations/v13_stake_tracker/mod.rs | 11 +--- .../src/migrations/v13_stake_tracker/tests.rs | 4 +- .../migrations/v13_stake_tracker/weights.rs | 7 ++- substrate/frame/staking/src/mock.rs | 1 + substrate/frame/staking/src/weights.rs | 30 ++++++++++ 9 files changed, 61 insertions(+), 71 deletions(-) delete mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 0f8796a91c31..311193fb2cd2 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -710,7 +710,6 @@ impl pallet_stake_tracker::Config for Runtime { type Staking = Staking; type VoterList = VoterList; type TargetList = TargetList; - type WeightInfo = (); // TODO } impl pallet_fast_unstake::Config for Runtime { @@ -2666,7 +2665,6 @@ mod benches { [pallet_session, SessionBench::] [pallet_society, Society] [pallet_staking, Staking] - [pallet_stake_tracker, StakeTracker] [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index fce8156bce9c..c640f848c693 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -90,7 +90,6 @@ runtime-benchmarks = [ "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-migrations/runtime-benchmarks", - "pallet-stake-tracker/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", "sp-runtime/runtime-benchmarks", diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 74d5c53e3eb0..4ab8366e733f 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -18,15 +18,17 @@ //! Staking pallet benchmarking. use super::*; -use crate::{ConfigOp, Pallet as Staking}; +use crate::{migrations::v13_stake_tracker as v13, ConfigOp, Pallet as Staking}; use testing_utils::*; use codec::Decode; use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ + migrations::SteppedMigration, pallet_prelude::*, storage::bounded_vec::BoundedVec, traits::{Currency, Get, Imbalance, UnfilteredDispatchable}, + weights::WeightMeter, }; use sp_runtime::{ traits::{Bounded, One, StaticLookup, TrailingZeroInput, Zero}, @@ -1000,6 +1002,23 @@ benchmarks! { assert!(!T::TargetList::contains(&dangling_target)); } + // Multiblock-step benchmark. + v13_mmb_step { + let mut meter = WeightMeter::new(); + + let _ = + create_validators_with_nominators_for_era::(1000, 3000, 16, false, None).unwrap(); + // clear target bags list. + T::TargetList::unsafe_clear(); + assert_eq!(T::TargetList::iter().count(), 0); + + }: { + v13::MigrationV13::>::step(None, &mut meter).unwrap(); + } + verify { + assert_eq!(T::TargetList::iter().count(), 1000); + } + impl_benchmark_test_suite!( Staking, crate::mock::ExtBuilder::default().has_stakers(true), diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs deleted file mode 100644 index 1b8f9e8ce3eb..000000000000 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/benchmarks.rs +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and - -//! Benchmark the v13 multi-block-migrations - -#![cfg(feature = "runtime-benchmarks")] - -use crate::{ - migrations::{v13_stake_tracker, v13_stake_tracker::*}, - mock::Staking, - Config, Pallet, -}; -use frame_benchmarking::v2::*; -use frame_support::{migrations::SteppedMigration, weights::WeightMeter}; - -#[benchmarks] -mod benches { - use super::*; - - /// Benchmark a simple step of the v13 multi-block migration. - #[benchmark] - fn step() { - let mut meter = WeightMeter::new(); - - #[block] - { - v13_stake_tracker::MigrationV13::>::step( - None, &mut meter, - ) - .unwrap(); - } - - // TODO: after benchmarks sanity checks. - } - - impl_benchmark_test_suite!( - Staking, - crate::mock::ExtBuilder::default().has_stakers(true), - crate::mock::Test, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 92e9677518f5..8ef79e2b7a1c 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -19,22 +19,17 @@ //! Implements the multi-block migrations to support the `pallet-stake-tracker` and a strictly //! sorted list of targets with a bags-list. +use super::PALLET_MIGRATIONS_ID; +use crate::{log, BalanceOf, Config, Nominators, Pallet, Validators}; use core::marker::PhantomData; - +use frame_election_provider_support::SortedListProvider; use frame_support::{ migrations::{MigrationId, SteppedMigration}, traits::Defensive, }; - -use super::PALLET_MIGRATIONS_ID; -use crate::{log, BalanceOf, Config, Nominators, Pallet, Validators}; -use frame_election_provider_support::SortedListProvider; use sp_runtime::Saturating; use sp_staking::StakingInterface; -// TODO -//#[cfg(feature = "runtime-benchmarks")] -//mod benchmarks; #[cfg(test)] mod tests; pub mod weights; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 1f3921b589da..141caf62ad8a 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -14,6 +14,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and +#![cfg(all(test, not(feature = "runtime-benchmarks")))] + use crate::{ migrations::v13_stake_tracker::weights::{SubstrateWeight, WeightInfo as _}, mock::{ @@ -31,6 +33,7 @@ fn mb_migration_target_list_simple_works() { ExtBuilder::default().build_and_execute(|| { // simulates an empty target list which is the case before the migrations. clear_target_list(); + assert_eq!(TargetBagsList::iter().count(), 0); // try state fails since the target list count != number of validators. assert!(Staking::do_try_state(System::block_number()).is_err()); @@ -41,7 +44,6 @@ fn mb_migration_target_list_simple_works() { MigratorServiceWeight::set(&limit); // start stepped migrations. - System::set_block_number(1); AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs // 1 step, should migrate 2 targets. diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs index b69150bf46d2..87ecc26cece7 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs @@ -14,7 +14,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and -// TODO: all manual for now for testing. use benchmarking instead. +use crate::weights::{SubstrateWeight as StakingWeight, WeightInfo as _}; + use core::marker::PhantomData; use frame_support::weights::Weight; @@ -25,12 +26,12 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn step() -> Weight { - 1000000000.into() + StakingWeight::::v13_mmb_step() } } impl WeightInfo for () { fn step() -> Weight { - 1000000000.into() + Weight::default() } } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 86240e5e647d..8c31c0543261 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -1131,6 +1131,7 @@ pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(Accoun ) } +#[cfg(not(feature = "runtime-benchmarks"))] pub(crate) fn clear_target_list() { TargetBagsList::unsafe_clear(); assert!(TargetBagsList::iter().count() == 0); diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 154b0dd7baa8..9b572a9a96fc 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -84,6 +84,7 @@ pub trait WeightInfo { fn set_min_commission() -> Weight; fn restore_ledger() -> Weight; fn drop_dangling_nomination() -> Weight; + fn v13_mmb_step() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -840,6 +841,31 @@ impl WeightInfo for SubstrateWeight { // TODO(gpestana): run benchmarks. Weight::default() } + + /// Storage: `Staking::Validators` (r:1001 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:4000 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:4000 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:3001 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1000 w:1000) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:16 w:16) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn v13_mmb_step() -> Weight { + // Proof Size summary in bytes: + // Measured: `2484224` + // Estimated: `14264990` + // Minimum execution time: 15_238_334_000_000 picoseconds. + Weight::from_parts(15_238_334_000_000, 0) + .saturating_add(Weight::from_parts(0, 14264990)) + .saturating_add(T::DbWeight::get().reads(13019)) + .saturating_add(T::DbWeight::get().writes(1017)) + } } // For backwards compatibility and tests. @@ -1595,4 +1621,8 @@ impl WeightInfo for () { // TODO(gpestana): run benchmarks. Weight::default() } + + fn v13_mmb_step() -> Weight { + Weight::default() + } } From 6123e12751b7f8c73e6db699f5d9d3ae0c594b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 22 Apr 2024 12:36:21 +0200 Subject: [PATCH 085/133] refactors benchmarks to use benchmarking::v2 --- substrate/frame/staking/src/benchmarking.rs | 628 ++++++++++++-------- 1 file changed, 395 insertions(+), 233 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 4ab8366e733f..cb3fe8cd0bdc 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -38,9 +38,9 @@ use sp_staking::{currency_to_vote::CurrencyToVote, SessionIndex, StakingInterfac use sp_std::prelude::*; pub use frame_benchmarking::v1::{ - account, benchmarks, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, - BenchmarkError, + account, impl_benchmark_test_suite, whitelist_account, whitelisted_caller, BenchmarkError, }; +use frame_benchmarking::v2::*; use frame_system::RawOrigin; const SEED: u32 = 0; @@ -226,19 +226,26 @@ impl ListScenario { const USER_SEED: u32 = 999666; -benchmarks! { - bond { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn bond() { let stash = create_funded_user::("stash", USER_SEED, 100); let reward_destination = RewardDestination::Staked; let amount = T::Currency::minimum_balance() * 10u32.into(); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash.clone()), amount, reward_destination) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone()), amount, reward_destination); + assert!(Bonded::::contains_key(stash.clone())); assert!(Ledger::::contains_key(stash)); } - bond_extra { + #[benchmark] + fn bond_extra() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -253,25 +260,31 @@ benchmarks! { let stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1; - let original_bonded: BalanceOf - = Ledger::::get(&controller).map(|l| l.active).ok_or("ledger not created after")?; + let original_bonded: BalanceOf = Ledger::::get(&controller) + .map(|l| l.active) + .ok_or("ledger not created after")?; let _ = T::Currency::deposit_into_existing(&stash, max_additional).unwrap(); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash), max_additional) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash), max_additional); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded < new_bonded); + + Ok(()) } - unbond { + #[benchmark] + fn unbond() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); // setup the worst case list scenario. - let total_issuance = T::Currency::total_issuance(); + let _total_issuance = T::Currency::total_issuance(); // the weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). let origin_weight = BalanceOf::::try_from(952_994_955_240_703u128) @@ -279,24 +292,28 @@ benchmarks! { .unwrap(); let scenario = ListScenario::::new(origin_weight, false)?; - let stash = scenario.origin_stash1.clone(); + let _stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1.clone(); let amount = origin_weight - scenario.dest_weight; let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_bonded: BalanceOf = ledger.active; whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), amount) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), amount); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded > new_bonded); + + Ok(()) } // Withdraw only updates the ledger - withdraw_unbonded_update { + #[benchmark] + fn withdraw_unbonded_update(s: Linear<0, MAX_SPANS>) -> Result<(), BenchmarkError> { // Slashing Spans - let s in 0 .. MAX_SPANS; let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; add_slashing_spans::(&stash, s); let amount = T::Currency::minimum_balance() * 5u32.into(); // Half of total @@ -305,17 +322,20 @@ benchmarks! { let ledger = Ledger::::get(&controller).ok_or("ledger not created before")?; let original_total: BalanceOf = ledger.total; whitelist_account!(controller); - }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) - verify { + + #[extrinsic_call] + withdraw_unbonded(RawOrigin::Signed(controller.clone()), s); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_total: BalanceOf = ledger.total; assert!(original_total > new_total); + + Ok(()) } // Worst case scenario, everything is removed after the bonding duration - withdraw_unbonded_kill { - // Slashing Spans - let s in 0 .. MAX_SPANS; + #[benchmark] + fn withdraw_unbonded_kill(s: Linear<0, MAX_SPANS>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -336,13 +356,18 @@ benchmarks! { CurrentEra::::put(EraIndex::max_value()); whitelist_account!(controller); - }: withdraw_unbonded(RawOrigin::Signed(controller.clone()), s) - verify { + + #[extrinsic_call] + withdraw_unbonded(RawOrigin::Signed(controller.clone()), s); + assert!(!Ledger::::contains_key(controller)); assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - validate { + #[benchmark] + fn validate() -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::( MaxNominationsOf::::get() - 1, 100, @@ -353,22 +378,26 @@ benchmarks! { let prefs = ValidatorPrefs::default(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), prefs) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), prefs); + assert!(Validators::::contains_key(&stash)); assert!(T::VoterList::contains(&stash)); - } - kick { - // scenario: we want to kick `k` nominators from nominating us (we are a validator). - // we'll assume that `k` is under 128 for the purposes of determining the slope. - // each nominator should have `T::MaxNominations::get()` validators nominated, and our validator - // should be somewhere in there. - let k in 1 .. 128; + Ok(()) + } + // scenario: we want to kick `k` nominators from nominating us (we are a validator). + // we'll assume that `k` is under 128 for the purposes of determining the slope. + // each nominator should have `T::MaxNominations::get()` validators nominated, and our validator + // should be somewhere in there. + #[benchmark] + fn kick(k: Linear<1, 128>) -> Result<(), BenchmarkError> { // these are the other validators; there are `T::MaxNominations::get() - 1` of them, so // there are a total of `T::MaxNominations::get()` validators in the system. - let rest_of_validators = create_validators_with_seed::(MaxNominationsOf::::get() - 1, 100, 415)?; + let rest_of_validators = + create_validators_with_seed::(MaxNominationsOf::::get() - 1, 100, 415)?; // this is the validator that will be kicking. let (stash, controller) = create_stash_controller::( @@ -384,7 +413,7 @@ benchmarks! { // we now create the nominators. there will be `k` of them; each will nominate all // validators. we will then kick each of the `k` nominators from the main validator. let mut nominator_stashes = Vec::with_capacity(k as usize); - for i in 0 .. k { + for i in 0..k { // create a nominator stash. let (n_stash, n_controller) = create_stash_controller::( MaxNominationsOf::::get() + i, @@ -409,49 +438,60 @@ benchmarks! { } // we need the unlookuped version of the nominator stash for the kick. - let kicks = nominator_stashes.iter() + let kicks = nominator_stashes + .iter() .map(|n| T::Lookup::unlookup(n.clone())) .collect::>(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), kicks) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), kicks); + // all nominators now should *not* be nominating our validator... for n in nominator_stashes.iter() { assert!(!Nominators::::get(n).unwrap().targets.contains(&stash)); } + + Ok(()) } // Worst case scenario, T::MaxNominations::get() - nominate { - let n in 1 .. MaxNominationsOf::::get(); - + #[benchmark] + fn nominate(n: Linear<1, { MaxNominationsOf::::get() }>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); let origin_weight = MinNominatorBond::::get().max(T::Currency::minimum_balance()); - // setup a worst case list scenario. Note we don't care about the destination position, because - // we are just doing an insert into the origin position. - let scenario = ListScenario::::new(origin_weight, true)?; + // setup a worst case list scenario. Note we don't care about the destination position, + // because we are just doing an insert into the origin position. + let _scenario = ListScenario::::new(origin_weight, true)?; let (stash, controller) = create_stash_controller_with_balance::( - SEED + MaxNominationsOf::::get() + 1, // make sure the account does not conflict with others + SEED + MaxNominationsOf::::get() + 1, /* make sure the account does not conflict + * with others */ origin_weight, RewardDestination::Staked, - ).unwrap(); + ) + .unwrap(); assert!(!Nominators::::contains_key(&stash)); assert!(!T::VoterList::contains(&stash)); let validators = create_validators::(n, 100).unwrap(); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), validators) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), validators); + assert!(Nominators::::contains_key(&stash)); - assert!(T::VoterList::contains(&stash)) + assert!(T::VoterList::contains(&stash)); + + Ok(()) } - chill { + #[benchmark] + fn chill() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -465,94 +505,130 @@ benchmarks! { assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller)); + assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - set_payee { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + #[benchmark] + fn set_payee() -> Result<(), BenchmarkError> { + let (stash, controller) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; assert_eq!(Payee::::get(&stash), Some(RewardDestination::Staked)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), RewardDestination::Account(controller.clone())); + assert_eq!(Payee::::get(&stash), Some(RewardDestination::Account(controller))); + + Ok(()) } - update_payee { - let (stash, controller) = create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; + #[benchmark] + fn update_payee() -> Result<(), BenchmarkError> { + let (stash, controller) = + create_stash_controller::(USER_SEED, 100, RewardDestination::Staked)?; Payee::::insert(&stash, { #[allow(deprecated)] RewardDestination::Controller }); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), controller.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), controller.clone()); + assert_eq!(Payee::::get(&stash), Some(RewardDestination::Account(controller))); + + Ok(()) } - set_controller { - let (stash, ctlr) = create_unique_stash_controller::(9000, 100, RewardDestination::Staked, false)?; + #[benchmark] + fn set_controller() -> Result<(), BenchmarkError> { + let (stash, ctlr) = + create_unique_stash_controller::(9000, 100, RewardDestination::Staked, false)?; // ensure `ctlr` is the currently stored controller. assert!(!Ledger::::contains_key(&stash)); assert!(Ledger::::contains_key(&ctlr)); assert_eq!(Bonded::::get(&stash), Some(ctlr.clone())); whitelist_account!(stash); - }: _(RawOrigin::Signed(stash.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(stash.clone())); + assert!(Ledger::::contains_key(&stash)); + + Ok(()) } - set_validator_count { + #[benchmark] + fn set_validator_count() { let validator_count = MaxValidators::::get(); - }: _(RawOrigin::Root, validator_count) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, validator_count); + assert_eq!(ValidatorCount::::get(), validator_count); } - force_no_eras {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceNone); } + #[benchmark] + fn force_no_eras() { + #[extrinsic_call] + _(RawOrigin::Root); + assert_eq!(ForceEra::::get(), Forcing::ForceNone); + } - force_new_era {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceNew); } + #[benchmark] + fn force_new_era() { + #[extrinsic_call] + _(RawOrigin::Root); + assert_eq!(ForceEra::::get(), Forcing::ForceNew); + } - force_new_era_always {}: _(RawOrigin::Root) - verify { assert_eq!(ForceEra::::get(), Forcing::ForceAlways); } + #[benchmark] + fn force_new_era_always() { + #[extrinsic_call] + _(RawOrigin::Root); + assert_eq!(ForceEra::::get(), Forcing::ForceAlways); + } // Worst case scenario, the list of invulnerables is very long. - set_invulnerables { - let v in 0 .. MaxValidators::::get(); + #[benchmark] + fn set_invulnerables(v: Linear<0, { MaxValidators::::get() }>) { let mut invulnerables = Vec::new(); - for i in 0 .. v { + for i in 0..v { invulnerables.push(account("invulnerable", i, SEED)); } - }: _(RawOrigin::Root, invulnerables) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, invulnerables); + assert_eq!(Invulnerables::::get().len(), v as usize); } - deprecate_controller_batch { - // We pass a dynamic number of controllers to the benchmark, up to - // `MaxControllersInDeprecationBatch`. - let i in 0 .. T::MaxControllersInDeprecationBatch::get(); - + #[benchmark] + fn deprecate_controller_batch( + i: Linear<0, { T::MaxControllersInDeprecationBatch::get() }>, + ) -> Result<(), BenchmarkError> { let mut controllers: Vec<_> = vec![]; let mut stashes: Vec<_> = vec![]; for n in 0..i as u32 { - let (stash, controller) = create_unique_stash_controller::( - n, - 100, - RewardDestination::Staked, - false - )?; + let (stash, controller) = + create_unique_stash_controller::(n, 100, RewardDestination::Staked, false)?; controllers.push(controller); stashes.push(stash); } let bounded_controllers: BoundedVec<_, T::MaxControllersInDeprecationBatch> = BoundedVec::try_from(controllers.clone()).unwrap(); - }: _(RawOrigin::Root, bounded_controllers) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, bounded_controllers); + for n in 0..i as u32 { let stash = &stashes[n as usize]; let controller = &controllers[n as usize]; @@ -563,11 +639,12 @@ benchmarks! { // Ledger is now keyed by stash. assert_eq!(Ledger::::get(stash).unwrap().stash, *stash); } + + Ok(()) } - force_unstake { - // Slashing Spans - let s in 0 .. MAX_SPANS; + #[benchmark] + fn force_unstake(s: Linear<0, MAX_SPANS>) -> Result<(), BenchmarkError> { // Clean up any existing state. clear_validators_and_nominators::(); @@ -581,30 +658,38 @@ benchmarks! { assert!(T::VoterList::contains(&stash)); add_slashing_spans::(&stash, s); - }: _(RawOrigin::Root, stash.clone(), s) - verify { + #[extrinsic_call] + _(RawOrigin::Root, stash.clone(), s); + assert!(!Ledger::::contains_key(&controller)); assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - cancel_deferred_slash { - let s in 1 .. MAX_SLASHES; + #[benchmark] + fn cancel_deferred_slash(s: Linear<1, MAX_SLASHES>) { let mut unapplied_slashes = Vec::new(); let era = EraIndex::one(); let dummy = || T::AccountId::decode(&mut TrailingZeroInput::zeroes()).unwrap(); - for _ in 0 .. MAX_SLASHES { - unapplied_slashes.push(UnappliedSlash::>::default_from(dummy())); + for _ in 0..MAX_SLASHES { + unapplied_slashes + .push(UnappliedSlash::>::default_from(dummy())); } UnappliedSlashes::::insert(era, &unapplied_slashes); - let slash_indices: Vec = (0 .. s).collect(); - }: _(RawOrigin::Root, era, slash_indices) - verify { + let slash_indices: Vec = (0..s).collect(); + + #[extrinsic_call] + _(RawOrigin::Root, era, slash_indices); + assert_eq!(UnappliedSlashes::::get(&era).len(), (MAX_SLASHES - s) as usize); } - payout_stakers_alive_staked { - let n in 0 .. T::MaxExposurePageSize::get() as u32; + #[benchmark] + fn payout_stakers_alive_staked( + n: Linear<0, { T::MaxExposurePageSize::get() }>, + ) -> Result<(), BenchmarkError> { let (validator, nominators) = create_validator_with_nominators::( n, T::MaxExposurePageSize::get() as u32, @@ -615,7 +700,11 @@ benchmarks! { let current_era = CurrentEra::::get().unwrap(); // set the commission for this particular era as well. - >::insert(current_era, validator.clone(), >::validators(&validator)); + >::insert( + current_era, + validator.clone(), + >::validators(&validator), + ); let caller = whitelisted_caller(); let balance_before = T::Currency::free_balance(&validator); @@ -624,25 +713,29 @@ benchmarks! { let balance = T::Currency::free_balance(stash); nominator_balances_before.push(balance); } - }: payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era) - verify { + + #[extrinsic_call] + payout_stakers(RawOrigin::Signed(caller), validator.clone(), current_era); + let balance_after = T::Currency::free_balance(&validator); ensure!( balance_before < balance_after, "Balance of validator stash should have increased after payout.", ); - for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) { + for ((stash, _), balance_before) in nominators.iter().zip(nominator_balances_before.iter()) + { let balance_after = T::Currency::free_balance(stash); ensure!( balance_before < &balance_after, "Balance of nominator stash should have increased after payout.", ); } - } - rebond { - let l in 1 .. T::MaxUnlockingChunks::get() as u32; + Ok(()) + } + #[benchmark] + fn rebond(l: Linear<1, { T::MaxUnlockingChunks::get() }>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -665,31 +758,32 @@ benchmarks! { // so the sum of unlocking chunks puts voter into the dest bag. assert!(value * l.into() + origin_weight > origin_weight); assert!(value * l.into() + origin_weight <= dest_weight); - let unlock_chunk = UnlockChunk::> { - value, - era: EraIndex::zero(), - }; + let unlock_chunk = UnlockChunk::> { value, era: EraIndex::zero() }; - let stash = scenario.origin_stash1.clone(); + let _921stash = scenario.origin_stash1.clone(); let controller = scenario.origin_controller1; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); - for _ in 0 .. l { + for _ in 0..l { staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap() } Ledger::::insert(controller.clone(), staking_ledger.clone()); let original_bonded: BalanceOf = staking_ledger.active; whitelist_account!(controller); - }: _(RawOrigin::Signed(controller.clone()), rebond_amount) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller.clone()), rebond_amount); + let ledger = Ledger::::get(&controller).ok_or("ledger not created after")?; let new_bonded: BalanceOf = ledger.active; assert!(original_bonded < new_bonded); + + Ok(()) } - reap_stash { - let s in 1 .. MAX_SPANS; + #[benchmark] + fn reap_stash(s: Linear<1, MAX_SPANS>) -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -702,26 +796,25 @@ benchmarks! { let stash = scenario.origin_stash1; add_slashing_spans::(&stash, s); - let l = StakingLedger::::new( - stash.clone(), - T::Currency::minimum_balance() - One::one(), - ); + let l = StakingLedger::::new(stash.clone(), T::Currency::minimum_balance() - One::one()); Ledger::::insert(&controller, l); assert!(Bonded::::contains_key(&stash)); assert!(T::VoterList::contains(&stash)); whitelist_account!(controller); - }: _(RawOrigin::Signed(controller), stash.clone(), s) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(controller), stash.clone(), s); + assert!(!Bonded::::contains_key(&stash)); assert!(!T::VoterList::contains(&stash)); - } - new_era { - let v in 1 .. 10; - let n in 0 .. 100; + Ok(()) + } + #[benchmark] + fn new_era(v: Linear<1, 10>, n: Linear<0, 100>) -> Result<(), BenchmarkError> { create_validators_with_nominators_for_era::( v, n, @@ -730,16 +823,19 @@ benchmarks! { None, )?; let session_index = SessionIndex::one(); - }: { - let validators = Staking::::try_trigger_new_era(session_index, true) - .ok_or("`new_era` failed")?; - assert!(validators.len() == v as usize); + + #[block] + { + let validators = + Staking::::try_trigger_new_era(session_index, true).ok_or("`new_era` failed")?; + assert!(validators.len() == v as usize); + } + + Ok(()) } - #[extra] - payout_all { - let v in 1 .. 10; - let n in 0 .. 100; + #[benchmark(extra)] + fn payout_all(v: Linear<1, 10>, n: Linear<0, 100>) -> Result<(), BenchmarkError> { create_validators_with_nominators_for_era::( v, n, @@ -776,53 +872,71 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let origin = RawOrigin::Signed(caller); - let calls: Vec<_> = payout_calls_arg.iter().map(|arg| - Call::::payout_stakers_by_page { validator_stash: arg.0.clone(), era: arg.1, page: 0 }.encode() - ).collect(); - }: { - for call in calls { - as Decode>::decode(&mut &*call) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(origin.clone().into())?; + let calls: Vec<_> = payout_calls_arg + .iter() + .map(|arg| { + Call::::payout_stakers_by_page { + validator_stash: arg.0.clone(), + era: arg.1, + page: 0, + } + .encode() + }) + .collect(); + + #[block] + { + for call in calls { + as Decode>::decode(&mut &*call) + .expect("call is encoded above, encoding must be correct") + .dispatch_bypass_filter(origin.clone().into())?; + } } + + Ok(()) } - #[extra] - do_slash { - let l in 1 .. T::MaxUnlockingChunks::get() as u32; + #[benchmark(extra)] + fn do_slash(l: Linear<1, { T::MaxUnlockingChunks::get() }>) -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); - let unlock_chunk = UnlockChunk::> { - value: 1u32.into(), - era: EraIndex::zero(), - }; - for _ in 0 .. l { + let unlock_chunk = + UnlockChunk::> { value: 1u32.into(), era: EraIndex::zero() }; + for _ in 0..l { staking_ledger.unlocking.try_push(unlock_chunk.clone()).unwrap(); } Ledger::::insert(controller, staking_ledger); let slash_amount = T::Currency::minimum_balance() * 10u32.into(); let balance_before = T::Currency::free_balance(&stash); - }: { - crate::slashing::do_slash::( - &stash, - slash_amount, - &mut BalanceOf::::zero(), - &mut NegativeImbalanceOf::::zero(), - EraIndex::zero() - ); - } verify { + + #[block] + { + crate::slashing::do_slash::( + &stash, + slash_amount, + &mut BalanceOf::::zero(), + &mut NegativeImbalanceOf::::zero(), + EraIndex::zero(), + ); + } + let balance_after = T::Currency::free_balance(&stash); assert!(balance_before > balance_after); - } - get_npos_voters { - // number of validator intention. we will iterate all of them. - let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); - // number of nominator intention. we will iterate all of them. - let n in (MaxNominators::::get() / 2) .. MaxNominators::::get(); + Ok(()) + } - let validators = create_validators_with_nominators_for_era::( - v, n, MaxNominationsOf::::get() as usize, false, None + #[benchmark] + fn get_npos_voters( + v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, + n: Linear<{ MaxNominators::::get() / 2 }, { MaxNominators::::get() }>, + ) -> Result<(), BenchmarkError> { + let _validators = create_validators_with_nominators_for_era::( + v, + n, + MaxNominationsOf::::get() as usize, + false, + None, )? .into_iter() .map(|v| T::Lookup::lookup(v).unwrap()) @@ -832,38 +946,56 @@ benchmarks! { assert_eq!(Nominators::::count(), n); let num_voters = (v + n) as usize; - }: { - // default bounds are unbounded. - let voters = >::get_npos_voters(DataProviderBounds::default()); - assert_eq!(voters.len(), num_voters); + + #[block] + { + // default bounds are unbounded. + let voters = >::get_npos_voters(DataProviderBounds::default()); + assert_eq!(voters.len(), num_voters); + } + + Ok(()) } - get_npos_targets { - // number of validator intention. - let v in (MaxValidators::::get() / 2) .. MaxValidators::::get(); + #[benchmark] + fn get_npos_targets( + v: Linear<{ MaxValidators::::get() / 2 }, { MaxValidators::::get() }>, + ) -> Result<(), BenchmarkError> { // number of nominator intention. let n = MaxNominators::::get(); let _ = create_validators_with_nominators_for_era::( - v, n, MaxNominationsOf::::get() as usize, false, None + v, + n, + MaxNominationsOf::::get() as usize, + false, + None, )?; - }: { - // default bounds are unbounded. - let targets = >::get_npos_targets(DataProviderBounds::default()); - assert_eq!(targets.len() as u32, v); + + #[block] + { + // default bounds are unbounded. + let targets = >::get_npos_targets(DataProviderBounds::default()); + assert_eq!(targets.len() as u32, v); + } + + Ok(()) } - set_staking_configs_all_set { - }: set_staking_configs( - RawOrigin::Root, - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(BalanceOf::::max_value()), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(u32::MAX), - ConfigOp::Set(Percent::max_value()), - ConfigOp::Set(Perbill::max_value()), - ConfigOp::Set(Percent::max_value()) - ) verify { + #[benchmark] + fn set_staking_configs_all_set() { + #[extrinsic_call] + set_staking_configs( + RawOrigin::Root, + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(BalanceOf::::max_value()), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(u32::MAX), + ConfigOp::Set(Percent::max_value()), + ConfigOp::Set(Perbill::max_value()), + ConfigOp::Set(Percent::max_value()), + ); + assert_eq!(MinNominatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MinValidatorBond::::get(), BalanceOf::::max_value()); assert_eq!(MaxNominatorsCount::::get(), Some(u32::MAX)); @@ -873,17 +1005,20 @@ benchmarks! { assert_eq!(MaxStakedRewards::::get(), Some(Percent::from_percent(100))); } - set_staking_configs_all_remove { - }: set_staking_configs( - RawOrigin::Root, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove, - ConfigOp::Remove - ) verify { + #[benchmark] + fn set_staking_configs_all_remove() { + #[extrinsic_call] + set_staking_configs( + RawOrigin::Root, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ConfigOp::Remove, + ); + assert!(!MinNominatorBond::::exists()); assert!(!MinValidatorBond::::exists()); assert!(!MaxNominatorsCount::::exists()); @@ -893,7 +1028,8 @@ benchmarks! { assert!(!MaxStakedRewards::::exists()); } - chill_other { + #[benchmark] + fn chill_other() -> Result<(), BenchmarkError> { // clean up any existing state. clear_validators_and_nominators::(); @@ -902,7 +1038,7 @@ benchmarks! { // setup a worst case list scenario. Note that we don't care about the setup of the // destination position because we are doing a removal from the list but no insert. let scenario = ListScenario::::new(origin_weight, true)?; - let controller = scenario.origin_controller1.clone(); + let _controller = scenario.origin_controller1.clone(); let stash = scenario.origin_stash1; assert!(T::VoterList::contains(&stash)); @@ -918,18 +1054,22 @@ benchmarks! { )?; let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), stash.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), stash.clone()); + assert!(!T::VoterList::contains(&stash)); + + Ok(()) } - force_apply_min_commission { + #[benchmark] + fn force_apply_min_commission() -> Result<(), BenchmarkError> { // Clean up any existing state clear_validators_and_nominators::(); // Create a validator with a commission of 50% - let (stash, controller) = - create_stash_controller::(1, 1, RewardDestination::Staked)?; + let (stash, controller) = create_stash_controller::(1, 1, RewardDestination::Staked)?; let validator_prefs = ValidatorPrefs { commission: Perbill::from_percent(50), ..Default::default() }; Staking::::validate(RawOrigin::Signed(controller).into(), validator_prefs)?; @@ -943,33 +1083,46 @@ benchmarks! { // Set the min commission to 75% MinCommission::::set(Perbill::from_percent(75)); let caller = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), stash.clone()) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller), stash.clone()); + // The validators commission has been bumped to 75% assert_eq!( Validators::::get(&stash), ValidatorPrefs { commission: Perbill::from_percent(75), ..Default::default() } ); + + Ok(()) } - set_min_commission { + #[benchmark] + fn set_min_commission() { let min_commission = Perbill::max_value(); - }: _(RawOrigin::Root, min_commission) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, min_commission); + assert_eq!(MinCommission::::get(), Perbill::from_percent(100)); } - restore_ledger { + #[benchmark] + fn restore_ledger() -> Result<(), BenchmarkError> { let (stash, controller) = create_stash_controller::(0, 100, RewardDestination::Staked)?; // corrupt ledger. Ledger::::remove(controller); - }: _(RawOrigin::Root, stash.clone(), None, None, None) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, stash.clone(), None, None, None); + assert_eq!(Staking::::inspect_bond_state(&stash), Ok(LedgerIntegrityState::Ok)); + + Ok(()) } - drop_dangling_nomination { - let caller = account("caller", 0, SEED); + #[benchmark] + fn drop_dangling_nomination() -> Result<(), BenchmarkError> { + let caller = account("caller", 0, SEED); whitelist_account!(caller); let mut targets = create_validators_with_nominators_for_era::(2, 1, 2, false, None)?; @@ -994,16 +1147,20 @@ benchmarks! { Ok(StakerStatus::Nominator(vec![dangling_target.clone(), other_target.clone()])) ); - }: _(RawOrigin::Signed(caller), voter.clone(), dangling_target.clone()) - verify { + #[extrinsic_call] + _(RawOrigin::Signed(caller), voter.clone(), dangling_target.clone()); + // voter is not nominating validator anymore assert_eq!(Staking::::status(&voter), Ok(StakerStatus::Nominator(vec![other_target]))); // target is not in the target list anymore. assert!(!T::TargetList::contains(&dangling_target)); + + Ok(()) } // Multiblock-step benchmark. - v13_mmb_step { + #[benchmark] + fn v13_mmb_step() { let mut meter = WeightMeter::new(); let _ = @@ -1012,10 +1169,12 @@ benchmarks! { T::TargetList::unsafe_clear(); assert_eq!(T::TargetList::iter().count(), 0); - }: { - v13::MigrationV13::>::step(None, &mut meter).unwrap(); - } - verify { + #[block] + { + v13::MigrationV13::>::step(None, &mut meter) + .unwrap(); + } + assert_eq!(T::TargetList::iter().count(), 1000); } @@ -1123,6 +1282,8 @@ mod tests { }); } + // TODO: SelectedBenchmark not exposed by v2? + /* #[test] fn test_payout_all() { ExtBuilder::default().build_and_execute(|| { @@ -1143,4 +1304,5 @@ mod tests { ); }); } + */ } From 25589af9e09c4bcd98e97baea871f7963e396215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 22 Apr 2024 17:55:38 +0200 Subject: [PATCH 086/133] some refactoring on mmb benchmarks --- substrate/frame/staking/src/benchmarking.rs | 24 +++++++++--- .../src/migrations/v13_stake_tracker/mod.rs | 20 +++++----- .../src/migrations/v13_stake_tracker/tests.rs | 2 +- .../migrations/v13_stake_tracker/weights.rs | 37 ------------------- substrate/frame/staking/src/mock.rs | 2 +- 5 files changed, 31 insertions(+), 54 deletions(-) delete mode 100644 substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index cb3fe8cd0bdc..6536ce487e8d 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1158,24 +1158,36 @@ mod benchmarks { Ok(()) } - // Multiblock-step benchmark. + // Multi-block step benchmark. + + // TODO: comments about the step() #[benchmark] fn v13_mmb_step() { let mut meter = WeightMeter::new(); - let _ = - create_validators_with_nominators_for_era::(1000, 3000, 16, false, None).unwrap(); - // clear target bags list. + let n_validators = 1000; + let n_nominators = 1000; + + let _ = create_validators_with_nominators_for_era::( + n_validators, + n_nominators, + 16, + false, + None, + ) + .unwrap(); + T::TargetList::unsafe_clear(); assert_eq!(T::TargetList::iter().count(), 0); #[block] { - v13::MigrationV13::>::step(None, &mut meter) + v13::MigrationV13::>::step(None, &mut meter) .unwrap(); } - assert_eq!(T::TargetList::iter().count(), 1000); + // TODO: check the current try-state assertions in the stake-tracker. + assert_eq!(T::TargetList::iter().count(), n_validators as usize); } impl_benchmark_test_suite!( diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 8ef79e2b7a1c..704a31b0aa63 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -20,7 +20,7 @@ //! sorted list of targets with a bags-list. use super::PALLET_MIGRATIONS_ID; -use crate::{log, BalanceOf, Config, Nominators, Pallet, Validators}; +use crate::{log, weights, BalanceOf, Config, Nominators, Pallet, Validators}; use core::marker::PhantomData; use frame_election_provider_support::SortedListProvider; use frame_support::{ @@ -32,7 +32,6 @@ use sp_staking::StakingInterface; #[cfg(test)] mod tests; -pub mod weights; pub struct MigrationV13(PhantomData<(T, W)>); impl SteppedMigration for MigrationV13 { @@ -48,7 +47,7 @@ impl SteppedMigration for MigrationV13 mut cursor: Option, meter: &mut frame_support::weights::WeightMeter, ) -> Result, frame_support::migrations::SteppedMigrationError> { - let required = W::step(); + let required = W::v13_mmb_step(); // If there's no enough weight left in the block for a migration step, return an error. if meter.remaining().any_lt(required) { @@ -68,16 +67,11 @@ impl SteppedMigration for MigrationV13 }; if let Some((target, _)) = iter.next() { - log!( - info, - "multi-block migrations: processing target {:?}. remaining {} targets to migrate.", - target, - iter.count()); - // 2. calculate target's stake which consits of self-stake + all of its nominator's // stake. let self_stake = Pallet::::stake(&target).defensive_unwrap_or_default().total; + // TODO: need to split. let total_stake = Nominators::::iter() .filter(|(_v, noms)| noms.targets.contains(&target)) .map(|(v, _)| Pallet::::stake(&v).defensive_unwrap_or_default()) @@ -86,6 +80,14 @@ impl SteppedMigration for MigrationV13 // 3. insert (validator, score = total_stake) to the target bags list. let _ = T::TargetList::on_insert(target.clone(), total_stake).defensive(); + log!( + info, + "multi-block migrations: processed target {:?} (total stake: {:?}). remaining {} targets to migrate.", + target, + total_stake, + iter.count() + ); + // 4. progress cursor. cursor = Some(target) } else { diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 141caf62ad8a..e05016c1916e 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -37,7 +37,7 @@ fn mb_migration_target_list_simple_works() { // try state fails since the target list count != number of validators. assert!(Staking::do_try_state(System::block_number()).is_err()); - // Give it enough weight to do 2 target migrations per block. + // Give it enough weight to do 2 steps per block. let limit = ::WeightInfo::progress_mbms_none() + pallet_migrations::Pallet::::exec_migration_max_weight() + SubstrateWeight::::step() * 2; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs deleted file mode 100644 index 87ecc26cece7..000000000000 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/weights.rs +++ /dev/null @@ -1,37 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and - -use crate::weights::{SubstrateWeight as StakingWeight, WeightInfo as _}; - -use core::marker::PhantomData; -use frame_support::weights::Weight; - -pub trait WeightInfo { - fn step() -> Weight; -} - -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - fn step() -> Weight { - StakingWeight::::v13_mmb_step() - } -} - -impl WeightInfo for () { - fn step() -> Weight { - Weight::default() - } -} diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 8c31c0543261..3ec44beb986d 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -409,7 +409,7 @@ impl pallet_migrations::Config for Test { #[cfg(not(feature = "runtime-benchmarks"))] type Migrations = crate::migrations::v13_stake_tracker::MigrationV13< Test, - crate::migrations::v13_stake_tracker::weights::SubstrateWeight, + crate::weights::SubstrateWeight, >; #[cfg(feature = "runtime-benchmarks")] type Migrations = pallet_migrations::mock_helpers::MockedMigrations; From 7e6db9e2f078c32dfc045c36f886a64f31034a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 23 Apr 2024 01:18:47 +0200 Subject: [PATCH 087/133] changes mmb strategy -- do nominator-based migrations instead of validator --- .../src/migrations/v13_stake_tracker/mod.rs | 71 +++++---- .../src/migrations/v13_stake_tracker/tests.rs | 141 +++++++++++++++--- substrate/frame/staking/src/mock.rs | 6 - 3 files changed, 165 insertions(+), 53 deletions(-) diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 704a31b0aa63..7997ee2fcab0 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -20,14 +20,14 @@ //! sorted list of targets with a bags-list. use super::PALLET_MIGRATIONS_ID; -use crate::{log, weights, BalanceOf, Config, Nominators, Pallet, Validators}; +use crate::{log, weights, Config, Nominators, Pallet}; use core::marker::PhantomData; use frame_election_provider_support::SortedListProvider; use frame_support::{ - migrations::{MigrationId, SteppedMigration}, + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, traits::Defensive, }; -use sp_runtime::Saturating; +use sp_runtime::traits::CheckedAdd; use sp_staking::StakingInterface; #[cfg(test)] @@ -46,50 +46,65 @@ impl SteppedMigration for MigrationV13 fn step( mut cursor: Option, meter: &mut frame_support::weights::WeightMeter, - ) -> Result, frame_support::migrations::SteppedMigrationError> { + ) -> Result, SteppedMigrationError> { let required = W::v13_mmb_step(); // If there's no enough weight left in the block for a migration step, return an error. if meter.remaining().any_lt(required) { - return Err(frame_support::migrations::SteppedMigrationError::InsufficientWeight { - required, - }); + return Err(SteppedMigrationError::InsufficientWeight { required }); } // Do as much progress as possible per step. while meter.try_consume(required).is_ok() { // 1. get next validator in the Validators map. - let mut iter = if let Some(ref last_val) = cursor { - Validators::::iter_from(Validators::::hashed_key_for(last_val)) + let mut iter = if let Some(ref last_nom) = cursor { + Nominators::::iter_from(Nominators::::hashed_key_for(last_nom)) } else { // first step, start from beginning of the validator's map. - Validators::::iter() + Nominators::::iter() }; - if let Some((target, _)) = iter.next() { - // 2. calculate target's stake which consits of self-stake + all of its nominator's - // stake. - let self_stake = Pallet::::stake(&target).defensive_unwrap_or_default().total; - - // TODO: need to split. - let total_stake = Nominators::::iter() - .filter(|(_v, noms)| noms.targets.contains(&target)) - .map(|(v, _)| Pallet::::stake(&v).defensive_unwrap_or_default()) - .fold(self_stake, |sum: BalanceOf, stake| stake.total.saturating_add(sum)); - - // 3. insert (validator, score = total_stake) to the target bags list. - let _ = T::TargetList::on_insert(target.clone(), total_stake).defensive(); + if let Some((nominator, _)) = iter.next() { + let nominator_stake = + Pallet::::stake(&nominator).defensive_unwrap_or_default().total; + let nominations = Nominators::::get(&nominator) + .map(|n| n.targets.into_inner()) + .unwrap_or_default(); log!( info, - "multi-block migrations: processed target {:?} (total stake: {:?}). remaining {} targets to migrate.", - target, - total_stake, + "multi-block migrations: processing nominator {:?} with {} nominations. remaining {} nominators to migrate.", + nominator, + nominations.len(), iter.count() ); - // 4. progress cursor. - cursor = Some(target) + // iter over up to `MaxNominationsOf` targets of `nominator`. + for target in nominations.into_iter() { + if let Ok(current_stake) = T::TargetList::get_score(&target) { + // target is not in the target list. update with nominator's stake. + + if let Some(total_stake) = current_stake.checked_add(&nominator_stake) { + let _ = T::TargetList::on_update(&target, total_stake).defensive(); + } else { + log!(error, "target stake overflow. exit."); + return Err(SteppedMigrationError::Failed) + } + } else { + // target is not in the target list, insert new node and consider self + // stake. + let self_stake = Pallet::::stake(&target).defensive_unwrap_or_default(); + if let Some(total_stake) = self_stake.total.checked_add(&nominator_stake) { + let _ = T::TargetList::on_insert(target, total_stake).defensive(); + } else { + log!(error, "target stake overflow. exit."); + return Err(SteppedMigrationError::Failed) + } + } + } + + // progress cursor. + cursor = Some(nominator) } else { // done, return earlier. return Ok(None) diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index e05016c1916e..0ac976db7bb5 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -17,46 +17,149 @@ #![cfg(all(test, not(feature = "runtime-benchmarks")))] use crate::{ - migrations::v13_stake_tracker::weights::{SubstrateWeight, WeightInfo as _}, mock::{ - clear_target_list, run_to_block, AllPalletsWithSystem, ExtBuilder, MigratorServiceWeight, - Staking, System, TargetBagsList, Test as T, + bond_nominator, bond_validator, run_to_block, AllPalletsWithSystem, ExtBuilder, + MigratorServiceWeight, Staking, System, TargetBagsList, Test as T, }, - Validators, + testing_utils, + weights::{SubstrateWeight, WeightInfo as _}, + Nominators, }; use frame_election_provider_support::SortedListProvider; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::{assert_ok, traits::OnRuntimeUpgrade}; use pallet_migrations::WeightInfo as _; #[test] fn mb_migration_target_list_simple_works() { - ExtBuilder::default().build_and_execute(|| { - // simulates an empty target list which is the case before the migrations. - clear_target_list(); - assert_eq!(TargetBagsList::iter().count(), 0); - // try state fails since the target list count != number of validators. + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + bond_validator(1, 10); + bond_validator(2, 20); + bond_validator(3, 30); + bond_nominator(4, 40, vec![1, 2]); + bond_nominator(5, 50, vec![2, 3]); + bond_nominator(6, 60, vec![3]); + + TargetBagsList::unsafe_clear(); + assert!(TargetBagsList::count() == 0); assert!(Staking::do_try_state(System::block_number()).is_err()); - // Give it enough weight to do 2 steps per block. + // allocate 3 steps per block to do the full migration in one step. let limit = ::WeightInfo::progress_mbms_none() + pallet_migrations::Pallet::::exec_migration_max_weight() + - SubstrateWeight::::step() * 2; + SubstrateWeight::::v13_mmb_step() * 3; MigratorServiceWeight::set(&limit); - // start stepped migrations. + // migrate 3 nominators. AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs - - // 1 step, should migrate 2 targets. run_to_block(2); - assert_eq!(TargetBagsList::iter().count(), 2); - // migration not completed yet, the one target missing. + + // stakes of each validators are correct (sum of self_stake and nominations stake). + assert_eq!(TargetBagsList::get_score(&1).unwrap(), 10 + 40); + assert_eq!(TargetBagsList::get_score(&2).unwrap(), 20 + 40 + 50); + assert_eq!(TargetBagsList::get_score(&3).unwrap(), 30 + 50 + 60); + + assert_eq!(TargetBagsList::count(), 3); + + // migration done, try state checks pass. + assert!(Staking::do_try_state(System::block_number()).is_ok()); + }) +} + +#[test] +fn mb_migration_target_list_multiple_steps_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + bond_validator(1, 10); + bond_validator(2, 20); + bond_validator(3, 30); + bond_nominator(4, 40, vec![1, 2]); + bond_nominator(5, 50, vec![2, 3]); + bond_nominator(6, 60, vec![3]); + + TargetBagsList::unsafe_clear(); + assert!(TargetBagsList::count() == 0); assert!(Staking::do_try_state(System::block_number()).is_err()); - // next step completes migration. + // allocate 1 step (i.e. 1 nominator) per block. + let limit = ::WeightInfo::progress_mbms_none() + + pallet_migrations::Pallet::::exec_migration_max_weight() + + SubstrateWeight::::v13_mmb_step(); + MigratorServiceWeight::set(&limit); + + AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs + + // starts from last bonded nominator (6). + let mut migrating = Nominators::::iter().map(|(n, _)| n); + assert_eq!(migrating.next(), Some(6)); + run_to_block(2); + + // 6 nominates 3, thus target list node 3 has self stake + stake of 6. + assert_eq!(TargetBagsList::get_score(&3).unwrap(), 30 + 60); + assert_eq!(TargetBagsList::count(), 1); + + // next block, migrates nominator 5. + assert_eq!(migrating.next(), Some(5)); run_to_block(3); - assert_eq!(TargetBagsList::iter().count() as u32, Validators::::count()); + + // 5 nominates 2 and 3. stakes are updated as expected. + assert_eq!(TargetBagsList::get_score(&3).unwrap(), 30 + 60 + 50); + assert_eq!(TargetBagsList::get_score(&2).unwrap(), 20 + 50); + assert_eq!(TargetBagsList::count(), 2); + + // last block, migrates nominator 4. + assert_eq!(migrating.next(), Some(4)); + run_to_block(4); + + // 4 nominates 1 and 2. stakes are updated as expected. + assert_eq!(TargetBagsList::get_score(&2).unwrap(), 20 + 50 + 40); + assert_eq!(TargetBagsList::get_score(&1).unwrap(), 10 + 40); + assert_eq!(TargetBagsList::count(), 3); + + // migration done, try state checks pass. + assert_eq!(migrating.next(), None); + assert!(Staking::do_try_state(System::block_number()).is_ok()); + }) +} + +#[test] +fn mb_migration_target_list_chilled_validator_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // TODO + }) +} + +#[test] +fn mb_migration_target_list_bench_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // setup: + // 1000 validators; + // 5 nominators; + // 16 nominations. + let _ = + testing_utils::create_validators_with_nominators_for_era::(1000, 5, 16, true, None); + assert_eq!(TargetBagsList::count(), 1000); + + // drop targets from target list nominated by the one nominator to be migrated. + let (_to_migrate, nominations) = + Nominators::::iter().map(|(n, noms)| (n, noms.targets)).next().unwrap(); + + for t in nominations.iter() { + assert_ok!(TargetBagsList::on_remove(&t)); + } + + assert!(TargetBagsList::count() < 1000); + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // allocate 1 step per block. + let limit = ::WeightInfo::progress_mbms_none() + + pallet_migrations::Pallet::::exec_migration_max_weight() + + SubstrateWeight::::v13_mmb_step(); + MigratorServiceWeight::set(&limit); + + AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs + run_to_block(2); // migration done, try state checks pass. + assert_eq!(TargetBagsList::count(), 1000); assert!(Staking::do_try_state(System::block_number()).is_ok()); }) } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 3ec44beb986d..f86145d6776c 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -1131,12 +1131,6 @@ pub(crate) fn voters_and_targets() -> (Vec<(AccountId, VoteWeight)>, Vec<(Accoun ) } -#[cfg(not(feature = "runtime-benchmarks"))] -pub(crate) fn clear_target_list() { - TargetBagsList::unsafe_clear(); - assert!(TargetBagsList::iter().count() == 0); -} - #[allow(dead_code)] pub(crate) fn print_lists_debug() { println!("\nVoters:"); From 28646317265d7c596ea9d5c375c98b77a02f508b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 23 Apr 2024 11:20:31 +0200 Subject: [PATCH 088/133] Finishes benchmarks and MMB for stake-tracker --- substrate/frame/staking/src/benchmarking.rs | 36 +++++++-- .../src/migrations/v13_stake_tracker/mod.rs | 12 +++ .../src/migrations/v13_stake_tracker/tests.rs | 80 +++++++++++-------- substrate/frame/staking/src/mock.rs | 4 + 4 files changed, 91 insertions(+), 41 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 6536ce487e8d..23f029c62b94 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -24,6 +24,7 @@ use testing_utils::*; use codec::Decode; use frame_election_provider_support::{bounds::DataProviderBounds, SortedListProvider}; use frame_support::{ + assert_ok, migrations::SteppedMigration, pallet_prelude::*, storage::bounded_vec::BoundedVec, @@ -1158,15 +1159,20 @@ mod benchmarks { Ok(()) } - // Multi-block step benchmark. - - // TODO: comments about the step() + /// Multi-block step benchmark for v13 stake-tracker migration. + /// + /// The setup benchmarks the worst case scenario of a *single-step* of the migration. A single + /// step of this MMB migration consists of migrating one nominator, i.e. fetch all the + /// nominated targets of one nominator and add them to the target list. + /// The worst case scenario case should consider potential rebaggings done internally by the + /// sorted list provider, thus we populate the target list with 1000 validators before the + /// migration. #[benchmark] fn v13_mmb_step() { let mut meter = WeightMeter::new(); let n_validators = 1000; - let n_nominators = 1000; + let n_nominators = 5; let _ = create_validators_with_nominators_for_era::( n_validators, @@ -1177,8 +1183,23 @@ mod benchmarks { ) .unwrap(); - T::TargetList::unsafe_clear(); - assert_eq!(T::TargetList::iter().count(), 0); + // drop targets from target list nominated by the one nominator to be migrated. + let (_to_migrate, mut nominations) = Nominators::::iter() + .map(|(n, noms)| (n, noms.targets.into_inner())) + .next() + .unwrap(); + + // remove duplicates. + nominations.sort(); + nominations.dedup(); + + for t in nominations.iter() { + assert_ok!(T::TargetList::on_remove(&t)); + } + + // targets nominated by first nominator will be dropped from the target list. + // note: +1 because there is one extra validator added by the test setup. + assert_eq!(T::TargetList::count(), n_validators + 1 - nominations.len() as u32); #[block] { @@ -1186,8 +1207,7 @@ mod benchmarks { .unwrap(); } - // TODO: check the current try-state assertions in the stake-tracker. - assert_eq!(T::TargetList::iter().count(), n_validators as usize); + assert_eq!(T::TargetList::count(), n_validators + 1); } impl_benchmark_test_suite!( diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 7997ee2fcab0..6db0df9abd88 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -33,6 +33,18 @@ use sp_staking::StakingInterface; #[cfg(test)] mod tests; +/// V13 Multi-block migration to introduce the stake-tracker pallet. +/// +/// A step of the migration consists of processing one nominator in the [`Nominators`] list. All +/// nominatior's target nominations are processed per step (bound by upper bound of the max +/// nominations). +/// +/// The goals of the migration are: +/// - Insert all the nominated targets into the [`SortedListProvider`] target list. +/// - Ensure the target score (total stake) is the sum of the self stake and all its nominations +/// stake. +/// - Ensure the new targets in the list are sorted per total stake (as per the underlying +/// [`SortedListProvider`]). pub struct MigrationV13(PhantomData<(T, W)>); impl SteppedMigration for MigrationV13 { type Cursor = T::AccountId; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 0ac976db7bb5..054aa4bf2145 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -129,37 +129,51 @@ fn mb_migration_target_list_chilled_validator_works() { #[test] fn mb_migration_target_list_bench_works() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { - // setup: - // 1000 validators; - // 5 nominators; - // 16 nominations. - let _ = - testing_utils::create_validators_with_nominators_for_era::(1000, 5, 16, true, None); - assert_eq!(TargetBagsList::count(), 1000); - - // drop targets from target list nominated by the one nominator to be migrated. - let (_to_migrate, nominations) = - Nominators::::iter().map(|(n, noms)| (n, noms.targets)).next().unwrap(); - - for t in nominations.iter() { - assert_ok!(TargetBagsList::on_remove(&t)); - } - - assert!(TargetBagsList::count() < 1000); - assert!(Staking::do_try_state(System::block_number()).is_err()); - - // allocate 1 step per block. - let limit = ::WeightInfo::progress_mbms_none() + - pallet_migrations::Pallet::::exec_migration_max_weight() + - SubstrateWeight::::v13_mmb_step(); - MigratorServiceWeight::set(&limit); - - AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs - run_to_block(2); - - // migration done, try state checks pass. - assert_eq!(TargetBagsList::count(), 1000); - assert!(Staking::do_try_state(System::block_number()).is_ok()); - }) + ExtBuilder::default() + .has_stakers(false) + .max_winners(1000) + .build_and_execute(|| { + // setup: + // 1000 validators; + // 5 nominators; + // 16 nominations. + let _ = testing_utils::create_validators_with_nominators_for_era::( + 1000, 5, 16, true, None, + ); + assert_eq!(TargetBagsList::count(), 1000); + + // drop targets from target list nominated by the one nominator to be migrated. + let (_to_migrate, mut nominations) = Nominators::::iter() + .map(|(n, noms)| (n, noms.targets.into_inner())) + .next() + .unwrap(); + + // remove duplicates. + nominations.sort(); + nominations.dedup(); + + for t in nominations.iter() { + assert_ok!(TargetBagsList::on_remove(&t)); + } + + // targets nominated by first nominator will be dropped from the target list. + assert_eq!(TargetBagsList::count(), 1000 - nominations.len() as u32); + assert!(Staking::do_try_state(System::block_number()).is_err()); + + // allocate 1 step per block. + let limit = ::WeightInfo::progress_mbms_none() + + pallet_migrations::Pallet::::exec_migration_max_weight() + + SubstrateWeight::::v13_mmb_step(); + MigratorServiceWeight::set(&limit); + + AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs + + // migrate first nominator, which will add back all the targets to the target list. + run_to_block(2); + + // migration done, try state checks pass. + assert_eq!(TargetBagsList::count(), 1000); + Staking::do_try_state(System::block_number()).unwrap(); + assert!(Staking::do_try_state(System::block_number()).is_ok()); + }) } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index f86145d6776c..fde8a13d154a 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -562,6 +562,10 @@ impl ExtBuilder { SkipStakeTrackerTryStateCheck::set(!enable); self } + pub fn max_winners(self, max: u32) -> Self { + MaxWinners::set(max); + self + } fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); From b01f0135ee31dd01f68fc472cc829200a43f1e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 28 Apr 2024 13:08:04 +0200 Subject: [PATCH 089/133] simplifies defensive for tests only --- substrate/frame/staking/stake-tracker/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 1a1bf0a0dc03..5d6767c17f08 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -521,7 +521,10 @@ impl OnStakingUpdate> for Pallet { prev_stake: Option>>, stake: Stake>, ) { - match T::Staking::stake(who).and(T::Staking::status(who)) { + #[cfg(any(test, feature = "try-runtime))]"))] + assert_eq!(T::Staking::stake(who).unwrap(), stake); + + match T::Staking::status(who) { Ok(StakerStatus::Nominator(nominations)) => { let voter_weight = Self::weight_of(stake.active); From 34c46123a3d8b9f9166175d9982cd7d1ab150bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 28 Apr 2024 16:48:34 +0200 Subject: [PATCH 090/133] nit --- .../staking/src/migrations/v13_stake_tracker/tests.rs | 8 ++++++++ substrate/frame/staking/src/tests.rs | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 054aa4bf2145..092a14fb7335 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -127,6 +127,14 @@ fn mb_migration_target_list_chilled_validator_works() { }) } +#[test] +fn mb_migration_target_list_dangling_validators_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // TODO + }) +} + + #[test] fn mb_migration_target_list_bench_works() { ExtBuilder::default() diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 254669ae3a7c..2f3235376ed0 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7979,11 +7979,9 @@ mod stake_tracker { &[slash_percent], ); - // 11 has been chilled but it is still part of the targets list and it is in `Idle` - // state. It's current approvals reflects the fact that it is chilled (no self-stake) - // and the slash. + // note: upon slashing, validators are not chilled. assert!(>::contains(&11)); - assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); + assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator)); // and its balance has been updated based on the slash applied + chilling. let score_11_after = >::score(&11); From 6273d4cf7fef2153f3b44e39b9f5ad3fce97442a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 29 Apr 2024 00:40:59 +0200 Subject: [PATCH 091/133] nits --- substrate/frame/staking/stake-tracker/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 3202c1b3e3a3..ea44f1540afe 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -38,10 +38,10 @@ //! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new //! nomination updates, nominator/validator slashes and rewards. This pallet *must* ensure that the -//! scores of the targets and voters are always up to date and thus, that the targets and voters in +//! scores of the targets and voters are always up to date and thus, that the targets and voters in //! the lists are sorted by score at all time. //! -//! Note that from the POV of this pallet, all events will result in one or multiple updates to +//! Note that from the POV of this pallet, staking actions may result in one or multiple updates to //! [`Config::VoterList`] and/or [`Config::TargetList`] state. If a set of staking updates require //! too much weight to execute (e.g. at nominator's rewards payout or at slashes), the event emitter //! should handle that in some way (e.g. buffering events and implementing a multi-block event From 2096b251c30e15797051ce1afeada256955f4e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 29 Apr 2024 12:35:29 +0200 Subject: [PATCH 092/133] fixes imports --- substrate/frame/staking/src/migrations/single_block.rs | 6 +++++- .../frame/staking/src/migrations/v13_stake_tracker/mod.rs | 1 + .../frame/staking/src/migrations/v13_stake_tracker/tests.rs | 1 - 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/migrations/single_block.rs b/substrate/frame/staking/src/migrations/single_block.rs index cdb70651868a..4a25dbdab4f7 100644 --- a/substrate/frame/staking/src/migrations/single_block.rs +++ b/substrate/frame/staking/src/migrations/single_block.rs @@ -17,7 +17,10 @@ //! Single-block storage migrations for the Staking pallet. The changelog for this is maintained at //! [CHANGELOG.md](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame/staking/CHANGELOG.md). -use crate::{log, slashing, Config, EraIndex, Nominators, Pallet, UnappliedSlashes, Validators, UpToLimitDisablingStrategy, DisabledValidators, SessionInterface}; +use crate::{ + log, slashing, Config, DisabledValidators, EraIndex, Nominators, Pallet, SessionInterface, + UnappliedSlashes, UpToLimitDisablingStrategy, Validators, +}; use frame_election_provider_support::SortedListProvider; use frame_support::{ migrations::VersionedMigration, @@ -27,6 +30,7 @@ use frame_support::{ weights::Weight, }; use sp_runtime::{traits::Zero, RuntimeDebug}; +use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 6db0df9abd88..02ef5cd5da88 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -29,6 +29,7 @@ use frame_support::{ }; use sp_runtime::traits::CheckedAdd; use sp_staking::StakingInterface; +use sp_std::prelude::*; #[cfg(test)] mod tests; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 092a14fb7335..a7050b0ece71 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -134,7 +134,6 @@ fn mb_migration_target_list_dangling_validators_works() { }) } - #[test] fn mb_migration_target_list_bench_works() { ExtBuilder::default() From c6593dcc06dcef5acb7556591d2fe0b4b0d24390 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Mon, 29 Apr 2024 12:55:20 +0000 Subject: [PATCH 093/133] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_staking --- substrate/frame/staking/src/weights.rs | 1219 ++++++++++++++---------- 1 file changed, 737 insertions(+), 482 deletions(-) diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 9b572a9a96fc..c9e138b96a7d 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,27 +18,25 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-09, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-04-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/production/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking -// --no-storage-info -// --no-median-slopes -// --no-min-squares // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/staking/src/weights.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_staking +// --chain=dev // --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -94,41 +92,55 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1042` + // Measured: `1134` // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Minimum execution time: 61_142_000 picoseconds. + Weight::from_parts(62_583_000, 4764) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` - // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `2742` + // Estimated: `11506` + // Minimum execution time: 133_409_000 picoseconds. + Weight::from_parts(137_789_000, 11506) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -140,22 +152,28 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2738` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Minimum execution time: 128_838_000 picoseconds. + Weight::from_parts(132_727_000, 8877) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -163,22 +181,28 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` + // Measured: `1415` // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6_u64)) + // Minimum execution time: 62_632_000 picoseconds. + Weight::from_parts(64_185_798, 4764) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(47_715, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -189,22 +213,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -212,14 +240,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 135_885_000 picoseconds. + Weight::from_parts(147_555_024, 8877) + // Standard Error: 4_447 + .saturating_add(Weight::from_parts(1_474_964, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(17_u64)) + .saturating_add(T::DbWeight::get().writes(15_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -235,8 +263,14 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:1 w:0) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:0) + /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -247,40 +281,47 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1644` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) - .saturating_add(T::DbWeight::get().reads(11_u64)) - .saturating_add(T::DbWeight::get().writes(5_u64)) + // Minimum execution time: 79_115_000 picoseconds. + Weight::from_parts(82_034_000, 4556) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } - /// Storage: `Staking::Ledger` (r:1 w:0) + /// Storage: `Staking::Ledger` (r:129 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:129 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:128 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:3 w:3) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:49 w:49) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` - // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) + // Measured: `3671 + k * (752 ±0)` + // Estimated: `33920 + k * (3566 ±0)` + // Minimum execution time: 99_428_000 picoseconds. + Weight::from_parts(172_946_107, 33920) + // Standard Error: 43_151 + .saturating_add(Weight::from_parts(37_545_879, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(18_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(k.into()))) + .saturating_add(T::DbWeight::get().writes(16_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:17 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:1) + /// Storage: `Staking::Nominators` (r:17 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -288,27 +329,32 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForNominators` (r:1 w:1) - /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:16 w:16) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` - // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) + // Measured: `2384 + n * (348 ±0)` + // Estimated: `6248 + n * (3033 ±0)` + // Minimum execution time: 112_661_000 picoseconds. + Weight::from_parts(90_042_831, 6248) + // Standard Error: 36_011 + .saturating_add(Weight::from_parts(33_478_365, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -320,20 +366,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1816` - // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `2430` + // Estimated: `8877` + // Minimum execution time: 95_934_000 picoseconds. + Weight::from_parts(97_624_000, 8877) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -343,10 +391,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 19_872_000 picoseconds. + Weight::from_parts(20_614_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -358,10 +406,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 23_905_000 picoseconds. + Weight::from_parts(24_901_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -371,10 +419,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 23_846_000 picoseconds. + Weight::from_parts(24_732_000, 8122) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -384,8 +432,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_438_000 picoseconds. + Weight::from_parts(2_597_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -394,8 +442,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_219_000 picoseconds. + Weight::from_parts(8_685_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -404,8 +452,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_212_000 picoseconds. + Weight::from_parts(8_703_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -414,8 +462,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_193_000 picoseconds. + Weight::from_parts(8_622_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -425,10 +473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_673_000 picoseconds. + Weight::from_parts(3_260_136, 0) + // Standard Error: 32 + .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -440,12 +488,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_081_000 picoseconds. + Weight::from_parts(5_272_000, 990) + // Standard Error: 106_956 + .saturating_add(Weight::from_parts(30_736_628, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -454,26 +502,30 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -481,14 +533,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(12_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 131_018_000 picoseconds. + Weight::from_parts(144_246_801, 8877) + // Standard Error: 4_444 + .saturating_add(Weight::from_parts(1_458_960, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(17_u64)) + .saturating_add(T::DbWeight::get().writes(16_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -497,12 +549,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 96_853_000 picoseconds. + Weight::from_parts(892_001_373, 70170) + // Standard Error: 57_528 + .saturating_add(Weight::from_parts(4_872_094, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -520,58 +572,80 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:257 w:257) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:257 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:257 w:257) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasValidatorPrefs` (r:1 w:0) /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:257 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:257 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:8 w:8) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:257 w:257) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(14_u64)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4_u64)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + // Measured: `34118 + n * (625 ±0)` + // Estimated: `31763 + n * (3774 ±0)` + // Minimum execution time: 248_954_000 picoseconds. + Weight::from_parts(1_054_655_035, 31763) + // Standard Error: 540_385 + .saturating_add(Weight::from_parts(86_501_516, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(29_u64)) + .saturating_add(T::DbWeight::get().reads((10_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(16_u64)) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` - // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9_u64)) - .saturating_add(T::DbWeight::get().writes(7_u64)) + // Measured: `2743 + l * (7 ±0)` + // Estimated: `11506` + // Minimum execution time: 130_367_000 picoseconds. + Weight::from_parts(134_369_938, 11506) + // Standard Error: 6_686 + .saturating_add(Weight::from_parts(185_942, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -579,22 +653,26 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -602,14 +680,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 142_165_000 picoseconds. + Weight::from_parts(150_545_357, 8877) + // Standard Error: 4_445 + .saturating_add(Weight::from_parts(1_439_599, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(16_u64)) + .saturating_add(T::DbWeight::get().writes(15_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -619,16 +697,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:110 w:0) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:110 w:0) + /// Storage: `Staking::Bonded` (r:111 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:110 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:110 w:0) + /// Storage: `Staking::Nominators` (r:111 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:11 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:11 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `Staking::ValidatorCount` (r:1 w:0) /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::MinimumValidatorCount` (r:1 w:0) @@ -651,16 +733,16 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(206_u64)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) + // Measured: `0 + n * (720 ±0) + v * (3776 ±0)` + // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 957_678_000 picoseconds. + Weight::from_parts(964_225_000, 516555) + // Standard Error: 2_413_573 + .saturating_add(Weight::from_parts(79_822_457, 0).saturating_mul(v.into())) + // Standard Error: 240_499 + .saturating_add(Weight::from_parts(20_562_885, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(410_u64)) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) @@ -687,14 +769,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3208 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 37_903_494_000 picoseconds. + Weight::from_parts(38_991_701_000, 512390) + // Standard Error: 406_095 + .saturating_add(Weight::from_parts(8_454_350, 0).saturating_mul(v.into())) + // Standard Error: 406_095 + .saturating_add(Weight::from_parts(2_716_681, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -702,22 +784,30 @@ impl WeightInfo for SubstrateWeight { .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1001 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1001 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1001 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1001 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` - // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) + // Measured: `58454 + v * (323 ±0)` + // Estimated: `516555 + v * (3033 ±0)` + // Minimum execution time: 9_230_123_000 picoseconds. + Weight::from_parts(1_671_253_694, 516555) + // Standard Error: 178_631 + .saturating_add(Weight::from_parts(17_181_912, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(206_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -737,8 +827,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 5_848_000 picoseconds. + Weight::from_parts(6_161_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -759,8 +849,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_778_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -779,20 +869,22 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` - // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(6_u64)) + // Measured: `2545` + // Estimated: `8877` + // Minimum execution time: 109_628_000 picoseconds. + Weight::from_parts(111_707_000, 8877) + .saturating_add(T::DbWeight::get().reads(15_u64)) + .saturating_add(T::DbWeight::get().writes(9_u64)) } /// Storage: `Staking::MinCommission` (r:1 w:0) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -800,10 +892,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 12_843_000 picoseconds. + Weight::from_parts(13_310_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -813,8 +905,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 3_051_000 picoseconds. + Weight::from_parts(3_169_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Balances::Locks` (r:1 w:1) @@ -825,47 +917,71 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1165` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(T::DbWeight::get().reads(5_u64)) + // Minimum execution time: 56_877_000 picoseconds. + Weight::from_parts(58_435_000, 4764) + .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } - + /// Storage: `Staking::Bonded` (r:3 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:2 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:2 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { - // TODO(gpestana): run benchmarks. - Weight::default() + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `8631` + // Minimum execution time: 93_338_000 picoseconds. + Weight::from_parts(94_432_000, 8631) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(4_u64)) + } + /// Storage: `Staking::Nominators` (r:6 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:21 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:21 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:78 w:78) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:4 w:4) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn v13_mmb_step() -> Weight { + // Proof Size summary in bytes: + // Measured: `47878` + // Estimated: `207300` + // Minimum execution time: 2_239_356_000 picoseconds. + Weight::from_parts(2_284_677_000, 207300) + .saturating_add(T::DbWeight::get().reads(131_u64)) + .saturating_add(T::DbWeight::get().writes(83_u64)) } - - /// Storage: `Staking::Validators` (r:1001 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:4000 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:4000 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:3001 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:1000 w:1000) - /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:16 w:16) - /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) - /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) - /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn v13_mmb_step() -> Weight { - // Proof Size summary in bytes: - // Measured: `2484224` - // Estimated: `14264990` - // Minimum execution time: 15_238_334_000_000 picoseconds. - Weight::from_parts(15_238_334_000_000, 0) - .saturating_add(Weight::from_parts(0, 14264990)) - .saturating_add(T::DbWeight::get().reads(13019)) - .saturating_add(T::DbWeight::get().writes(1017)) - } } // For backwards compatibility and tests. @@ -874,41 +990,55 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1042` + // Measured: `1134` // Estimated: `4764` - // Minimum execution time: 46_504_000 picoseconds. - Weight::from_parts(48_459_000, 4764) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + // Minimum execution time: 61_142_000 picoseconds. + Weight::from_parts(62_583_000, 4764) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1990` - // Estimated: `8877` - // Minimum execution time: 90_475_000 picoseconds. - Weight::from_parts(93_619_000, 8877) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `2742` + // Estimated: `11506` + // Minimum execution time: 133_409_000 picoseconds. + Weight::from_parts(137_789_000, 11506) + .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -920,22 +1050,28 @@ impl WeightInfo for () { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2195` + // Measured: `2738` // Estimated: `8877` - // Minimum execution time: 99_335_000 picoseconds. - Weight::from_parts(101_440_000, 8877) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Minimum execution time: 128_838_000 picoseconds. + Weight::from_parts(132_727_000, 8877) + .saturating_add(RocksDbWeight::get().reads(15_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -943,22 +1079,28 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1297` + // Measured: `1415` // Estimated: `4764` - // Minimum execution time: 50_067_000 picoseconds. - Weight::from_parts(52_396_327, 4764) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(51_406, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(6_u64)) + // Minimum execution time: 62_632_000 picoseconds. + Weight::from_parts(64_185_798, 4764) + // Standard Error: 1_112 + .saturating_add(Weight::from_parts(47_715, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -969,22 +1111,26 @@ impl WeightInfo for () { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -992,14 +1138,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 92_931_000 picoseconds. - Weight::from_parts(101_398_156, 6248) - // Standard Error: 4_180 - .saturating_add(Weight::from_parts(1_377_850, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 135_885_000 picoseconds. + Weight::from_parts(147_555_024, 8877) + // Standard Error: 4_447 + .saturating_add(Weight::from_parts(1_474_964, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(17_u64)) + .saturating_add(RocksDbWeight::get().writes(15_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1015,8 +1161,14 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:1 w:0) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:0) + /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -1027,40 +1179,47 @@ impl WeightInfo for () { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1372` + // Measured: `1644` // Estimated: `4556` - // Minimum execution time: 56_291_000 picoseconds. - Weight::from_parts(58_372_000, 4556) - .saturating_add(RocksDbWeight::get().reads(11_u64)) - .saturating_add(RocksDbWeight::get().writes(5_u64)) + // Minimum execution time: 79_115_000 picoseconds. + Weight::from_parts(82_034_000, 4556) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } - /// Storage: `Staking::Ledger` (r:1 w:0) + /// Storage: `Staking::Ledger` (r:129 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:129 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:128 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:3 w:3) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:49 w:49) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1815 + k * (572 ±0)` - // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 36_218_000 picoseconds. - Weight::from_parts(38_811_308, 4556) - // Standard Error: 8_352 - .saturating_add(Weight::from_parts(6_527_398, 0).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) + // Measured: `3671 + k * (752 ±0)` + // Estimated: `33920 + k * (3566 ±0)` + // Minimum execution time: 99_428_000 picoseconds. + Weight::from_parts(172_946_107, 33920) + // Standard Error: 43_151 + .saturating_add(Weight::from_parts(37_545_879, 0).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(18_u64)) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(k.into()))) + .saturating_add(RocksDbWeight::get().writes(16_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:17 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:1) + /// Storage: `Staking::Nominators` (r:17 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1068,27 +1227,32 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForNominators` (r:1 w:1) - /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:16 w:16) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1866 + n * (102 ±0)` - // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 68_607_000 picoseconds. - Weight::from_parts(66_831_185, 6248) - // Standard Error: 14_014 - .saturating_add(Weight::from_parts(4_031_635, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(6_u64)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) + // Measured: `2384 + n * (348 ±0)` + // Estimated: `6248 + n * (3033 ±0)` + // Minimum execution time: 112_661_000 picoseconds. + Weight::from_parts(90_042_831, 6248) + // Standard Error: 36_011 + .saturating_add(Weight::from_parts(33_478_365, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -1100,20 +1264,22 @@ impl WeightInfo for () { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1816` - // Estimated: `6248` - // Minimum execution time: 60_088_000 picoseconds. - Weight::from_parts(62_471_000, 6248) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `2430` + // Estimated: `8877` + // Minimum execution time: 95_934_000 picoseconds. + Weight::from_parts(97_624_000, 8877) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -1123,10 +1289,10 @@ impl WeightInfo for () { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_777_000 picoseconds. - Weight::from_parts(20_690_000, 4556) + // Minimum execution time: 19_872_000 picoseconds. + Weight::from_parts(20_614_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1138,10 +1304,10 @@ impl WeightInfo for () { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `969` + // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_705_000 picoseconds. - Weight::from_parts(24_409_000, 4556) + // Minimum execution time: 23_905_000 picoseconds. + Weight::from_parts(24_901_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1151,10 +1317,10 @@ impl WeightInfo for () { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `902` + // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_479_000 picoseconds. - Weight::from_parts(24_502_000, 8122) + // Minimum execution time: 23_846_000 picoseconds. + Weight::from_parts(24_732_000, 8122) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1164,8 +1330,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_675_000 picoseconds. - Weight::from_parts(2_802_000, 0) + // Minimum execution time: 2_438_000 picoseconds. + Weight::from_parts(2_597_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1174,8 +1340,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_413_000, 0) + // Minimum execution time: 8_219_000 picoseconds. + Weight::from_parts(8_685_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1184,8 +1350,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_977_000 picoseconds. - Weight::from_parts(7_353_000, 0) + // Minimum execution time: 8_212_000 picoseconds. + Weight::from_parts(8_703_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1194,8 +1360,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_071_000 picoseconds. - Weight::from_parts(7_463_000, 0) + // Minimum execution time: 8_193_000 picoseconds. + Weight::from_parts(8_622_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1205,10 +1371,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_833_000 picoseconds. - Weight::from_parts(3_328_130, 0) - // Standard Error: 30 - .saturating_add(Weight::from_parts(10_058, 0).saturating_mul(v.into())) + // Minimum execution time: 2_673_000 picoseconds. + Weight::from_parts(3_260_136, 0) + // Standard Error: 32 + .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -1220,12 +1386,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 5900]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1746 + i * (229 ±0)` + // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_300_000 picoseconds. - Weight::from_parts(5_437_000, 990) - // Standard Error: 66_261 - .saturating_add(Weight::from_parts(30_172_457, 0).saturating_mul(i.into())) + // Minimum execution time: 5_081_000 picoseconds. + Weight::from_parts(5_272_000, 990) + // Standard Error: 106_956 + .saturating_add(Weight::from_parts(30_736_628, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -1234,26 +1400,30 @@ impl WeightInfo for () { /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -1261,14 +1431,14 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 87_677_000 picoseconds. - Weight::from_parts(96_386_462, 6248) - // Standard Error: 3_717 - .saturating_add(Weight::from_parts(1_370_585, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(12_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 131_018_000 picoseconds. + Weight::from_parts(144_246_801, 8877) + // Standard Error: 4_444 + .saturating_add(Weight::from_parts(1_458_960, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(17_u64)) + .saturating_add(RocksDbWeight::get().writes(16_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1277,12 +1447,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66672` - // Estimated: `70137` - // Minimum execution time: 105_086_000 picoseconds. - Weight::from_parts(1_167_895_222, 70137) - // Standard Error: 77_022 - .saturating_add(Weight::from_parts(6_487_305, 0).saturating_mul(s.into())) + // Measured: `66705` + // Estimated: `70170` + // Minimum execution time: 96_853_000 picoseconds. + Weight::from_parts(892_001_373, 70170) + // Standard Error: 57_528 + .saturating_add(Weight::from_parts(4_872_094, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1300,58 +1470,80 @@ impl WeightInfo for () { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::VirtualStakers` (r:257 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:257 w:257) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:257 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:257 w:257) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasValidatorPrefs` (r:1 w:0) /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:257 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:257 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:257 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:8 w:8) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:257 w:257) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `33297 + n * (377 ±0)` - // Estimated: `30944 + n * (3774 ±3)` - // Minimum execution time: 154_210_000 picoseconds. - Weight::from_parts(192_836_012, 30944) - // Standard Error: 40_441 - .saturating_add(Weight::from_parts(47_646_642, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(14_u64)) - .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(4_u64)) - .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n.into()))) + // Measured: `34118 + n * (625 ±0)` + // Estimated: `31763 + n * (3774 ±0)` + // Minimum execution time: 248_954_000 picoseconds. + Weight::from_parts(1_054_655_035, 31763) + // Standard Error: 540_385 + .saturating_add(Weight::from_parts(86_501_516, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(29_u64)) + .saturating_add(RocksDbWeight::get().reads((10_u64).saturating_mul(n.into()))) + .saturating_add(RocksDbWeight::get().writes(16_u64)) + .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:4 w:4) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) + /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1991 + l * (7 ±0)` - // Estimated: `8877` - // Minimum execution time: 88_337_000 picoseconds. - Weight::from_parts(91_391_254, 8877) - // Standard Error: 4_485 - .saturating_add(Weight::from_parts(103_443, 0).saturating_mul(l.into())) - .saturating_add(RocksDbWeight::get().reads(9_u64)) - .saturating_add(RocksDbWeight::get().writes(7_u64)) + // Measured: `2743 + l * (7 ±0)` + // Estimated: `11506` + // Minimum execution time: 130_367_000 picoseconds. + Weight::from_parts(134_369_938, 11506) + // Standard Error: 6_686 + .saturating_add(Weight::from_parts(185_942, 0).saturating_mul(l.into())) + .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) } /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) @@ -1359,22 +1551,26 @@ impl WeightInfo for () { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -1382,14 +1578,14 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2196 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 98_014_000 picoseconds. - Weight::from_parts(102_537_670, 6248) - // Standard Error: 3_324 - .saturating_add(Weight::from_parts(1_353_142, 0).saturating_mul(s.into())) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) + // Measured: `2843 + s * (4 ±0)` + // Estimated: `8877 + s * (4 ±0)` + // Minimum execution time: 142_165_000 picoseconds. + Weight::from_parts(150_545_357, 8877) + // Standard Error: 4_445 + .saturating_add(Weight::from_parts(1_439_599, 0).saturating_mul(s.into())) + .saturating_add(RocksDbWeight::get().reads(16_u64)) + .saturating_add(RocksDbWeight::get().writes(15_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -1399,16 +1595,20 @@ impl WeightInfo for () { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:110 w:0) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:110 w:0) + /// Storage: `Staking::Bonded` (r:111 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:110 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:110 w:0) + /// Storage: `Staking::Nominators` (r:111 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:11 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:11 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `Staking::ValidatorCount` (r:1 w:0) /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::MinimumValidatorCount` (r:1 w:0) @@ -1431,16 +1631,16 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (720 ±0) + v * (3598 ±0)` - // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 608_575_000 picoseconds. - Weight::from_parts(613_663_000, 512390) - // Standard Error: 2_286_521 - .saturating_add(Weight::from_parts(72_108_001, 0).saturating_mul(v.into())) - // Standard Error: 227_839 - .saturating_add(Weight::from_parts(20_314_085, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(206_u64)) - .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) + // Measured: `0 + n * (720 ±0) + v * (3776 ±0)` + // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 957_678_000 picoseconds. + Weight::from_parts(964_225_000, 516555) + // Standard Error: 2_413_573 + .saturating_add(Weight::from_parts(79_822_457, 0).saturating_mul(v.into())) + // Standard Error: 240_499 + .saturating_add(Weight::from_parts(20_562_885, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(410_u64)) + .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(v.into()))) @@ -1467,14 +1667,14 @@ impl WeightInfo for () { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3175 + n * (911 ±0) + v * (395 ±0)` + // Measured: `3208 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_173_756_000 picoseconds. - Weight::from_parts(37_488_937_000, 512390) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(8_086_367, 0).saturating_mul(v.into())) - // Standard Error: 467_413 - .saturating_add(Weight::from_parts(3_108_193, 0).saturating_mul(n.into())) + // Minimum execution time: 37_903_494_000 picoseconds. + Weight::from_parts(38_991_701_000, 512390) + // Standard Error: 406_095 + .saturating_add(Weight::from_parts(8_454_350, 0).saturating_mul(v.into())) + // Standard Error: 406_095 + .saturating_add(Weight::from_parts(2_716_681, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1482,22 +1682,30 @@ impl WeightInfo for () { .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1001 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1001 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1001 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1001 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `979 + v * (50 ±0)` - // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_641_258_000 picoseconds. - Weight::from_parts(382_882_595, 3510) - // Standard Error: 11_991 - .saturating_add(Weight::from_parts(4_695_820, 0).saturating_mul(v.into())) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) + // Measured: `58454 + v * (323 ±0)` + // Estimated: `516555 + v * (3033 ±0)` + // Minimum execution time: 9_230_123_000 picoseconds. + Weight::from_parts(1_671_253_694, 516555) + // Standard Error: 178_631 + .saturating_add(Weight::from_parts(17_181_912, 0).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(206_u64)) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1517,8 +1725,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_753_000 picoseconds. - Weight::from_parts(6_529_000, 0) + // Minimum execution time: 5_848_000 picoseconds. + Weight::from_parts(6_161_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1539,8 +1747,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_212_000 picoseconds. - Weight::from_parts(5_451_000, 0) + // Minimum execution time: 4_778_000 picoseconds. + Weight::from_parts(5_052_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -1559,20 +1767,22 @@ impl WeightInfo for () { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:2 w:2) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:1 w:1) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1939` - // Estimated: `6248` - // Minimum execution time: 73_000_000 picoseconds. - Weight::from_parts(75_184_000, 6248) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(6_u64)) + // Measured: `2545` + // Estimated: `8877` + // Minimum execution time: 109_628_000 picoseconds. + Weight::from_parts(111_707_000, 8877) + .saturating_add(RocksDbWeight::get().reads(15_u64)) + .saturating_add(RocksDbWeight::get().writes(9_u64)) } /// Storage: `Staking::MinCommission` (r:1 w:0) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -1580,10 +1790,10 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `691` + // Measured: `724` // Estimated: `3510` - // Minimum execution time: 13_056_000 picoseconds. - Weight::from_parts(13_517_000, 3510) + // Minimum execution time: 12_843_000 picoseconds. + Weight::from_parts(13_310_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1593,8 +1803,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_201_000 picoseconds. - Weight::from_parts(3_442_000, 0) + // Minimum execution time: 3_051_000 picoseconds. + Weight::from_parts(3_169_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Balances::Locks` (r:1 w:1) @@ -1605,24 +1815,69 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { // Proof Size summary in bytes: - // Measured: `1047` + // Measured: `1165` // Estimated: `4764` - // Minimum execution time: 44_671_000 picoseconds. - Weight::from_parts(45_611_000, 4764) - .saturating_add(RocksDbWeight::get().reads(5_u64)) + // Minimum execution time: 56_877_000 picoseconds. + Weight::from_parts(58_435_000, 4764) + .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } - + /// Storage: `Staking::Bonded` (r:3 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:2 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:2 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { - // TODO(gpestana): run benchmarks. - Weight::default() + // Proof Size summary in bytes: + // Measured: `1863` + // Estimated: `8631` + // Minimum execution time: 93_338_000 picoseconds. + Weight::from_parts(94_432_000, 8631) + .saturating_add(RocksDbWeight::get().reads(13_u64)) + .saturating_add(RocksDbWeight::get().writes(4_u64)) } - + /// Storage: `Staking::Nominators` (r:6 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:21 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:21 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:78 w:78) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:4 w:4) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn v13_mmb_step() -> Weight { - Weight::default() + // Proof Size summary in bytes: + // Measured: `47878` + // Estimated: `207300` + // Minimum execution time: 2_239_356_000 picoseconds. + Weight::from_parts(2_284_677_000, 207300) + .saturating_add(RocksDbWeight::get().reads(131_u64)) + .saturating_add(RocksDbWeight::get().writes(83_u64)) } } From 605e54d9d03013132a93ca24e5159651f5bf9998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 29 Apr 2024 23:14:22 +0200 Subject: [PATCH 094/133] starts sorting mode --- .../frame/staking/stake-tracker/src/lib.rs | 92 ++++++++++++++----- .../frame/staking/stake-tracker/src/tests.rs | 61 +++++++++++- 2 files changed, 131 insertions(+), 22 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index ea44f1540afe..c8628a82afb0 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -23,19 +23,28 @@ //! ## Overview //! //! The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] -//! trait and, based on those events, ensures that the score of nodes in the lists -//! [`Config::VoterList`] and [`Config::TargetList`] are kept up to date with the staker's bonds -//! and nominations in the system. In addition, the pallet also ensures that both the -//! [`Config::TargetList`] and [`Config::VoterList`] are *strictly sorted* by -//! [`SortedListProvider::Score`]. +//! trait. Based on those events, maintais a *strictly* sorted list of target lists based on their +//! approval voting power. +//! +//! For the voter list, the [`crate::SortingMode`] defines the type of sortition of the list, +//! namely: +//! +//! - [`crate::SortingMode::Lazy`]: will skip the score update in the voter list. +//! - [`crate::SortingMode::Strict`]: will ensure that the score updates are kept sorted +//! for the corresponding list. In this case, the [`Config::VoterList`] is *strictly* +//! sorted* by [`SortedListProvider::Score`] (note: from the time the sorting mode is strict). //! //! ## Goals //! -//! The [`OnStakingUpdate`] implementation aims to achieve the following goals: +//! Note: these goals are assuming the both target list and sorted lists have +//! [`crate::SortingMode::Strict`] set. +//! +//! The [`OnStakingUpdate`] implementation (in strict mode) aims to achieve the following goals: //! -//! * The [`Config::TargetList`] keeps a sorted list of validators, sorted by approvals +//! * The [`Config::TargetList`] keeps a sorted list of validators, *strictly* sorted by approvals //! (which include self-vote and nominations' stake). -//! * The [`Config::VoterList`] keeps a sorted list of voters, sorted by bonded stake. +//! * The [`Config::VoterList`] keeps a list of voters, *stricly* sorted by bonded stake if it has +//! [`crate::SortingMode::strict`] mode enabled, otherwise the list is kept lazily sorted. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new //! nomination updates, nominator/validator slashes and rewards. This pallet *must* ensure that the //! scores of the targets and voters are always up to date and thus, that the targets and voters in @@ -49,13 +58,14 @@ //! //! ## Staker status and list invariants //! -//! There are a few invariants that depend on the staker's (nominator or validator) state, as -//! exposed by the [`Config::Staking`] interface: +//! Note: these goals are assuming the both target list and sorted lists have +//! [`crate::SortingMode::Strict`] set. //! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the -//! voter list's score. In addition, the voters' scores are up to date with the current stake -//! returned by [`T::Staking::stake`]. -//! * A [`sp_staking::StakerStatus::Validator`] is part of both voter and target list. And its +//! voter list's score. In addition, if the `VoterList` is in strict mode, the voters' scores are up +//! to date with the current stake returned by [`T::Staking::stake`]. +//! * A [`sp_staking::StakerStatus::Validator`] is part of both voter and target list. In addition, +//! if the `TargetList` is in strict mode, its //! approvals score (nominations + self-stake) is kept up to date as the target list's score. //! * A [`sp_staking::StakerStatus::Idle`] may have a target list's score while other stakers //! nominate the idle validator. @@ -81,6 +91,7 @@ pub use pallet::*; use frame_election_provider_support::SortedListProvider; use frame_support::{ defensive, + pallet_prelude::*, traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; use sp_runtime::traits::Zero; @@ -131,11 +142,32 @@ impl StakeImbalance { } } +/// Defines the sorting mode of sorted list providers. +/// +/// Strict: all score update events will be autimatically reflected in the sorted list. +/// Lazy: no score update events will be automatically reflected in the sorted list. +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum SortingMode { + Strict, + Lazy, +} + +impl Default for SortingMode { + fn default() -> Self { + Self::Strict + } +} + +impl SortingMode { + fn is_lazy_mode(&self) -> bool { + matches!(self, Self::Lazy) + } +} + #[frame_support::pallet] pub mod pallet { use crate::*; use frame_election_provider_support::{ExtendedBalance, VoteWeight}; - use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::BlockNumberFor; /// The current storage version. @@ -166,6 +198,9 @@ pub mod pallet { >; } + #[pallet::storage] + pub type VoterListMode = StorageValue<_, SortingMode, ValueQuery>; + #[pallet::event] pub enum Event {} @@ -358,10 +393,15 @@ impl Pallet { let active_stake = T::Staking::stake(&voter) .map(|s| Self::weight_of(s.active)) .expect("active voter has bonded stake; qed."); - frame_support::ensure!( - active_stake == score, - "voter score must be the same as its active stake" - ); + + // if the voter list is in lazy mode, we don't expect the stake of the voter to + // match the score in the list at all times. + if !VoterListMode::::get().is_lazy_mode() { + frame_support::ensure!( + active_stake == score, + "voter score must be the same as its active stake" + ); + } for nomination in nominations { if let Some(stake) = approvals_map.get_mut(&nomination) { @@ -443,6 +483,8 @@ impl Pallet { log!(trace, "try-state: calculated approvals map: {:?}", approvals_map); + // if the target list is in lazy mode, we don't expect the stake approvals of the target + // to be correct at all times. // compare calculated approvals per target with target list state. for (target, calculated_stake) in approvals_map.iter() { let stake_in_list = T::TargetList::get_score(target).expect("target must exist; qed."); @@ -499,6 +541,12 @@ impl Pallet { /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the /// correct position in the list (bag or otherwise), given its score. pub fn do_try_state_voter_sorting() -> Result<(), sp_runtime::TryRuntimeError> { + // if the voter list is in lazy mode, we don't expect the nodes to be sorted at all times. + // skip checks. + if !VoterListMode::::get().is_lazy_mode() { + return Ok(()) + } + for t in T::VoterList::iter() { frame_support::ensure!( T::VoterList::in_position(&t).expect("voter exists"), @@ -521,11 +569,13 @@ impl OnStakingUpdate> for Pallet { prev_stake: Option>>, stake: Stake>, ) { - #[cfg(any(test, feature = "try-runtime))]"))] - debug_assert!(T::Staking::stake(who).unwrap() == stake, "input stake mismatches expected."); - match T::Staking::status(who) { Ok(StakerStatus::Nominator(nominations)) => { + // if voters are in lazy mode, return without updating the stake. + if VoterListMode::::get().is_lazy_mode() { + return + } + let voter_weight = Self::weight_of(stake.active); let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index cd3df32ab1c5..9c6221c25b03 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -17,7 +17,7 @@ #![cfg(test)] -use crate::{mock::*, StakeImbalance}; +use crate::{mock::*, SortingMode, StakeImbalance, VoterListMode}; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_support::assert_ok; @@ -152,6 +152,36 @@ fn on_stake_update_works() { }) } +#[test] +fn on_stake_update_lazy_voters_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + VoterListMode::::set(SortingMode::Lazy); + + assert!(VoterBagsList::contains(&1)); + let stake_before = stake_of(1); + + let nominations = ::nominations(&1).unwrap(); + assert!(nominations.len() == 1); + let nomination_score_before = TargetBagsList::get_score(&nominations[0]).unwrap(); + + // manually change the stake of the voter. + let new_stake = Stake { total: 10, active: 10 }; + // assert imbalance of the operation is negative. + assert!(stake_before.unwrap().active > new_stake.active); + + TestNominators::mutate(|n| { + n.insert(1, (new_stake, nominations.clone())); + }); + + >::on_stake_update(&1, stake_before, new_stake); + + // score of voter did not update, since the voter list is lazily updated. + assert_eq!(VoterBagsList::get_score(&1).unwrap(), stake_before.unwrap().active); + let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); + assert_eq!(nomination_score_after, nomination_score_before,); + }); +} + #[test] fn on_stake_update_sorting_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { @@ -383,6 +413,7 @@ fn on_validator_remove_defensive_works() { } mod staking_integration { + use super::*; #[test] @@ -510,6 +541,34 @@ mod staking_integration { }) } + #[test] + fn on_nominator_update_lazy_voter_works() { + ExtBuilder::default().populate_lists().build_and_execute(|| { + // sets voter list to lazy mode. + VoterListMode::::set(SortingMode::Lazy); + + assert_eq!( + get_scores::(), + vec![(10, 100), (11, 100), (1, 100), (2, 100)] + ); + assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + + add_validator(20, 500); + // removes nomination from 10 and adds nomination to new validator, 20. + update_nominations_of(2, vec![11, 20]); + + // voter list has been updated because a new voter (20) has been added, not stake + // updated. + assert_eq!( + get_scores::(), + [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)] + ); + + // target list has been updated: + assert_eq!(get_scores::(), vec![(20, 600), (11, 200), (10, 200)]); + }) + } + #[test] fn target_chill_remove_lifecycle_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { From 3fa1601473fd4027a7db2aaf064847769ef2f2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 30 Apr 2024 11:22:26 +0200 Subject: [PATCH 095/133] fixes iter --- substrate/frame/staking/src/pallet/impls.rs | 7 +++---- substrate/frame/staking/src/tests.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a8d1fe84cc7c..a975299bb0ed 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1081,8 +1081,8 @@ impl Pallet { // target list may contain chilled validators and dangling (i.e. unbonded) targets, filter // those. let mut targets_iter = T::TargetList::iter().filter(|t| match Self::status(&t) { - Ok(StakerStatus::Idle) | Err(_) => false, - Ok(_) => true, + Ok(StakerStatus::Idle) | Ok(StakerStatus::Nominator(_)) | Err(_) => false, + Ok(StakerStatus::Validator) => true, }); while all_targets.len() < final_predicted_len as usize && @@ -2188,8 +2188,7 @@ impl Pallet { ); ensure!( ::TargetList::iter() - .filter(|t| Self::status(&t) != Ok(StakerStatus::Idle)) - .filter(|t| !Self::status(&t).is_err()) + .filter(|t| Self::status(&t) == Ok(StakerStatus::Validator)) .count() as u32 == Validators::::count(), "wrong external count (TargetList.count != Validators.count)" ); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0c995229fc05..e418530180e7 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7626,6 +7626,18 @@ mod stake_tracker { // keep tests clean; type A = AccountId; + #[test] + fn validator_turns_nominator() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator)); + + // 11 and 21 are both Validators. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(11), vec![21])); + + assert_eq!(Staking::status(&11), Ok(StakerStatus::Nominator(vec![21]))); + }); + } + #[test] fn add_remove_nomination_works() { // Test case: a new nomination affects the stake behind the target in the target list and From 9e18a84bad8d274b4c14ebd382748a3e6c5b35d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 2 May 2024 14:53:10 +0200 Subject: [PATCH 096/133] cargo lock update after merging master --- Cargo.lock | 3330 +++++++++++++++++++++++++++------------------------- 1 file changed, 1707 insertions(+), 1623 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9453505cb697..759e22e6a971 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.28.0", + "gimli 0.28.1", ] [[package]] @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher 0.4.4", @@ -83,19 +83,19 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.14", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.10", + "getrandom 0.2.14", "once_cell", "version_check", "zerocopy", @@ -103,18 +103,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-primitives" @@ -138,13 +138,12 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" dependencies = [ "arrayvec 0.7.4", "bytes", - "smol_str", ] [[package]] @@ -157,9 +156,9 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", "syn-solidity", "tiny-keccak", ] @@ -214,9 +213,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -234,37 +233,37 @@ checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "approx" @@ -284,8 +283,8 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -298,9 +297,9 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -495,7 +494,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -505,7 +504,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -517,7 +516,7 @@ checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint", "num-traits", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -529,8 +528,8 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -560,20 +559,6 @@ dependencies = [ "hashbrown 0.13.2", ] -[[package]] -name = "ark-scale" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "parity-scale-codec", - "scale-info", -] - [[package]] name = "ark-scale" version = "0.0.12" @@ -631,8 +616,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -678,9 +663,9 @@ checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "array-bytes" -version = "6.1.0" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b1c5a481ec30a5abd8dfbd94ab5cf1bb4e9a66be7f1b3b322f2f1170c200fd" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" [[package]] name = "arrayref" @@ -725,8 +710,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "synstructure", ] @@ -737,21 +722,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "assert_cmd" -version = "2.0.12" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6" +checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" dependencies = [ "anstyle", "bstr", "doc-comment", - "predicates 3.0.3", + "predicates 3.1.0", "predicates-core", "predicates-tree", "wait-timeout", @@ -1069,7 +1054,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -1084,17 +1069,29 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-channel" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +dependencies = [ + "concurrent-queue", + "event-listener 5.3.0", + "event-listener-strategy 0.5.2", + "futures-core", + "pin-project-lite 0.2.14", +] + [[package]] name = "async-executor" -version = "1.5.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" dependencies = [ - "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand 1.9.0", - "futures-lite", + "fastrand 2.1.0", + "futures-lite 2.3.0", "slab", ] @@ -1107,21 +1104,21 @@ dependencies = [ "async-lock 2.8.0", "autocfg", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel", + "async-channel 2.2.1", "async-executor", - "async-io", - "async-lock 2.8.0", + "async-io 2.3.2", + "async-lock 3.3.0", "blocking", - "futures-lite", + "futures-lite 2.3.0", "once_cell", ] @@ -1135,16 +1132,35 @@ dependencies = [ "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", - "polling", - "rustix 0.37.23", + "polling 2.8.0", + "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +dependencies = [ + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.0", + "rustix 0.38.34", + "slab", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "async-lock" version = "2.8.0" @@ -1161,40 +1177,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ "event-listener 4.0.3", - "event-listener-strategy", - "pin-project-lite 0.2.12", + "event-listener-strategy 0.4.0", + "pin-project-lite 0.2.14", ] [[package]] name = "async-net" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" +checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" dependencies = [ - "async-io", - "autocfg", + "async-io 1.13.0", "blocking", - "futures-lite", + "futures-lite 1.13.0", ] [[package]] name = "async-process" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ - "async-io", + "async-io 1.13.0", "async-lock 2.8.0", - "autocfg", + "async-signal", "blocking", "cfg-if", - "event-listener 2.5.3", - "futures-lite", - "rustix 0.37.23", - "signal-hook", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.34", "windows-sys 0.48.0", ] +[[package]] +name = "async-signal" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" +dependencies = [ + "async-io 2.3.2", + "async-lock 3.3.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.34", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + [[package]] name = "async-std" version = "1.12.0" @@ -1202,21 +1234,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", - "async-channel", + "async-channel 1.9.0", "async-global-executor", - "async-io", + "async-io 1.13.0", "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite", + "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", "memchr", "once_cell", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "pin-utils", "slab", "wasm-bindgen-futures", @@ -1230,7 +1262,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", ] [[package]] @@ -1239,26 +1271,26 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "async-task" -version = "4.4.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -1271,7 +1303,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", ] [[package]] @@ -1282,9 +1314,9 @@ checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atty" @@ -1299,21 +1331,20 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 1.0.109", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backoff" @@ -1321,16 +1352,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.14", "instant", "rand 0.8.5", ] [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line 0.21.0", "cc", @@ -1384,24 +1415,21 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "base64ct" -version = "1.6.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "basic-toml" -version = "0.1.8" +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" -dependencies = [ - "serde", -] +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beef" @@ -1416,7 +1444,7 @@ dependencies = [ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "env_logger 0.11.3", "hash-db", "log", @@ -1445,13 +1473,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.12", - "proc-macro2 1.0.75", - "quote 1.0.35", + "prettyplease 0.2.19", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex", "rustc-hash", "shlex", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -1510,9 +1538,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" @@ -1560,31 +1588,31 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.2.6", + "constant_time_eq 0.3.0", ] [[package]] name = "blake2s_simd" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.2.6", + "constant_time_eq 0.3.0", ] [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec 0.7.4", @@ -1613,17 +1641,16 @@ dependencies = [ [[package]] name = "blocking" -version = "1.3.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ - "async-channel", - "async-lock 2.8.0", + "async-channel 2.2.1", + "async-lock 3.3.0", "async-task", - "atomic-waker", - "fastrand 1.9.0", - "futures-lite", - "log", + "futures-io", + "futures-lite 2.3.0", + "piper", ] [[package]] @@ -1919,7 +1946,7 @@ dependencies = [ "bp-parachains", "bp-polkadot-core", "bp-runtime", - "ed25519-dalek 2.1.0", + "ed25519-dalek 2.1.1", "finality-grandpa", "parity-scale-codec", "sp-application-crypto", @@ -2327,21 +2354,21 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "tinyvec", ] [[package]] name = "bstr" -version = "1.6.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata 0.3.6", + "regex-automata 0.4.6", "serde", ] @@ -2356,9 +2383,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -2374,21 +2401,21 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2-sys" @@ -2422,9 +2449,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -2437,7 +2464,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.18", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -2457,12 +2484,13 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -2476,9 +2504,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", ] @@ -2531,23 +2559,23 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -2556,15 +2584,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -2627,9 +2655,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", @@ -2665,24 +2693,24 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", - "clap_derive 4.5.3", + "clap_derive 4.5.4", ] [[package]] name = "clap-num" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" +checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" dependencies = [ "num-traits", ] @@ -2696,17 +2724,17 @@ dependencies = [ "anstream", "anstyle", "clap_lex 0.7.0", - "strsim 0.11.0", + "strsim 0.11.1", "terminal_size", ] [[package]] name = "clap_complete" -version = "4.4.0" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", ] [[package]] @@ -2717,21 +2745,21 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -2751,13 +2779,12 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "coarsetime" -version = "0.1.23" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" +checksum = "13b3839cf01bb7960114be3ccf2340f541b6d0c81f8690b007b2b39f750f7e5d" dependencies = [ "libc", - "once_cell", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasix", "wasm-bindgen", ] @@ -2891,9 +2918,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "eyre", @@ -2904,23 +2931,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" dependencies = [ "nom", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 1.0.109", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -2931,20 +2958,19 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -2952,12 +2978,12 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686" +checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" dependencies = [ - "strum 0.25.0", - "strum_macros 0.25.3", + "strum 0.26.2", + "strum_macros 0.26.2", "unicode-width", ] @@ -2985,9 +3011,9 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -3017,9 +3043,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +checksum = "5ba00838774b4ab0233e355d26710fbfc8327a05c017f6dc4873f876d1f79f78" dependencies = [ "cfg-if", "cpufeatures", @@ -3030,29 +3056,27 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-random" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", - "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.14", "once_cell", - "proc-macro-hack", "tiny-keccak", ] @@ -3062,12 +3086,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -[[package]] -name = "constant_time_eq" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" - [[package]] name = "constant_time_eq" version = "0.3.0" @@ -3076,9 +3094,9 @@ checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "constcat" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f272d0c4cf831b4fa80ee529c7707f76585986e910e1fbce1d7921970bc1a241" +checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" [[package]] name = "contracts-rococo-runtime" @@ -3152,9 +3170,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -3162,9 +3180,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core2" @@ -3334,9 +3352,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -3441,9 +3459,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b432c56615136f8dba245fed7ec3d5518c500a31108661067e61e72fe7e6bc" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -3456,9 +3474,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -3500,7 +3518,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.3", + "clap 4.5.4", "criterion-plot", "futures", "is-terminal", @@ -3531,46 +3549,37 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -3580,9 +3589,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", @@ -3634,7 +3643,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -3659,7 +3668,7 @@ dependencies = [ "cumulus-test-runtime", "futures", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -3772,7 +3781,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-consensus", "sp-api", "sp-block-builder", @@ -3797,7 +3806,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-primitives", "polkadot-parachain-primitives", "polkadot-primitives", @@ -3993,10 +4002,10 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -4240,13 +4249,13 @@ dependencies = [ name = "cumulus-relay-chain-minimal-node" version = "0.7.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "async-trait", "cumulus-primitives-core", "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-availability-recovery", "polkadot-collator-protocol", "polkadot-core-primitives", @@ -4411,7 +4420,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.3", + "clap 4.5.4", "criterion 0.5.1", "cumulus-client-cli", "cumulus-client-collator", @@ -4499,7 +4508,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "socket2 0.5.6", + "socket2 0.5.7", "windows-sys 0.52.0", ] @@ -4551,13 +4560,13 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -4575,9 +4584,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.106" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" +checksum = "21db378d04296a84d8b7d047c36bb3954f0b46529db725d7e62fb02f9ba53ccc" dependencies = [ "cc", "cxxbridge-flags", @@ -4587,60 +4596,60 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.106" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" +checksum = "3e5262a7fa3f0bae2a55b767c223ba98032d7c328f5c13fa5cdc980b77fc0658" dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "scratch", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] name = "cxxbridge-flags" -version = "1.0.106" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" +checksum = "be8dcadd2e2fb4a501e1d9e93d6e88e6ea494306d8272069c92d5a9edf8855c0" [[package]] name = "cxxbridge-macro" -version = "1.0.106" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" +checksum = "ad08a837629ad949b73d032c637653d069e909cffe4ee7870b02301939ce39cc" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.10", ] [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -4648,9 +4657,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" dependencies = [ "data-encoding", "syn 1.0.109", @@ -4667,9 +4676,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -4691,9 +4700,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derivative" @@ -4701,8 +4713,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -4712,8 +4724,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -4723,9 +4735,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -4735,8 +4747,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -4831,16 +4843,16 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "dissimilar" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "440d59c0c6d96354061909b4769b2ca03868dbaee203e7b779d9021ebbde3058" [[package]] name = "dleq_vrf" @@ -4849,7 +4861,7 @@ source = "git+https://github.com/w3f/ring-vrf?rev=e9782f9#e9782f938629c90f3adb3f dependencies = [ "ark-ec", "ark-ff 0.4.2", - "ark-scale 0.0.12", + "ark-scale", "ark-secret-scalar", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -4860,11 +4872,13 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" +checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d" dependencies = [ + "cfg-if", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -4891,12 +4905,12 @@ dependencies = [ "common-path", "derive-syn-parse 0.2.0", "once_cell", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex", - "syn 2.0.53", + "syn 2.0.60", "termcolor", - "toml 0.8.8", + "toml 0.8.12", "walkdir", ] @@ -4908,9 +4922,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dtoa" @@ -4940,29 +4954,29 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", "elliptic-curve", "rfc6979", "serdect", - "signature 2.1.0", + "signature 2.2.0", "spki", ] @@ -4977,12 +4991,12 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "signature 2.1.0", + "signature 2.2.0", ] [[package]] @@ -5001,12 +5015,12 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek 4.1.2", - "ed25519 2.2.2", + "ed25519 2.2.3", "rand_core 0.6.4", "serde", "sha2 0.10.8", @@ -5035,8 +5049,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ "curve25519-dalek 4.1.2", - "ed25519 2.2.2", - "hashbrown 0.14.3", + "ed25519 2.2.3", + "hashbrown 0.14.5", "hex", "rand_core 0.6.4", "sha2 0.10.8", @@ -5045,9 +5059,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elliptic-curve" @@ -5109,9 +5123,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -5123,8 +5137,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -5135,40 +5149,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "enumflags2" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "enumn" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -5193,9 +5207,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -5265,23 +5279,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -5331,6 +5334,17 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.14", +] + [[package]] name = "event-listener" version = "4.0.3" @@ -5339,7 +5353,18 @@ checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.14", ] [[package]] @@ -5349,7 +5374,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ "event-listener 4.0.3", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.0", + "pin-project-lite 0.2.14", ] [[package]] @@ -5369,28 +5404,29 @@ checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" dependencies = [ "blake3", "fs-err", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", ] [[package]] name = "expander" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +checksum = "00e83c02035136f1592a47964ea60c05a50e4ed8b5892cfac197063850898d4d" dependencies = [ "blake2 0.10.6", "fs-err", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "prettier-please", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -5419,9 +5455,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fastrlp" @@ -5453,8 +5489,8 @@ dependencies = [ "expander 0.0.4", "indexmap 1.9.3", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "thiserror", ] @@ -5510,9 +5546,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" [[package]] name = "file-per-thread-logger" @@ -5520,20 +5556,20 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.1", + "env_logger 0.10.2", "log", ] [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -5548,7 +5584,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "scale-info", ] @@ -5564,7 +5600,7 @@ dependencies = [ "futures", "log", "num-traits", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "relay-utils", ] @@ -5600,9 +5636,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "libz-sys", @@ -5648,9 +5684,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -5675,7 +5711,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" name = "frame-benchmarking" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-support", "frame-support-procedural", "frame-system", @@ -5703,9 +5739,9 @@ name = "frame-benchmarking-cli" version = "32.0.0" dependencies = [ "Inflector", - "array-bytes 6.1.0", + "array-bytes 6.2.2", "chrono", - "clap 4.5.3", + "clap 4.5.4", "comfy-table", "frame-benchmarking", "frame-support", @@ -5768,12 +5804,12 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", "scale-info", "sp-arithmetic", - "syn 2.0.53", + "syn 2.0.60", "trybuild", ] @@ -5799,7 +5835,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5817,7 +5853,7 @@ name = "frame-executive" version = "28.0.0" dependencies = [ "aquamarine 0.3.3", - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-support", "frame-system", "frame-try-runtime", @@ -5851,7 +5887,7 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "cumulus-primitives-proof-size-hostfunction", "env_logger 0.11.3", "frame-benchmarking-cli", @@ -5888,7 +5924,7 @@ name = "frame-support" version = "28.0.0" dependencies = [ "aquamarine 0.5.0", - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "bitflags 1.3.2", "docify", @@ -5935,16 +5971,16 @@ dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse 0.2.0", - "expander 2.0.0", + "expander 2.1.0", "frame-support-procedural-tools", "itertools 0.10.5", "macro_magic", "proc-macro-warning", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex", "sp-crypto-hashing", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -5952,19 +5988,19 @@ name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -6089,9 +6125,12 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fs2" @@ -6109,7 +6148,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.34", "windows-sys 0.48.0", ] @@ -6185,19 +6224,32 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite 0.2.14", +] + [[package]] name = "futures-macro" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -6207,7 +6259,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.8", + "rustls 0.20.9", "webpki", ] @@ -6225,9 +6277,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" @@ -6242,7 +6294,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "pin-utils", "slab", ] @@ -6312,9 +6364,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -6333,11 +6385,11 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "polyval", ] @@ -6354,9 +6406,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator 0.3.0", "stable_deref_trait", @@ -6428,9 +6480,9 @@ dependencies = [ [[package]] name = "governor" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ "cfg-if", "dashmap", @@ -6438,10 +6490,12 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.1", + "parking_lot 0.12.2", + "portable-atomic", "quanta", "rand 0.8.5", "smallvec", + "spinning_top", ] [[package]] @@ -6467,7 +6521,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.3", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -6476,15 +6530,19 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "handlebars" -version = "5.1.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", @@ -6524,16 +6582,16 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "allocator-api2", "serde", ] @@ -6544,7 +6602,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -6579,9 +6637,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -6603,9 +6661,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac 0.12.1", ] @@ -6640,6 +6698,15 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "honggfuzz" version = "0.5.55" @@ -6665,9 +6732,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -6676,13 +6743,13 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", ] [[package]] @@ -6711,9 +6778,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -6725,8 +6792,8 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.12", - "socket2 0.4.9", + "pin-project-lite 0.2.14", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -6735,15 +6802,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", "hyper", "log", - "rustls 0.21.6", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -6751,16 +6818,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core 0.52.0", ] [[package]] @@ -6793,23 +6860,33 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if-addrs" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "if-watch" -version = "3.0.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9465340214b296cd17a0009acdb890d6160010b8adf8f78a00d0d7ab270f79f" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "async-io", + "async-io 2.3.2", "core-foundation", "fnv", "futures", @@ -6819,7 +6896,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows 0.34.0", + "windows 0.51.1", ] [[package]] @@ -6866,8 +6943,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -6886,8 +6963,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", ] [[package]] @@ -6909,12 +6986,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -6925,9 +7002,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -6975,7 +7052,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -6992,7 +7069,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.6", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -7000,19 +7077,19 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.2", - "rustix 0.38.21", - "windows-sys 0.48.0", + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -7030,19 +7107,19 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" dependencies = [ - "async-channel", + "async-channel 1.9.0", "castaway", "crossbeam-utils", "curl", "curl-sys", "encoding_rs", "event-listener 2.5.3", - "futures-lite", + "futures-lite 1.13.0", "http", "log", "mime", "once_cell", - "polling", + "polling 2.8.0", "slab", "sluice", "tracing", @@ -7069,26 +7146,35 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -7112,9 +7198,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3ae45a64cfc0882934f963be9431b2a165d667f53140358181f262aca0702" +checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -7128,9 +7214,9 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455fc882e56f58228df2aee36b88a1340eafd707c76af2fa68cf94b37d461131" +checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" dependencies = [ "futures-util", "http", @@ -7149,19 +7235,18 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75568f4f9696e3a47426e1985b548e1a9fcb13372a5e320372acaf04aca30d1" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" dependencies = [ "anyhow", - "async-lock 3.3.0", "async-trait", "beef", "futures-timer", "futures-util", "hyper", "jsonrpsee-types", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "rand 0.8.5", "rustc-hash", @@ -7175,9 +7260,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7a95e346f55df84fb167b7e06470e196e7d5b9488a21d69c5d9732043ba7ba" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", "hyper", @@ -7195,22 +7280,22 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca066e73dd70294aebc5c2675d8ffae43be944af027c857ce0d4c51785f014" +checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" dependencies = [ "heck 0.4.1", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "jsonrpsee-server" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e29c1bd1f9bba83c864977c73404e505f74f730fa0db89dd490ec174e36d7f0" +checksum = "12d8b6a9674422a8572e0b0abb12feeb3f2aeda86528c80d0350c2bd0923ab41" dependencies = [ "futures-util", "http", @@ -7232,9 +7317,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" dependencies = [ "anyhow", "beef", @@ -7245,9 +7330,9 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.22.2" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca71e74983f624c0cb67828e480a981586074da8ad3a2f214c6a3f884edab9" +checksum = "58b9db2dfd5bb1194b0ce921504df9ceae210a345bc2f6c5a61432089bbab070" dependencies = [ "http", "jsonrpsee-client-transport", @@ -7272,9 +7357,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -7447,7 +7532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parking_lot 0.12.1", + "parking_lot 0.12.2", ] [[package]] @@ -7458,7 +7543,7 @@ checksum = "b644c70b92285f66bfc2032922a79000ea30af7bc2ab31902992a5dcb9b434f6" dependencies = [ "kvdb", "num_cpus", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "regex", "rocksdb", "smallvec", @@ -7475,9 +7560,9 @@ dependencies = [ [[package]] name = "landlock" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc" +checksum = "9baa9eeb6e315942429397e617a190f4fdc696ef1ee0342939d641029cbb4ea7" dependencies = [ "enumflags2", "libc", @@ -7504,9 +7589,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libflate" @@ -7541,25 +7626,25 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.52.5", ] [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libnghttp2-sys" -version = "0.1.9+1.58.0" +version = "0.1.10+1.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b57e858af2798e167e709b9d969325b6d8e9d50232fcbc494d7d54f976854a64" +checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" dependencies = [ "cc", "libc", @@ -7574,7 +7659,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.10", + "getrandom 0.2.14", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -7639,7 +7724,7 @@ dependencies = [ "multihash 0.17.0", "multistream-select", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "quick-protobuf", "rand 0.8.5", @@ -7659,7 +7744,7 @@ dependencies = [ "futures", "libp2p-core", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "smallvec", "trust-dns-resolver 0.22.0", ] @@ -7693,7 +7778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "276bb57e7af15d8f100d3c11cbdd32c6752b7eef4ba7a18ecf464972c07abcce" dependencies = [ "bs58 0.4.0", - "ed25519-dalek 2.1.0", + "ed25519-dalek 2.1.1", "log", "multiaddr", "multihash 0.17.0", @@ -7747,7 +7832,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "trust-dns-proto 0.22.0", "void", @@ -7821,10 +7906,10 @@ dependencies = [ "libp2p-identity", "libp2p-tls", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "quinn-proto", "rand 0.8.5", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "tokio", ] @@ -7873,7 +7958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" dependencies = [ "heck 0.4.1", - "quote 1.0.35", + "quote 1.0.36", "syn 1.0.109", ] @@ -7889,7 +7974,7 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", ] @@ -7905,7 +7990,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.16.20", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "webpki", "x509-parser 0.14.0", @@ -7937,7 +8022,7 @@ dependencies = [ "futures-rustls", "libp2p-core", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "quicksink", "rw-stream-sink", "soketto", @@ -7958,6 +8043,16 @@ dependencies = [ "yamux", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -8023,9 +8118,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" dependencies = [ "cc", "libc", @@ -8059,9 +8154,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" +checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" dependencies = [ "nalgebra", ] @@ -8080,9 +8175,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lioness" @@ -8127,14 +8222,14 @@ dependencies = [ "futures", "futures-timer", "hex-literal", - "indexmap 2.2.3", + "indexmap 2.2.6", "libc", "mockall", "multiaddr", "multihash 0.17.0", "network-interface", "nohash-hasher", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "prost 0.11.9", "prost-build", @@ -8142,13 +8237,13 @@ dependencies = [ "rand 0.8.5", "rcgen", "ring 0.16.20", - "rustls 0.20.8", + "rustls 0.20.9", "serde", "sha2 0.10.8", "simple-dns", "smallvec", "snow", - "socket2 0.5.6", + "socket2 0.5.7", "static_assertions", "str0m", "thiserror", @@ -8162,7 +8257,7 @@ dependencies = [ "unsigned-varint", "url", "webpki", - "x25519-dalek 2.0.0", + "x25519-dalek 2.0.1", "x509-parser 0.15.1", "yasna", "zeroize", @@ -8170,9 +8265,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -8208,9 +8303,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "lru-cache" @@ -8250,15 +8345,6 @@ dependencies = [ "libc", ] -[[package]] -name = "mach2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] - [[package]] name = "macro_magic" version = "0.5.0" @@ -8267,8 +8353,8 @@ checksum = "e03844fc635e92f3a0067e25fa4bf3e3dbf3f2927bf3aa01bb7bc8f1c428949d" dependencies = [ "macro_magic_core", "macro_magic_macros", - "quote 1.0.35", - "syn 2.0.53", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -8280,9 +8366,9 @@ dependencies = [ "const-random", "derive-syn-parse 0.1.5", "macro_magic_core_macros", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -8291,9 +8377,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -8303,8 +8389,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", - "quote 1.0.35", - "syn 2.0.53", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -8319,15 +8405,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matchers" version = "0.1.0" @@ -8345,9 +8422,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" dependencies = [ "autocfg", "rawpointer", @@ -8355,17 +8432,17 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.23", + "rustix 0.38.34", ] [[package]] @@ -8379,9 +8456,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -8404,15 +8481,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-db" version = "0.32.0" @@ -8447,7 +8515,7 @@ dependencies = [ "hex", "log", "num-traits", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "relay-utils", "sp-arithmetic", ] @@ -8492,7 +8560,7 @@ dependencies = [ name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "futures", "futures-timer", "jsonrpsee", @@ -8543,9 +8611,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -8577,7 +8645,7 @@ dependencies = [ "hashlink", "lioness", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", @@ -8593,7 +8661,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-offchain", @@ -8646,8 +8714,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -8753,8 +8821,8 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "synstructure", ] @@ -8778,8 +8846,8 @@ checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "synstructure", ] @@ -8806,9 +8874,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.3" +version = "0.32.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" dependencies = [ "approx", "matrixmultiply", @@ -8826,8 +8894,8 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -8902,9 +8970,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ "bytes", "futures", @@ -8915,9 +8983,9 @@ dependencies = [ [[package]] name = "network-interface" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae72fd9dbd7f55dda80c00d66acc3b2130436fcba9ea89118fc508eaae48dfb0" +checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" dependencies = [ "cc", "libc", @@ -8938,16 +9006,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", "pin-utils", - "static_assertions", ] [[package]] @@ -8956,7 +9023,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "cfg-if", "libc", ] @@ -8977,8 +9044,8 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "node-bench" version = "0.9.0-dev" dependencies = [ - "array-bytes 6.1.0", - "clap 4.5.3", + "array-bytes 6.2.2", + "clap 4.5.4", "derive_more", "fs_extra", "futures", @@ -9055,7 +9122,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "generate-bags", "kitchensink-runtime", ] @@ -9064,7 +9131,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "flate2", "fs_extra", "glob", @@ -9167,9 +9234,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" dependencies = [ "num-bigint", "num-complex", @@ -9192,13 +9259,19 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-format" version = "0.4.4" @@ -9211,19 +9284,18 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -9244,9 +9316,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -9258,7 +9330,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.9", "libc", ] @@ -9327,9 +9399,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" @@ -9337,7 +9409,7 @@ version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -9352,9 +9424,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -9414,13 +9486,13 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eedb646674596266dc9bb2b5c7eea7c36b32ecc7777eba0d510196972d72c4fd" dependencies = [ - "expander 2.0.0", - "indexmap 2.2.3", + "expander 2.1.0", + "indexmap 2.2.6", "itertools 0.11.0", "petgraph", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -9435,9 +9507,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "overload" @@ -9455,7 +9527,7 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" name = "pallet-alliance" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-benchmarking", "frame-support", "frame-system", @@ -9781,7 +9853,7 @@ dependencies = [ name = "pallet-beefy-mmr" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "binary-merkle-tree", "frame-support", "frame-system", @@ -10029,7 +10101,7 @@ dependencies = [ name = "pallet-contracts" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "bitflags 1.3.2", "env_logger 0.11.3", @@ -10081,7 +10153,7 @@ dependencies = [ "polkavm-linker", "sp-runtime", "tempfile", - "toml 0.8.8", + "toml 0.8.12", "twox-hash", ] @@ -10127,9 +10199,9 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -10247,7 +10319,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "scale-info", "sp-core", "sp-io", @@ -10270,7 +10342,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -10714,7 +10786,7 @@ dependencies = [ name = "pallet-mmr" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "env_logger 0.11.3", "frame-benchmarking", "frame-support", @@ -11207,7 +11279,7 @@ dependencies = [ name = "pallet-sassafras" version = "0.3.5-dev" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-benchmarking", "frame-support", "frame-system", @@ -11392,11 +11464,11 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", "sp-runtime", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -11427,7 +11499,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "scale-info", "serde", "sp-core", @@ -11576,7 +11648,7 @@ dependencies = [ name = "pallet-transaction-storage" version = "27.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-benchmarking", "frame-support", "frame-system", @@ -11801,7 +11873,7 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -12011,9 +12083,9 @@ checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" [[package]] name = "parity-db" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" +checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" dependencies = [ "blake2 0.10.6", "crc32fast", @@ -12023,17 +12095,18 @@ dependencies = [ "log", "lz4", "memmap2 0.5.10", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "siphasher", "snap", + "winapi", ] [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -12046,13 +12119,13 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro-crate 2.0.0", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -12074,7 +12147,7 @@ dependencies = [ "impl-trait-for-tuples", "lru 0.8.1", "parity-util-mem-derive", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "primitive-types", "smallvec", "winapi", @@ -12086,7 +12159,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.81", "syn 1.0.109", "synstructure", ] @@ -12099,9 +12172,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" @@ -12116,12 +12189,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.10", ] [[package]] @@ -12140,15 +12213,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -12475,25 +12548,26 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.2" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -12501,22 +12575,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -12530,27 +12604,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.2.6", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -12561,9 +12635,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -12571,6 +12645,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.1.0", + "futures-io", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -12583,15 +12668,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" -version = "3.0.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "plotters" @@ -12627,7 +12712,7 @@ version = "6.0.0" dependencies = [ "assert_cmd", "color-eyre", - "nix 0.26.2", + "nix 0.26.4", "polkadot-cli", "polkadot-core-primitives", "polkadot-node-core-pvf", @@ -12765,7 +12850,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.3", + "clap 4.5.4", "frame-benchmarking-cli", "futures", "log", @@ -12835,13 +12920,13 @@ name = "polkadot-dispute-distribution" version = "7.0.0" dependencies = [ "assert_matches", - "async-channel", + "async-channel 1.9.0", "async-trait", "derive_more", "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.2.6", "lazy_static", "parity-scale-codec", "polkadot-erasure-coding", @@ -12886,7 +12971,7 @@ dependencies = [ "futures", "futures-timer", "lazy_static", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -12920,7 +13005,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -12976,7 +13061,7 @@ dependencies = [ "log", "merlin", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13017,7 +13102,7 @@ dependencies = [ "kvdb-memorydb", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-erasure-coding", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -13133,7 +13218,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -13241,7 +13326,7 @@ name = "polkadot-node-core-pvf" version = "7.0.0" dependencies = [ "always-assert", - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "blake3", "cfg-if", @@ -13396,7 +13481,7 @@ dependencies = [ "log", "mick-jaeger", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-primitives", "polkadot-primitives", "sc-network", @@ -13411,7 +13496,7 @@ name = "polkadot-node-metrics" version = "7.0.0" dependencies = [ "assert_cmd", - "bs58 0.5.0", + "bs58 0.5.1", "futures", "futures-timer", "hyper", @@ -13436,7 +13521,7 @@ dependencies = [ name = "polkadot-node-network-protocol" version = "7.0.0" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-trait", "bitvec", "derive_more", @@ -13496,7 +13581,7 @@ version = "1.0.0" dependencies = [ "async-trait", "futures", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13558,7 +13643,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -13592,7 +13677,7 @@ dependencies = [ "futures", "futures-timer", "orchestra", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -13618,7 +13703,7 @@ dependencies = [ "async-trait", "bridge-hub-rococo-runtime", "bridge-hub-westend-runtime", - "clap 4.5.3", + "clap 4.5.4", "collectives-westend-runtime", "color-print", "contracts-rococo-runtime", @@ -13645,7 +13730,7 @@ dependencies = [ "hex-literal", "jsonrpsee", "log", - "nix 0.26.2", + "nix 0.26.4", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", @@ -13851,7 +13936,7 @@ dependencies = [ name = "polkadot-runtime-metrics" version = "7.0.0" dependencies = [ - "bs58 0.5.0", + "bs58 0.5.1", "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", @@ -14038,7 +14123,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -14145,12 +14230,12 @@ version = "7.0.0" dependencies = [ "arrayvec 0.7.4", "assert_matches", - "async-channel", + "async-channel 1.9.0", "bitvec", "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.2.6", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -14191,7 +14276,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.3", + "clap 4.5.4", "clap-num", "color-eyre", "colored", @@ -14287,7 +14372,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.3", + "clap 4.5.4", "color-eyre", "futures", "futures-timer", @@ -14430,7 +14515,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "generate-bags", "sp-io", "westend-runtime", @@ -14483,9 +14568,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -14495,7 +14580,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -14504,8 +14589,8 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ - "gimli 0.28.0", - "hashbrown 0.14.3", + "gimli 0.28.1", + "hashbrown 0.14.5", "log", "object 0.32.2", "polkavm-common", @@ -14531,10 +14616,25 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "windows-sys 0.48.0", ] +[[package]] +name = "polling" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.3.9", + "pin-project-lite 0.2.14", + "rustix 0.38.34", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "poly1305" version = "0.8.0" @@ -14542,27 +14642,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.4.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "portpicker" @@ -14573,6 +14673,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pprof" version = "0.12.1" @@ -14584,9 +14690,9 @@ dependencies = [ "findshlibs", "libc", "log", - "nix 0.26.2", + "nix 0.26.4", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "smallvec", "symbolic-demangle", "tempfile", @@ -14615,13 +14721,12 @@ dependencies = [ [[package]] name = "predicates" -version = "3.0.3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" dependencies = [ "anstyle", "difflib", - "itertools 0.10.5", "predicates-core", ] @@ -14641,6 +14746,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettier-please" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" +dependencies = [ + "proc-macro2 1.0.81", + "syn 2.0.60", +] + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -14653,29 +14768,29 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "f28f53e8b192565862cf99343194579a022eb9c7dd3a8d03134734803c7b3125" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.81", "syn 1.0.109", ] [[package]] name = "prettyplease" -version = "0.2.12" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" dependencies = [ - "proc-macro2 1.0.75", - "syn 2.0.53", + "proc-macro2 1.0.81", + "syn 2.0.60", ] [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -14714,11 +14829,20 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.0.0" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit 0.21.0", + "toml_edit 0.21.1", ] [[package]] @@ -14728,8 +14852,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "version_check", ] @@ -14740,26 +14864,20 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro-warning" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" +checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -14773,9 +14891,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -14786,13 +14904,13 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "chrono", "flate2", "hex", "lazy_static", "procfs-core", - "rustix 0.38.21", + "rustix 0.38.34", ] [[package]] @@ -14801,7 +14919,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "chrono", "hex", ] @@ -14816,7 +14934,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "thiserror", ] @@ -14828,7 +14946,7 @@ checksum = "5d6fa99d535dd930d1249e6c79cb3c2915f9172a540fe2b02a4c8f9ca954721e" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "prometheus-client-derive-encode", ] @@ -14838,19 +14956,19 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "prometheus-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2aa5feb83bf4b2c8919eaf563f51dbab41183de73ba2353c0e03cd7b6bd892" +checksum = "811031bea65e5a401fb2e1f37d802cca6601e204ac463809a3189352d13b78a5" dependencies = [ "chrono", - "itertools 0.10.5", + "itertools 0.12.1", "once_cell", "regex", ] @@ -14863,13 +14981,13 @@ checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.4.0", + "bitflags 2.5.0", "lazy_static", "num-traits", "rand 0.8.5", "rand_chacha 0.3.1", "rand_xorshift", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "rusty-fork", "tempfile", "unarray", @@ -14887,12 +15005,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", - "prost-derive 0.12.3", + "prost-derive 0.12.4", ] [[package]] @@ -14908,7 +15026,7 @@ dependencies = [ "log", "multimap", "petgraph", - "prettyplease 0.1.25", + "prettyplease 0.1.11", "prost 0.11.9", "prost-types", "regex", @@ -14925,22 +15043,22 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "prost-derive" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" dependencies = [ "anyhow", - "itertools 0.11.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "itertools 0.12.1", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -14993,13 +15111,12 @@ dependencies = [ [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", "wasi 0.11.0+wasi-snapshot-preview1", @@ -15064,11 +15181,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" dependencies = [ "bytes", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "thiserror", "tokio", "tracing", @@ -15077,15 +15194,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" +checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" dependencies = [ "bytes", "rand 0.8.5", "ring 0.16.20", "rustc-hash", - "rustls 0.20.8", + "rustls 0.20.9", "slab", "thiserror", "tinyvec", @@ -15101,7 +15218,7 @@ checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ "libc", "quinn-proto", - "socket2 0.4.9", + "socket2 0.4.10", "tracing", "windows-sys 0.42.0", ] @@ -15117,11 +15234,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.75", + "proc-macro2 1.0.81", ] [[package]] @@ -15189,7 +15306,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.10", + "getrandom 0.2.14", ] [[package]] @@ -15231,11 +15348,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] @@ -15307,30 +15424,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.10", - "redox_syscall 0.2.16", + "getrandom 0.2.14", + "libredox", "thiserror", ] @@ -15348,22 +15465,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -15393,14 +15510,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", ] [[package]] @@ -15414,19 +15531,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" - -[[package]] -name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", ] [[package]] @@ -15437,9 +15548,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "relative-path" @@ -15517,7 +15628,7 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -15530,11 +15641,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.21.2", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -15550,12 +15661,14 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.12", - "rustls 0.21.6", - "rustls-pemfile 1.0.3", + "pin-project-lite 0.2.14", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-rustls 0.24.1", "tower-service", @@ -15563,7 +15676,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", "winreg", ] @@ -15620,16 +15733,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "getrandom 0.2.10", + "cfg-if", + "getrandom 0.2.14", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -15890,13 +16004,13 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -15919,12 +16033,12 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.53", + "syn 2.0.60", "unicode-ident", ] @@ -15945,19 +16059,19 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "ruint" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +checksum = "8f308135fef9fc398342da5472ce7c484529df23743fb7c734e0f3d472971e62" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -15979,9 +16093,9 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" +checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" [[package]] name = "rustc-demangle" @@ -16025,7 +16139,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.18", + "semver 1.0.22", ] [[package]] @@ -16039,9 +16153,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.15" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -16053,9 +16167,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", @@ -16067,22 +16181,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" dependencies = [ "log", "ring 0.16.20", @@ -16092,26 +16206,26 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.16.20", - "rustls-webpki 0.101.4", + "ring 0.17.8", + "rustls-webpki 0.101.7", "sct", ] [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.2", + "rustls-webpki 0.102.3", "subtle 2.5.0", "zeroize", ] @@ -16123,7 +16237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.3", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] @@ -16135,7 +16249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile 2.0.0", + "rustls-pemfile 2.1.2", "rustls-pki-types", "schannel", "security-framework", @@ -16143,55 +16257,55 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.2", + "base64 0.21.7", ] [[package]] name = "rustls-pemfile" -version = "2.0.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.21.2", + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.2.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" +checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "rustls-webpki" -version = "0.102.2" +version = "0.102.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" [[package]] name = "rusty-fork" @@ -16229,9 +16343,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "safe-mix" @@ -16284,7 +16398,7 @@ dependencies = [ "multihash 0.17.0", "multihash-codetable", "parity-scale-codec", - "prost 0.12.3", + "prost 0.12.4", "prost-build", "quickcheck", "rand 0.8.5", @@ -16311,7 +16425,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -16348,10 +16462,10 @@ dependencies = [ name = "sc-chain-spec" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "docify", "log", - "memmap2 0.9.3", + "memmap2 0.9.4", "parity-scale-codec", "sc-chain-spec-derive", "sc-client-api", @@ -16378,19 +16492,19 @@ dependencies = [ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "sc-cli" version = "0.36.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "chrono", - "clap 4.5.3", + "clap 4.5.4", "fdlimit", "futures", "futures-timer", @@ -16435,7 +16549,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -16460,7 +16574,7 @@ dependencies = [ name = "sc-client-db" version = "0.35.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "criterion 0.4.0", "hash-db", "kitchensink-runtime", @@ -16471,7 +16585,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "quickcheck", "rand 0.8.5", "sc-client-api", @@ -16498,7 +16612,7 @@ dependencies = [ "futures-timer", "log", "mockall", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-client-api", "sc-network-types", "sc-utils", @@ -16522,7 +16636,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16564,7 +16678,7 @@ dependencies = [ "num-rational", "num-traits", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16626,14 +16740,14 @@ dependencies = [ name = "sc-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", - "async-channel", + "array-bytes 6.2.2", + "async-channel 1.9.0", "async-trait", "fnv", "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16674,7 +16788,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-consensus-beefy", "sc-rpc", "serde", @@ -16703,8 +16817,8 @@ dependencies = [ name = "sc-consensus-grandpa" version = "0.19.0" dependencies = [ - "ahash 0.8.8", - "array-bytes 6.1.0", + "ahash 0.8.11", + "array-bytes 6.2.2", "assert_matches", "async-trait", "dyn-clone", @@ -16714,7 +16828,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "sc-block-builder", "sc-chain-spec", @@ -16820,7 +16934,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-client-api", "sc-consensus", "sp-api", @@ -16862,13 +16976,13 @@ dependencies = [ name = "sc-executor" version = "0.32.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "criterion 0.4.0", "env_logger 0.11.3", "num_cpus", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "paste", "regex", "sc-executor-common", @@ -16894,7 +17008,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", "wat", ] @@ -16930,9 +17044,9 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "paste", - "rustix 0.36.15", + "rustix 0.36.17", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -16964,8 +17078,8 @@ dependencies = [ name = "sc-keystore" version = "25.0.0" dependencies = [ - "array-bytes 6.1.0", - "parking_lot 0.12.1", + "array-bytes 6.2.2", + "parking_lot 0.12.2", "serde_json", "sp-application-crypto", "sp-core", @@ -16988,7 +17102,7 @@ dependencies = [ "mixnet", "multiaddr", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-client-api", "sc-network", "sc-network-types", @@ -17006,9 +17120,9 @@ dependencies = [ name = "sc-network" version = "0.34.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", - "async-channel", + "async-channel 1.9.0", "async-trait", "asynchronous-codec", "bytes", @@ -17026,7 +17140,7 @@ dependencies = [ "multistream-select", "once_cell", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "partial_sort", "pin-project", "prost 0.11.9", @@ -17088,7 +17202,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.34.0" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "async-trait", "futures", "futures-timer", @@ -17112,12 +17226,12 @@ dependencies = [ name = "sc-network-light" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", - "async-channel", + "array-bytes 6.2.2", + "async-channel 1.9.0", "futures", "log", "parity-scale-codec", - "prost 0.12.3", + "prost 0.12.4", "prost-build", "sc-client-api", "sc-network", @@ -17132,8 +17246,8 @@ dependencies = [ name = "sc-network-statement" version = "0.16.0" dependencies = [ - "array-bytes 6.1.0", - "async-channel", + "array-bytes 6.2.2", + "async-channel 1.9.0", "futures", "libp2p", "log", @@ -17152,8 +17266,8 @@ dependencies = [ name = "sc-network-sync" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", - "async-channel", + "array-bytes 6.2.2", + "async-channel 1.9.0", "async-trait", "fork-tree", "futures", @@ -17162,7 +17276,7 @@ dependencies = [ "log", "mockall", "parity-scale-codec", - "prost 0.12.3", + "prost 0.12.4", "prost-build", "quickcheck", "sc-block-builder", @@ -17198,7 +17312,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17224,7 +17338,7 @@ dependencies = [ name = "sc-network-transactions" version = "0.33.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "futures", "libp2p", "log", @@ -17256,7 +17370,7 @@ dependencies = [ name = "sc-offchain" version = "29.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "async-trait", "bytes", "fnv", @@ -17270,7 +17384,7 @@ dependencies = [ "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17313,7 +17427,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pretty_assertions", "sc-block-builder", "sc-chain-spec", @@ -17342,7 +17456,7 @@ dependencies = [ "sp-version", "substrate-test-runtime-client", "tokio", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -17385,7 +17499,7 @@ dependencies = [ name = "sc-rpc-spec-v2" version = "0.34.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "futures", "futures-util", @@ -17393,7 +17507,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pretty_assertions", "rand 0.8.5", "sc-block-builder", @@ -17448,7 +17562,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "rand 0.8.5", "sc-chain-spec", @@ -17505,13 +17619,13 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ - "array-bytes 6.1.0", - "async-channel", + "array-bytes 6.2.2", + "async-channel 1.9.0", "fdlimit", "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -17543,7 +17657,7 @@ version = "0.30.0" dependencies = [ "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sp-core", ] @@ -17554,7 +17668,7 @@ dependencies = [ "env_logger 0.11.3", "log", "parity-db", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-client-api", "sc-keystore", "sp-api", @@ -17571,7 +17685,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "fs4", "log", "sp-core", @@ -17626,7 +17740,7 @@ dependencies = [ "futures", "libp2p", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "rand 0.8.5", "sc-network", @@ -17649,7 +17763,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "regex", "rustc-hash", "sc-client-api", @@ -17663,25 +17777,25 @@ dependencies = [ "sp-tracing 16.0.0", "thiserror", "tracing", - "tracing-log 0.1.3", - "tracing-subscriber 0.3.18", + "tracing-log 0.1.4", + "tracing-subscriber", ] [[package]] name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "sc-transaction-pool" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "async-trait", "criterion 0.4.0", @@ -17690,7 +17804,7 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-block-builder", "sc-client-api", "sc-transaction-pool-api", @@ -17731,12 +17845,12 @@ dependencies = [ name = "sc-utils" version = "14.0.0" dependencies = [ - "async-channel", + "async-channel 1.9.0", "futures", "futures-timer", "lazy_static", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "prometheus", "sp-arithmetic", "tokio-test", @@ -17744,9 +17858,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.1" +version = "2.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" dependencies = [ "bitvec", "cfg-if", @@ -17758,30 +17872,30 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.1" +version = "2.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc2f4e8bc344b9fc3d5f74f72c2e55bfc38d28dc2ebc69c194a3df424e4d9ac" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "schemars" -version = "0.8.13" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "7f55c82c700538496bdc329bb4918a81f87cc8888811bd123cf325a0f2f8d309" dependencies = [ "dyn-clone", "schemars_derive", @@ -17791,14 +17905,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "83263746fe5e32097f06356968a077f96089739c927a61450efa069905eec108" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.60", ] [[package]] @@ -17807,7 +17921,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "cfg-if", "hashbrown 0.13.2", ] @@ -17867,12 +17981,12 @@ checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -17916,18 +18030,18 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ "secp256k1-sys", ] [[package]] name = "secp256k1-sys" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] @@ -17943,9 +18057,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -17956,9 +18070,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -18028,9 +18142,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] @@ -18058,9 +18172,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -18076,33 +18190,33 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 1.0.109", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -18116,11 +18230,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -18128,9 +18242,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -18149,11 +18263,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.33" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -18180,7 +18294,7 @@ dependencies = [ "futures", "lazy_static", "log", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "serial_test_derive", ] @@ -18190,9 +18304,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -18205,7 +18319,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -18250,7 +18364,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -18276,9 +18390,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -18326,21 +18440,11 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -18353,9 +18457,9 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -18380,7 +18484,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae9a3fcdadafb6d97f4c0e007e4247b114ee0f119f650c3cbf3a8b3a1479694" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", ] [[package]] @@ -18423,9 +18527,9 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -18436,16 +18540,16 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" dependencies = [ - "async-channel", + "async-channel 1.9.0", "futures-core", "futures-io", ] [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smol" @@ -18453,24 +18557,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-executor", "async-fs", - "async-io", + "async-io 1.13.0", "async-lock 2.8.0", "async-net", "async-process", "blocking", - "futures-lite", -] - -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", + "futures-lite 1.13.0", ] [[package]] @@ -18482,10 +18577,10 @@ dependencies = [ "arrayvec 0.7.4", "async-lock 2.8.0", "atomic-take", - "base64 0.21.2", + "base64 0.21.7", "bip39", "blake2-rfc", - "bs58 0.5.0", + "bs58 0.5.1", "chacha20", "crossbeam-queue", "derive_more", @@ -18493,9 +18588,9 @@ dependencies = [ "either", "event-listener 2.5.3", "fnv", - "futures-lite", + "futures-lite 1.13.0", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "hmac 0.12.1", "itertools 0.11.0", @@ -18523,7 +18618,7 @@ dependencies = [ "soketto", "twox-hash", "wasmi", - "x25519-dalek 2.0.0", + "x25519-dalek 2.0.1", "zeroize", ] @@ -18533,24 +18628,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-lock 2.8.0", - "base64 0.21.2", + "base64 0.21.7", "blake2-rfc", "derive_more", "either", "event-listener 2.5.3", "fnv", "futures-channel", - "futures-lite", + "futures-lite 1.13.0", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "itertools 0.11.0", "log", - "lru 0.11.0", + "lru 0.11.1", "no-std-net", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pin-project", "rand 0.8.5", "rand_chacha 0.3.1", @@ -18565,9 +18660,9 @@ dependencies = [ [[package]] name = "snap" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snow" @@ -18580,7 +18675,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.1.2", "rand_core 0.6.4", - "ring 0.17.7", + "ring 0.17.8", "rustc_version 0.4.0", "sha2 0.10.8", "subtle 2.5.0", @@ -18909,9 +19004,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -18919,9 +19014,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -18948,7 +19043,7 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "frame-benchmarking-cli", "frame-system", "futures", @@ -19053,11 +19148,11 @@ dependencies = [ "Inflector", "assert_matches", "blake2 0.10.6", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "expander 2.1.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -19141,7 +19236,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-bls12-381-ext", - "sp-crypto-ec-utils 0.4.1", + "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -19150,7 +19245,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils 0.4.1", + "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -19180,7 +19275,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "schnellru", "sp-api", "sp-consensus", @@ -19241,7 +19336,7 @@ dependencies = [ name = "sp-consensus-beefy" version = "13.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "lazy_static", "parity-scale-codec", "scale-info", @@ -19312,12 +19407,12 @@ dependencies = [ name = "sp-core" version = "28.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "bandersnatch_vrfs", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", - "bs58 0.5.0", + "bs58 0.5.1", "criterion 0.4.0", "dyn-clonable", "ed25519-zebra 3.1.0", @@ -19333,7 +19428,7 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "paste", "primitive-types", "rand 0.8.5", @@ -19384,8 +19479,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" -version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "0.10.0" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -19398,14 +19492,14 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.11", - "sp-runtime-interface 17.0.0", - "sp-std 8.0.0", + "ark-scale", + "sp-runtime-interface 24.0.0", ] [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -19418,8 +19512,8 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.12", - "sp-runtime-interface 24.0.0", + "ark-scale", + "sp-runtime-interface 24.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -19440,9 +19534,9 @@ dependencies = [ name = "sp-crypto-hashing-proc-macro" version = "0.1.0" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "sp-crypto-hashing", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] @@ -19450,46 +19544,45 @@ name = "sp-database" version = "10.0.0" dependencies = [ "kvdb", - "parking_lot 0.12.1", + "parking_lot 0.12.2", ] [[package]] name = "sp-debug-derive" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "14.0.0" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "sp-debug-derive" version = "14.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "sp-externalities" -version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "0.25.0" dependencies = [ "environmental", "parity-scale-codec", - "sp-std 8.0.0", - "sp-storage 13.0.0", + "sp-storage 19.0.0", ] [[package]] name = "sp-externalities" version = "0.25.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 19.0.0", + "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -19521,7 +19614,7 @@ name = "sp-io" version = "30.0.0" dependencies = [ "bytes", - "ed25519-dalek 2.1.0", + "ed25519-dalek 2.1.1", "libsecp256k1", "log", "parity-scale-codec", @@ -19555,7 +19648,7 @@ name = "sp-keystore" version = "0.34.0" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "rand_chacha 0.2.2", "sp-core", @@ -19593,7 +19686,7 @@ dependencies = [ name = "sp-mmr-primitives" version = "26.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "ckb-merkle-mountain-range", "log", "parity-scale-codec", @@ -19624,7 +19717,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "honggfuzz", "rand 0.8.5", "sp-npos-elections", @@ -19688,24 +19781,6 @@ dependencies = [ "zstd 0.12.4", ] -[[package]] -name = "sp-runtime-interface" -version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "primitive-types", - "sp-externalities 0.19.0", - "sp-runtime-interface-proc-macro 11.0.0", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-tracing 10.0.0", - "sp-wasm-interface 14.0.0", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "24.0.0" @@ -19730,28 +19805,48 @@ dependencies = [ "trybuild", ] +[[package]] +name = "sp-runtime-interface" +version = "24.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive", + "primitive-types", + "sp-externalities 0.25.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-runtime-interface-proc-macro 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-wasm-interface 20.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "static_assertions", +] + [[package]] name = "sp-runtime-interface-proc-macro" -version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "17.0.0" dependencies = [ "Inflector", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "expander 2.1.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ "Inflector", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "expander 2.1.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -19821,12 +19916,12 @@ dependencies = [ name = "sp-state-machine" version = "0.35.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_matches", "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "pretty_assertions", "rand 0.8.5", "smallvec", @@ -19846,7 +19941,7 @@ version = "10.0.0" dependencies = [ "aes-gcm", "curve25519-dalek 4.1.2", - "ed25519-dalek 2.1.0", + "ed25519-dalek 2.1.1", "hkdf", "parity-scale-codec", "rand 0.8.5", @@ -19860,40 +19955,39 @@ dependencies = [ "sp-runtime", "sp-runtime-interface 24.0.0", "thiserror", - "x25519-dalek 2.0.0", + "x25519-dalek 2.0.1", ] [[package]] name = "sp-std" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "14.0.0" [[package]] name = "sp-std" version = "14.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" [[package]] name = "sp-storage" -version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "19.0.0" dependencies = [ "impl-serde", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 8.0.0", - "sp-std 8.0.0", + "sp-debug-derive 14.0.0", ] [[package]] name = "sp-storage" version = "19.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ "impl-serde", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 14.0.0", + "sp-debug-derive 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -19921,24 +20015,23 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "16.0.0" dependencies = [ "parity-scale-codec", - "sp-std 8.0.0", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber", ] [[package]] name = "sp-tracing" version = "16.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -19966,15 +20059,15 @@ dependencies = [ name = "sp-trie" version = "29.0.0" dependencies = [ - "ahash 0.8.8", - "array-bytes 6.1.0", + "ahash 0.8.11", + "array-bytes 6.2.2", "criterion 0.5.1", "hash-db", "lazy_static", "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "scale-info", "schnellru", @@ -20010,34 +20103,31 @@ name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "sp-version", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] name = "sp-wasm-interface" -version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "20.0.0" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 8.0.0", "wasmtime", ] [[package]] name = "sp-wasm-interface" version = "20.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#4e0b3abbd696c809aebd8d5e64a671abf843087f" dependencies = [ - "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", - "wasmtime", ] [[package]] @@ -20068,20 +20158,29 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spinners" -version = "4.1.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" +checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" dependencies = [ "lazy_static", "maplit", "strum 0.24.1", ] +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -20089,14 +20188,14 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.43.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" +checksum = "4743ce898933fbff7bbf414f497c459a782d496269644b3d650a398ae6a487ba" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "serde", "serde_json", "unicode-xid 0.2.4", @@ -20120,8 +20219,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -20135,7 +20234,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "log", "sc-chain-spec", "serde_json", @@ -20146,9 +20245,9 @@ dependencies = [ name = "staging-node-cli" version = "3.0.0-dev" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "assert_cmd", - "clap 4.5.3", + "clap 4.5.4", "clap_complete", "criterion 0.4.0", "frame-benchmarking", @@ -20161,7 +20260,7 @@ dependencies = [ "kitchensink-runtime", "log", "mmr-gadget", - "nix 0.26.2", + "nix 0.26.4", "node-primitives", "node-rpc", "node-testing", @@ -20258,7 +20357,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -20292,7 +20391,7 @@ version = "2.0.0" name = "staging-xcm" version = "7.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "bounded-collections", "derivative", "environmental", @@ -20388,8 +20487,8 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -20440,9 +20539,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "structopt" @@ -20463,8 +20562,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", ] @@ -20477,12 +20576,6 @@ dependencies = [ "strum_macros 0.24.3", ] -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "strum" version = "0.26.2" @@ -20499,25 +20592,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "rustversion", "syn 1.0.109", ] -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.75", - "quote 1.0.35", - "rustversion", - "syn 2.0.53", -] - [[package]] name = "strum_macros" version = "0.26.2" @@ -20525,17 +20605,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "rustversion", - "syn 2.0.53", + "syn 2.0.60", ] [[package]] name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "sc-cli", ] @@ -20562,7 +20642,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "futures", - "nix 0.26.2", + "nix 0.26.4", "node-primitives", "regex", "sc-cli", @@ -20577,7 +20657,7 @@ dependencies = [ name = "substrate-frame-cli" version = "32.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "frame-support", "frame-system", "sc-cli", @@ -20714,7 +20794,7 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "async-trait", "futures", "parity-scale-codec", @@ -20740,7 +20820,7 @@ dependencies = [ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ - "array-bytes 6.1.0", + "array-bytes 6.2.2", "frame-executive", "frame-support", "frame-system", @@ -20810,7 +20890,7 @@ version = "2.0.0" dependencies = [ "futures", "parity-scale-codec", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -20842,7 +20922,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum 0.26.2", "tempfile", - "toml 0.8.8", + "toml 0.8.12", "walkdir", "wasm-opt", ] @@ -20867,15 +20947,15 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "sval" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1" +checksum = "53eb957fbc79a55306d5d25d87daf3627bc3800681491cda0709eef36c748bfe" [[package]] name = "sval_buffer" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028" +checksum = "96e860aef60e9cbf37888d4953a13445abf523c534640d1f6174d310917c410d" dependencies = [ "sval", "sval_ref", @@ -20883,18 +20963,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf" +checksum = "ea3f2b07929a1127d204ed7cb3905049381708245727680e9139dac317ed556f" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326" +checksum = "c4e188677497de274a1367c4bda15bd2296de4070d91729aac8f0a09c1abf64d" dependencies = [ "itoa", "ryu", @@ -20903,53 +20983,63 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d" +checksum = "32f456c07dae652744781f2245d5e3b78e6a9ebad70790ac11eb15dbdbce5282" dependencies = [ "itoa", "ryu", "sval", ] +[[package]] +name = "sval_nested" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "886feb24709f0476baaebbf9ac10671a50163caa7e439d7a7beb7f6d81d0a6fb" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + [[package]] name = "sval_ref" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c" +checksum = "be2e7fc517d778f44f8cb64140afa36010999565528d48985f55e64d45f369ce" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.6.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046" +checksum = "79bf66549a997ff35cd2114a27ac4b0c2843280f2cfa84b240d169ecaa0add46" dependencies = [ "serde", "sval", - "sval_buffer", - "sval_fmt", + "sval_nested", ] [[package]] name = "symbolic-common" -version = "12.3.0" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167a4ffd7c35c143fd1030aa3c2caf76ba42220bd5a6b5f4781896434723b8c3" +checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" dependencies = [ "debugid", - "memmap2 0.5.10", + "memmap2 0.9.4", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "12.3.0" +version = "12.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e378c50e80686c1c5c205674e1f86a2858bec3d2a7dfdd690331a8a19330f293" +checksum = "76a99812da4020a67e76c4eb41f08c87364c14170495ff780f30dd519c221a68" dependencies = [ "cpp_demangle 0.4.3", "rustc-demangle", @@ -20973,19 +21063,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.53" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "unicode-ident", ] @@ -20996,28 +21086,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "syn 1.0.109", "unicode-xid 0.2.4", ] [[package]] name = "sysinfo" -version = "0.30.5" +version = "0.30.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +checksum = "87341a165d73787554941cd5ef55ad728011566fe714e987d1b976c15dbc3a83" dependencies = [ "cfg-if", "core-foundation-sys", @@ -21068,28 +21164,27 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.0", - "redox_syscall 0.4.1", - "rustix 0.38.21", - "windows-sys 0.48.0", + "fastrand 2.1.0", + "rustix 0.38.34", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -21100,7 +21195,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.34", "windows-sys 0.48.0", ] @@ -21127,7 +21222,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "futures", "futures-timer", "log", @@ -21175,7 +21270,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.4", "futures", "futures-timer", "log", @@ -21243,48 +21338,48 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-core" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" dependencies = [ "thiserror-core-impl", ] [[package]] name = "thiserror-core-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 1.0.109", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -21295,9 +21390,9 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -21358,14 +21453,16 @@ dependencies = [ [[package]] name = "time" -version = "0.3.27" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb39ee79a6d8de55f48f2293a830e040392f1c5f16e336bdd1788cd0aadce07" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "libc", + "num-conv", "num_threads", + "powerfmt", "serde", "time-core", "time-macros", @@ -21373,16 +21470,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.13" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "733d258752e9303d392b94b75230d07b0b9c489350c69b851fc6c065fde3e8f9" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -21431,10 +21529,10 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", - "pin-project-lite 0.2.12", + "parking_lot 0.12.2", + "pin-project-lite 0.2.14", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -21445,9 +21543,9 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -21467,7 +21565,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.6", + "rustls 0.21.12", "tokio", ] @@ -21477,28 +21575,28 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.22.2", + "rustls 0.22.4", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "tokio", "tokio-util", ] [[package]] name = "tokio-test" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ "async-stream", "bytes", @@ -21527,7 +21625,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.6", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -21536,15 +21634,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "tokio", "tracing", ] @@ -21560,14 +21658,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit 0.22.12", ] [[package]] @@ -21585,22 +21683,44 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.7", ] [[package]] @@ -21612,7 +21732,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "tower-layer", "tower-service", "tracing", @@ -21620,18 +21740,18 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "bytes", "futures-core", "futures-util", "http", "http-body", "http-range-header", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "tower-layer", "tower-service", ] @@ -21655,7 +21775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite 0.2.12", + "pin-project-lite 0.2.14", "tracing-attributes", "tracing-core", ] @@ -21666,9 +21786,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -21706,21 +21826,21 @@ name = "tracing-gum-proc-macro" version = "5.0.0" dependencies = [ "assert_matches", - "expander 2.0.0", - "proc-macro-crate 3.0.0", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "expander 2.1.0", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -21735,38 +21855,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers 0.0.1", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log 0.1.3", - "tracing-serde", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -21774,10 +21862,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "chrono", - "matchers 0.1.0", + "matchers", "nu-ansi-term", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "regex", "sharded-slab", "smallvec", @@ -21852,7 +21940,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tinyvec", "tokio", @@ -21896,7 +21984,7 @@ dependencies = [ "ipconfig", "lazy_static", "lru-cache", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "resolv-conf", "smallvec", "thiserror", @@ -21916,7 +22004,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "resolv-conf", "smallvec", @@ -21928,17 +22016,16 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" +checksum = "8ad7eb6319ebadebca3dacf1f85a93bc54b73dd81b9036795f73de7ddfe27d5a" dependencies = [ - "basic-toml", "dissimilar", "glob", "once_cell", @@ -21946,6 +22033,7 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", + "toml 0.8.12", ] [[package]] @@ -21986,7 +22074,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls 0.21.6", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -22013,9 +22101,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -22043,15 +22131,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -22070,9 +22158,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -22129,12 +22217,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna 0.5.0", "percent-encoding", ] @@ -22152,9 +22240,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" [[package]] name = "valuable" @@ -22164,9 +22252,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec26a25bd6fca441cdd0f769fd7f891bae119f996de31f86a5eddccef54c1d" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -22174,9 +22262,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead5b693d906686203f19a49e88c477fb8c15798b68cf72f60b4b5521b4ad891" +checksum = "ccacf50c5cb077a9abb723c5bcb5e0754c1a433f1e1de89edc328e2760b6328b" dependencies = [ "erased-serde", "serde", @@ -22185,9 +22273,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9d0f4a816370c3a0d7d82d603b62198af17675b12fe5e91de6b47ceb505882" +checksum = "1785bae486022dfb9703915d42287dcb284c1ee37bd1080eeba78cc04721285b" dependencies = [ "sval", "sval_buffer", @@ -22257,15 +22345,15 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -22292,11 +22380,20 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasix" +version = "0.12.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d" +dependencies = [ + "wasi 0.11.0+wasi-snapshot-preview1", +] + [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "serde", @@ -22306,24 +22403,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -22333,38 +22430,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "quote 1.0.35", + "quote 1.0.36", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wasm-bindgen-test" -version = "0.3.37" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" dependencies = [ "console_error_panic_hook", "js-sys", @@ -22376,19 +22473,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.37" +version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.206.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "d759312e1137f199096d80a70be685899cd7d3d09c572836bb2e9b69b4dc3b1e" dependencies = [ "leb128", ] @@ -22404,9 +22502,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.116.0" +version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" dependencies = [ "anyhow", "libc", @@ -22500,9 +22598,9 @@ dependencies = [ [[package]] name = "wasmparser-nostd" -version = "0.100.1" +version = "0.100.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157cab83003221bfd385833ab587a039f5d6fa7304854042ba358a3b09e0724" +checksum = "d5a015fe95f3504a94bb1462c717aae75253e39b9dd6c3fb1062c934535c64aa" dependencies = [ "indexmap-nostd", ] @@ -22551,12 +22649,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.2", + "base64 0.21.7", "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.15", + "rustix 0.36.17", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -22652,7 +22750,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.15", + "rustix 0.36.17", ] [[package]] @@ -22683,7 +22781,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand 0.8.5", - "rustix 0.36.15", + "rustix 0.36.17", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -22704,10 +22802,11 @@ dependencies = [ [[package]] name = "wast" -version = "63.0.0" +version = "206.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" +checksum = "68586953ee4960b1f5d84ebf26df3b628b17e6173bc088e0acfbce431469795a" dependencies = [ + "bumpalo", "leb128", "memchr", "unicode-width", @@ -22716,18 +22815,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.70" +version = "1.206.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" +checksum = "da4c6f2606276c6e991aebf441b2fc92c517807393f039992a3e0ad873efe4ad" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -22739,7 +22838,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -22754,9 +22853,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "westend-emulated-chain" @@ -22918,20 +23017,21 @@ dependencies = [ [[package]] name = "which" -version = "4.4.0" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix 0.38.34", ] [[package]] name = "wide" -version = "0.7.11" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" +checksum = "0f0e39d2c603fdc0504b12b458cf1f34e0b937ed2f4f2dc20796e3e86f34e11f" dependencies = [ "bytemuck", "safe_arch", @@ -22939,9 +23039,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "winapi" @@ -22961,11 +23061,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -22976,34 +23076,31 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.34.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows_aarch64_msvc 0.34.0", - "windows_i686_gnu 0.34.0", - "windows_i686_msvc 0.34.0", - "windows_x86_64_gnu 0.34.0", - "windows_x86_64_msvc 0.34.0", + "windows-core 0.51.1", + "windows-targets 0.48.5", ] [[package]] name = "windows" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-targets 0.48.5", + "windows-core 0.52.0", + "windows-targets 0.52.5", ] [[package]] -name = "windows" -version = "0.52.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-core", - "windows-targets 0.52.0", + "windows-targets 0.48.5", ] [[package]] @@ -23012,7 +23109,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -23054,7 +23151,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -23089,17 +23186,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -23116,15 +23214,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -23140,15 +23232,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -23164,15 +23250,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] -name = "windows_i686_msvc" -version = "0.34.0" +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -23188,15 +23274,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -23212,9 +23292,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -23230,15 +23310,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -23254,15 +23328,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.5.15" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" dependencies = [ "memchr", ] @@ -23299,9 +23382,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek 4.1.2", "rand_core 0.6.4", @@ -23346,11 +23429,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys 0.4.13", + "rustix 0.38.34", ] [[package]] @@ -23429,10 +23514,10 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", - "proc-macro2 1.0.75", - "quote 1.0.35", + "proc-macro2 1.0.81", + "quote 1.0.36", "staging-xcm", - "syn 2.0.53", + "syn 2.0.60", "trybuild", ] @@ -23517,7 +23602,7 @@ dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.1", + "parking_lot 0.12.2", "rand 0.8.5", "static_assertions", ] @@ -23552,9 +23637,9 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -23572,9 +23657,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.75", - "quote 1.0.35", - "syn 2.0.53", + "proc-macro2 1.0.81", + "quote 1.0.36", + "syn 2.0.60", ] [[package]] @@ -23634,11 +23719,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", - "libc", "pkg-config", ] From 40620e0fe83fc4721dc32f106c7d456d80d8c76a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 2 May 2024 13:57:10 +0100 Subject: [PATCH 097/133] Update substrate/frame/staking/stake-tracker/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index c8628a82afb0..1329dc0eb3b6 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -337,7 +337,7 @@ pub mod pallet { impl Pallet { /// Try-state checks for the stake-tracker pallet. /// - /// 1. `do_try_state_approvals`: checks the curent approval stake in the target list compared + /// 1. `do_try_state_approvals`: checks the current approval stake in the target list compared /// with the staking state. /// 2. `do_try_state_target_sorting`: checks if the target list is sorted by score (approvals). /// 3. `do_try_state_voter_sorting`: checks if the voter list is sorted by score (stake). From 97d254e31031b8ee31e2a4a84f9058fed67dcea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 2 May 2024 13:57:21 +0100 Subject: [PATCH 098/133] Update substrate/frame/staking/stake-tracker/src/mock.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/staking/stake-tracker/src/mock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 387d9198d869..3953a1a4d8e5 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -45,7 +45,7 @@ parameter_types! { pub static ExistentialDeposit: Balance = 1; } -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for Test { type Block = Block; type BlockHashCount = ConstU32<10>; From 86243206680eeeb86aac82f142ff74ab6ebbc821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 2 May 2024 15:04:01 +0200 Subject: [PATCH 099/133] nit --- substrate/frame/staking/stake-tracker/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 1329dc0eb3b6..b8e6ff59a455 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -481,8 +481,6 @@ impl Pallet { } } - log!(trace, "try-state: calculated approvals map: {:?}", approvals_map); - // if the target list is in lazy mode, we don't expect the stake approvals of the target // to be correct at all times. // compare calculated approvals per target with target list state. From e9218b6230f2f670d34fae252eae1bf4cdd3de04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 2 May 2024 15:09:31 +0200 Subject: [PATCH 100/133] nits --- Cargo.lock | 118 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1796d3f109cc..2949e4a93b42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1065,7 +1065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] @@ -1088,7 +1088,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" dependencies = [ - "async-lock", "async-task", "concurrent-queue", "fastrand 2.1.0", @@ -1102,7 +1101,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279cf904654eeebfa37ac9bb1598880884924aab82e290aa65c9e77a0e142e06" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "blocking", "futures-lite 1.13.0", @@ -1116,8 +1115,8 @@ checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ "async-channel 2.2.1", "async-executor", - "async-io", - "async-lock", + "async-io 2.3.2", + "async-lock 3.3.0", "blocking", "futures-lite 2.3.0", "once_cell", @@ -1129,7 +1128,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", @@ -1168,7 +1167,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +dependencies = [ + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite 0.2.14", ] [[package]] @@ -1188,15 +1198,14 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ - "async-io", - "async-lock", - "autocfg", + "async-io 1.13.0", + "async-lock 2.8.0", + "async-signal", "blocking", "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.37.23", - "signal-hook", + "event-listener 3.1.0", + "futures-lite 1.13.0", + "rustix 0.38.34", "windows-sys 0.48.0", ] @@ -1227,8 +1236,8 @@ dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", @@ -1636,8 +1645,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" dependencies = [ - "async-channel", - "async-lock", + "async-channel 2.2.1", + "async-lock 3.3.0", "async-task", "futures-io", "futures-lite 2.3.0", @@ -5325,6 +5334,59 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite 0.2.14", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.0", + "pin-project-lite 0.2.14", +] + [[package]] name = "exit-future" version = "0.2.0" @@ -7051,8 +7113,8 @@ dependencies = [ "curl", "curl-sys", "encoding_rs", - "event-listener", - "futures-lite", + "event-listener 2.5.3", + "futures-lite 1.13.0", "http", "log", "mime", @@ -18505,8 +18567,8 @@ dependencies = [ "async-channel 1.9.0", "async-executor", "async-fs", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "async-net", "async-process", "blocking", @@ -18520,7 +18582,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ "arrayvec 0.7.4", - "async-lock", + "async-lock 2.8.0", "atomic-take", "base64 0.21.7", "bip39", @@ -18531,7 +18593,7 @@ dependencies = [ "derive_more", "ed25519-zebra 4.0.3", "either", - "event-listener", + "event-listener 2.5.3", "fnv", "futures-lite 1.13.0", "futures-util", @@ -18573,13 +18635,13 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ - "async-channel", - "async-lock", - "base64 0.21.2", + "async-channel 1.9.0", + "async-lock 2.8.0", + "base64 0.21.7", "blake2-rfc", "derive_more", "either", - "event-listener", + "event-listener 2.5.3", "fnv", "futures-channel", "futures-lite 1.13.0", From 628bceb80b61d86d3e7730cc84adff784783910b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 10:54:15 +0100 Subject: [PATCH 101/133] `stake-tracker` feedback PR (#4411) - Changes the target list score type from balance to `u128` (`ExtendedBalance`) - simplifies `balance/ vote_weight/ extended_balance` conversions - relies less on the currency total issuance call - ensures approval stake calculations/storage is safe - Simplifies stake tracker logic - removes a few redundant checks - split `on_stake_update` code - Ensures `VoterUpdateMode` is taken into consideration in try-state checks - use voter mode lazy in benchmarks - update weights + check the diff with voter lazy - Docs improvements - All tests passing after merging validator disabling and virtual stakers **new** - ensures duplicate nominations are dedup before calculating the approvals stake - chills nominator after total slash to ensure the target can be reaped/kill without leaving nominations behind. - ensures that switching from validator to nominator and back is correct - a nominator may have an entry in the targetlist (if it was a validator + has nominations) - ensure target node is removed if balance is 0 and it is a nominator. - addresses https://github.com/paritytech-secops/srlabs_findings/issues/383 --- **Other experiments:** (not included) - https://github.com/paritytech/polkadot-sdk/pull/4402 (passing the status of the staker with who in the OnStakingUpdate interface is less clean, it turns out) - https://github.com/paritytech/polkadot-sdk/pull/4361 --------- Co-authored-by: command-bot <> --- .../runtime/westend/src/bag_thresholds.rs | 2 +- polkadot/runtime/westend/src/lib.rs | 12 +- .../westend/src/weights/pallet_staking.rs | 9 + substrate/bin/node/runtime/src/lib.rs | 6 +- substrate/frame/staking/src/benchmarking.rs | 2 +- .../src/migrations/v13_stake_tracker/tests.rs | 4 +- substrate/frame/staking/src/mock.rs | 17 +- substrate/frame/staking/src/pallet/impls.rs | 4 +- substrate/frame/staking/src/pallet/mod.rs | 2 - substrate/frame/staking/src/tests.rs | 402 ++++++++++---- substrate/frame/staking/src/weights.rs | 522 +++++++++--------- .../frame/staking/stake-tracker/src/lib.rs | 494 ++++++++--------- .../frame/staking/stake-tracker/src/mock.rs | 41 +- .../frame/staking/stake-tracker/src/tests.rs | 115 ++-- substrate/primitives/staking/src/lib.rs | 6 + 15 files changed, 934 insertions(+), 704 deletions(-) diff --git a/polkadot/runtime/westend/src/bag_thresholds.rs b/polkadot/runtime/westend/src/bag_thresholds.rs index 9bb80ca3571d..ddbcc1b6aae4 100644 --- a/polkadot/runtime/westend/src/bag_thresholds.rs +++ b/polkadot/runtime/westend/src/bag_thresholds.rs @@ -234,7 +234,7 @@ pub const VOTER_THRESHOLDS: [u64; 200] = [ ]; /// Upper thresholds delimiting the targets bag list. -pub const TARGET_THRESHOLDS: [crate::Balance; 200] = [ +pub const TARGET_THRESHOLDS: [u128; 200] = [ 10_000_000_000, 11_131_723_507, 12_391_526_824, diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f52dc0e37912..32b8b0c33c7c 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -578,7 +578,9 @@ impl pallet_election_provider_multi_phase::Config for Runtime { parameter_types! { pub const VoterBagThresholds: &'static [u64] = &bag_thresholds::VOTER_THRESHOLDS; - pub const TargetBagThresholds: &'static [Balance] = &bag_thresholds::TARGET_THRESHOLDS; + pub const TargetBagThresholds: &'static [u128] = &bag_thresholds::TARGET_THRESHOLDS; + + pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -596,16 +598,15 @@ impl pallet_bags_list::Config for Runtime { type ScoreProvider = pallet_bags_list::Pallet; type WeightInfo = weights::pallet_bags_list::WeightInfo; type BagThresholds = TargetBagThresholds; - type Score = Balance; + type Score = u128; } impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; - type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterList; type TargetList = TargetList; - type WeightInfo = (); // TODO + type VoterUpdateMode = VoterUpdateMode; } pallet_staking_reward_curve::build! { @@ -1680,7 +1681,8 @@ pub mod migrations { } /// Unreleased migrations. Add new ones here: - pub type Unreleased = (pallet_staking::migrations::v15::MigrateV14ToV15,); + pub type Unreleased = + (pallet_staking::migrations::single_block::v15::MigrateV14ToV15,); } /// Unchecked extrinsic type as expected by this runtime. diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 393fa0b37176..0db16d5d47db 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -826,4 +826,13 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } + + // TODO: run CI bot benchmarks + fn drop_dangling_nomination() -> Weight { + Weight::default() + } + + fn v13_mmb_step() -> Weight { + Weight::default() + } } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index ce33af29189d..f5385403c0e3 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -703,12 +703,16 @@ impl pallet_staking::Config for Runtime { type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } +parameter_types! { + pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; +} + impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; - type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterList; type TargetList = TargetList; + type VoterUpdateMode = VoterUpdateMode; } impl pallet_fast_unstake::Config for Runtime { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 23f029c62b94..b63f00129d38 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1212,7 +1212,7 @@ mod benchmarks { impl_benchmark_test_suite!( Staking, - crate::mock::ExtBuilder::default().has_stakers(true), + crate::mock::ExtBuilder::default().has_stakers(true).set_voter_list_lazy(), crate::mock::Test, exec_name = build_and_execute ); diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index a7050b0ece71..c853d4795fea 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -135,10 +135,12 @@ fn mb_migration_target_list_dangling_validators_works() { } #[test] -fn mb_migration_target_list_bench_works() { +fn mb_migration_target_list_single_step_bench_works() { ExtBuilder::default() .has_stakers(false) .max_winners(1000) + // skip checks as not all the steps are applied. + .stake_tracker_try_state(false) .build_and_execute(|| { // setup: // 1000 validators; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index be4a7f35e261..637c49b8b2d2 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -362,12 +362,16 @@ impl OnStakingUpdate for EventTracker { } } +parameter_types! { + pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; +} + impl pallet_stake_tracker::Config for Test { type Currency = Balances; - type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type VoterUpdateMode = VoterUpdateMode; } // Disabling threshold for `UpToLimitDisablingStrategy` @@ -568,6 +572,10 @@ impl ExtBuilder { SkipStakeTrackerTryStateCheck::set(!enable); self } + pub fn set_voter_list_lazy(self) -> Self { + VoterUpdateMode::set(pallet_stake_tracker::VoterUpdateMode::Lazy); + self + } pub fn max_winners(self, max: u32) -> Self { MaxWinners::set(max); self @@ -1100,6 +1108,13 @@ macro_rules! assert_session_era { }; } +pub(crate) fn nominators_of(t: &AccountId) -> Vec { + Nominators::::iter() + .filter(|(_, n)| n.targets.contains(&t)) + .map(|(v, _)| v) + .collect::>() +} + pub(crate) fn staking_events() -> Vec> { System::events() .into_iter() diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d38f53f0ccbf..2b227a05dedd 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1080,8 +1080,8 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - // target list may contain chilled validators and dangling (i.e. unbonded) targets, filter - // those. + // target list may contain chilled validators, dangling (i.e. unbonded) targets or even + // nominators that have been validators - filter those out. let mut targets_iter = T::TargetList::iter().filter(|t| match Self::status(&t) { Ok(StakerStatus::Idle) | Ok(StakerStatus::Nominator(_)) | Err(_) => false, Ok(StakerStatus::Validator) => true, diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 3b904acb13e2..4b0d700cd8b0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1094,8 +1094,6 @@ pub mod pallet { .try_push(UnlockChunk { value, era }) .map_err(|_| Error::::NoMoreChunks)?; }; - // NOTE: ledger must be updated prior to calling `Self::weight_of`. - ledger.update()?; Self::deposit_event(Event::::Unbonded { stash, amount: value }); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 7416294b03f9..d451cb1954f7 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -728,7 +728,7 @@ fn nominating_and_rewards_should_work() { // 333 is the reward destination for 3. assert_eq_error_rate!( Balances::total_balance(&333), - 2 * payout_for_11 / 9 + 3 * payout_for_21 / 11, + 2 * payout_for_21 / 9 + 3 * payout_for_11 / 11, 2 ); @@ -1291,19 +1291,25 @@ fn bond_extra_works() { #[test] fn bond_extra_controller_bad_state_works() { - ExtBuilder::default().try_state(false).build_and_execute(|| { - assert_eq!(StakingLedger::::get(StakingAccount::Stash(31)).unwrap().stash, 31); + ExtBuilder::default() + .try_state(false) + .stake_tracker_try_state(false) + .build_and_execute(|| { + assert_eq!(StakingLedger::::get(StakingAccount::Stash(31)).unwrap().stash, 31); - // simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41. - Bonded::::insert(31, 41); + // simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41. + Bonded::::insert(31, 41); - // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching - // the ledger associated with the controller 41, its stash is 41 (and not 31). - assert_eq!(Ledger::::get(41).unwrap().stash, 41); + // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching + // the ledger associated with the controller 41, its stash is 41 (and not 31). + assert_eq!(Ledger::::get(41).unwrap().stash, 41); - // if the ledger is in this bad state, the `bond_extra` should fail. - assert_noop!(Staking::bond_extra(RuntimeOrigin::signed(31), 10), Error::::BadState); - }) + // if the ledger is in this bad state, the `bond_extra` should fail. + assert_noop!( + Staking::bond_extra(RuntimeOrigin::signed(31), 10), + Error::::BadState + ); + }) } #[test] @@ -3388,8 +3394,8 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_11 = Staking::eras_stakers(active_era(), &11); let exposure_21 = Staking::eras_stakers(active_era(), &21); - assert_eq!(exposure_11.total, 1000 + 125); - assert_eq!(exposure_21.total, 1000 + 375); + assert_eq!(exposure_11.total, 1000 + 375); + assert_eq!(exposure_21.total, 1000 + 125); on_offence_now( &[OffenceDetails { offender: (11, exposure_11.clone()), reporters: vec![] }], @@ -3407,12 +3413,12 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid slash_era: 1 }, Event::Slashed { staker: 11, amount: 100 }, - Event::Slashed { staker: 101, amount: 12 }, + Event::Slashed { staker: 101, amount: 37 }, ] ); // post-slash balance - let nominator_slash_amount_11 = 125 / 10; + let nominator_slash_amount_11 = 375 / 10; assert_eq!(Balances::free_balance(11), 900); assert_eq!(Balances::free_balance(101), 2000 - nominator_slash_amount_11); @@ -3427,11 +3433,11 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid let exposure_21 = Staking::eras_stakers(active_era(), &21); // 11's own expo is reduced. sum of support from 11 is less (448), which is 500 - // 900 + 146 - assert!(matches!(exposure_11, Exposure { own: 900, total: 1046, .. })); - // 1000 + 342 - assert!(matches!(exposure_21, Exposure { own: 1000, total: 1342, .. })); - assert_eq!(500 - 146 - 342, nominator_slash_amount_11); + // 900 + 346 + assert!(matches!(exposure_11, Exposure { own: 900, total: 1036, .. })); + // 1000 + 327 + assert!(matches!(exposure_21, Exposure { own: 1000, total: 1327, .. })); + assert_eq!(500 - 136 - 327, nominator_slash_amount_11); }); } @@ -3484,7 +3490,7 @@ fn non_slashable_offence_disables_validator() { slash_era: 1 }, Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } + Event::Slashed { staker: 101, amount: 31 } ] ); @@ -3546,7 +3552,7 @@ fn slashing_independent_of_disabling_validator() { slash_era: 1 }, Event::Slashed { staker: 21, amount: 250 }, - Event::Slashed { staker: 101, amount: 94 } + Event::Slashed { staker: 101, amount: 31 } ] ); @@ -7441,8 +7447,6 @@ mod on_staking_update_events { add_slash(&11); ensure_on_staking_updates_emitted(vec![ - // disabling/chilling validator at slash. - ValidatorIdle { who: 11 }, Slash { who: 11, slashed_active: 90, slashed_total: 10 }, // slash applied on the validator stake. StakeUpdate { @@ -7561,6 +7565,7 @@ mod on_staking_update_events { let initial_exposure = Staking::eras_stakers(active_era(), &11); // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); + // make 101 a virtual nominator ::migrate_to_virtual_staker(&101); // set payee different to self. @@ -7636,6 +7641,7 @@ mod on_staking_update_events { let initial_exposure = Staking::eras_stakers(active_era(), &11); // 101 is a nominator for 11 assert_eq!(initial_exposure.others.first().unwrap().who, 101); + // make 101 a virtual nominator ::migrate_to_virtual_staker(&101); // set payee different to self. @@ -7676,6 +7682,7 @@ mod on_staking_update_events { // validator can be reaped. assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(10), 11, u32::MAX)); + // nominator is a virtual staker and cannot be reaped. assert_noop!( Staking::reap_stash(RuntimeOrigin::signed(10), 101, u32::MAX), @@ -7720,15 +7727,161 @@ mod stake_tracker { type A = AccountId; #[test] - fn validator_turns_nominator() { + fn duplicate_nominations_dedup_approvals_works() { + ExtBuilder::default() + .add_staker(100, 100, 1_000, StakerStatus::Nominator(vec![11])) + .build_and_execute(|| { + // 11 is a validator. + assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator)); + + // currently, 101 and 100 nominates 11. + assert_eq!(nominators_of(&11), vec![101, 100]); + + // current approvals is the self stake + 101 + 100 active stakes, as expected. + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + + Staking::active_stake(&101).unwrap() + + Staking::active_stake(&100).unwrap() + ); + + // change nominations of 101 to nominate 11 with duplicates. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11, 11, 11])); + assert_eq!(nominators_of(&11), vec![101, 100]); + + // even though the nominations of 101 have duplicate targets as 11. + assert_eq!(Nominators::::get(&101).unwrap().targets, vec![11, 11, 11]); + // the approvals stake of 11 is self_stake + active stake of 101 and 100. duplicate + // nominations in the same voter is dedup by the stake tracker. + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + + Staking::active_stake(&101).unwrap() + + Staking::active_stake(&100).unwrap() + ); + + // when bonding extra, the dedup nominations are also not counted in the approvals. + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(101), 500)); + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + + Staking::active_stake(&101).unwrap() + + Staking::active_stake(&100).unwrap() + ); + + // same when nominator with duplicate nominations unbonds stake. + assert_ok!(Staking::chill(RuntimeOrigin::signed(101))); + assert_eq!(Staking::status(&101), Ok(StakerStatus::Idle)); + + // 101 is not nominator of 11 anymore. + assert_eq!(nominators_of(&11), vec![100]); + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + Staking::active_stake(&100).unwrap() + ); + }) + } + + #[test] + fn total_slash_and_reap_target_works() { + // Test case: a validator and *ALL* its nominators are 100% slashed. The target score drops + // to 0. After calling reap_stash on the validator, the target list node is removed and *NO* + // nominations are left behind. + ExtBuilder::default() + // we need enough validators such that disables are allowed. + .validator_count(7) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(201, StakerStatus::Validator) + .set_status(202, StakerStatus::Validator) + .build_and_execute(|| { + // make 101 only nominate 11. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); + mock::start_active_era(1); + + // slash all stake. + let slash_percent = Perbill::from_percent(100); + let initial_exposure = Staking::eras_stakers(active_era(), &11); + // 101 is a nominator for 11 + assert_eq!(initial_exposure.others.first().unwrap().who, 101); + + let validator_balance = Balances::free_balance(&11); + let validator_stake = Staking::ledger(11.into()).unwrap().total; + + // target score is as expected. + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + Staking::active_stake(&101).unwrap() + ); + + on_offence_now( + &[OffenceDetails { + offender: (11, initial_exposure.clone()), + reporters: vec![], + }], + &[slash_percent], + ); + + // both stakes must have been decreased to 0. + assert_eq!(Staking::ledger(101.into()).unwrap().active, 0); + assert_eq!(Staking::ledger(11.into()).unwrap().active, 0); + + // all validator stake is slashed + assert_eq_error_rate!( + validator_balance - validator_stake, + Balances::free_balance(&11), + 1 + ); + assert!(is_disabled(11)); + + // target score is decreased as expected, down to 0. + assert_eq!(TargetBagsList::score(&11), 0); + assert_eq!( + TargetBagsList::score(&11), + Staking::active_stake(&11).unwrap() + Staking::active_stake(&101).unwrap() + ); + + // since the active take of the nominator dropped to 0 after the slash,, it has been + // chilled. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Idle)); + + // reap validator stash works. + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(10), 11, u32::MAX)); + + // 11 is not a nominator/validator anymore. + assert!(Staking::status(&11).is_err()); + assert_eq!(TargetBagsList::score(&11), 0); + }) + } + + #[test] + fn virtual_nomination_works() { ExtBuilder::default().build_and_execute(|| { - assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator)); + // make 101 only nominate 11. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); - // 11 and 21 are both Validators. - assert_ok!(Staking::nominate(RuntimeOrigin::signed(11), vec![21])); + // make 101 a virtual nominator + ::migrate_to_virtual_staker(&101); + assert_ok!(::update_payee(&101, &102)); + assert_eq!(Pallet::::is_virtual_staker(&101), true); - assert_eq!(Staking::status(&11), Ok(StakerStatus::Nominator(vec![21]))); - }); + // as a virtual nominator, 101 nominates 31 too. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11, 31])); + + let stake_101 = Staking::active_stake(&101).unwrap(); + + // target score of 11 is the sum of self stake and 101 bond. + assert_eq!(TargetBagsList::score(&11), Staking::active_stake(&11).unwrap() + stake_101); + // same for 31. + assert_eq!(TargetBagsList::score(&31), Staking::active_stake(&31).unwrap() + stake_101); + + assert_ok!(Staking::chill(RuntimeOrigin::signed(101))); + assert_ok!(Staking::kill_stash(&101, 0)); + + // target scores updated once virtual nominator unbonded. + assert_eq!(TargetBagsList::score(&11), Staking::active_stake(&11).unwrap()); + assert_eq!(TargetBagsList::score(&31), Staking::active_stake(&31).unwrap()); + }) } #[test] @@ -8028,10 +8181,10 @@ mod stake_tracker { [ BagsEvent::Rebagged { who: 11, from: 1000, to: 100 }, BagsEvent::ScoreUpdated { who: 11, new_score: 0 }, - BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 2100 }, BagsEvent::Rebagged { who: 11, from: 100, to: 2000 }, BagsEvent::ScoreUpdated { who: 11, new_score: 1100 }, + BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 2100 }, ] ); @@ -8157,7 +8310,7 @@ mod stake_tracker { System::reset_events(); // checks the current targets' score and list sorting. - assert_eq!(voters_and_targets().1, [(21, 2050), (11, 2050), (31, 500)]); + assert_eq!(voters_and_targets().1, [(11, 2050), (21, 2050), (31, 500)]); // get the bonded stake of the nominators that will be affected by the slash. let stake_101_before = Staking::ledger(Stash(101)).unwrap().active; @@ -8200,7 +8353,7 @@ mod stake_tracker { assert_eq!( score_11_after, score_11_before - - self_stake_11_before - (slash_percent * total_others_stake_to_slash), + slash_percent * (self_stake_11_before + total_others_stake_to_slash), ); // self-stake of 11 has decreased by 50% due to slash. @@ -8226,35 +8379,70 @@ mod stake_tracker { ); // the target list has been updated accordingly and an indirect rebag of 21 happened. - // Although 11 is chilled, it is still part of the target list. assert_eq!( voters_and_targets().1, - [(21, score_21_after), (11, score_11_after), (31, 500)] + [(11, score_11_after), (21, score_21_after), (31, 500)] ); assert_eq!( target_bags_events(), [ BagsEvent::Rebagged { who: 11, from: 10000, to: 2000 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 1050 }, - BagsEvent::Rebagged { who: 11, from: 2000, to: 1000 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 965 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1550 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1385 }, BagsEvent::Rebagged { who: 21, from: 10000, to: 2000 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 1965 }, - BagsEvent::ScoreUpdated { who: 21, new_score: 1872 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 872 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1885 }, + BagsEvent::ScoreUpdated { who: 11, new_score: 1204 }, + BagsEvent::ScoreUpdated { who: 21, new_score: 1704 } ] ); - // fetching targets sorted and filtered by status works. + // fetching targets sorted and filtered by status works. Validators are not chilled + // upon slashing, thus 11 is part of the set. assert_eq!( TargetBagsList::iter() .filter(|t| Staking::status(&t).unwrap() != StakerStatus::Idle) .collect::>(), - [21, 31], + [11, 21, 31], ); }) } + #[test] + fn validator_nominator_roles_snip_snap_works() { + // Test case: Validator becomes a nominator and vice-versa. In the process of a nominator + // turning validator, it leaves a target behind even though the staker is a nominator. The + // target is removed from the list once its score drops to 0 (similar to the dangling + // targets). + ExtBuilder::default().build_and_execute(|| { + // 11 and 21 are both validators. + assert_eq!(Staking::status(&11), Ok(StakerStatus::Validator)); + assert_eq!(Staking::status(&21), Ok(StakerStatus::Validator)); + // 101 nominates 11 and 21. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + + // 11 becomes nominator. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(11), vec![21])); + assert_eq!(Staking::status(&11), Ok(StakerStatus::Nominator(vec![21]))); + + // however, since 101 nominates 11 (which now is a nominator), 11 is still in the + // target list even though it is a nominator. + assert_eq!(nominators_of(&11), vec![101]); + assert_eq!(TargetBagsList::score(&11), Staking::active_stake(&101).unwrap()); + + // 101 starts validating. thus, it chills as a nominator. + assert_ok!(Staking::validate(RuntimeOrigin::signed(101), Default::default())); + assert_eq!(Staking::status(&101), Ok(StakerStatus::Validator)); + + // now 11 has no more score in the target list and it is a nominator, thus it is + // removed from the target list. + assert_eq!(nominators_of(&11).len(), 0); + assert!(!TargetBagsList::contains(&11)); + + // stake-tracker try-state will ensure actions above keep the integrity of the target + // and voter list. + }); + } + #[test] fn no_redundant_update_ledger_events() { ExtBuilder::default().build_and_execute(|| { @@ -8292,81 +8480,91 @@ mod stake_tracker { #[test] fn drop_dangling_nomination_works() { - ExtBuilder::default().try_state(false).build_and_execute(|| { - // setup. - bond_validator(42, 10); + ExtBuilder::default() + .try_state(false) + .stake_tracker_try_state(false) + .build_and_execute(|| { + // setup. + bond_validator(42, 10); - assert_ok!(Staking::bond(RuntimeOrigin::signed(90), 500, RewardDestination::Staked)); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11])); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(90), + 500, + RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); - // target is dangling with nominations from 101 and 90. - setup_dangling_target_for_nominators(42, vec![101, 90]); + // target is dangling with nominations from 101 and 90. + setup_dangling_target_for_nominators(42, vec![101, 90]); - // 101 is now nominating 42.. - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); - // .. which is unbonded.. - assert!(Staking::status(&42).is_err()); - // .. and still part of the target list (thus dangling). - assert!(TargetBagsList::contains(&42)); + // 101 is now nominating 42.. + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + // .. which is unbonded.. + assert!(Staking::status(&42).is_err()); + // .. and still part of the target list (thus dangling). + assert!(TargetBagsList::contains(&42)); - // remove 90 as dangling nomination. - assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); + // remove 90 as dangling nomination. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); - assert_eq!( - *mock::staking_events().last().unwrap(), - Event::::DanglingNominationDropped { nominator: 90, target: 42 }.into(), - ); + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationDropped { nominator: 90, target: 42 }.into(), + ); - // now, 90 is not nominating 42 anymore. - assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![11])); - // but 42 is still dangling because 101 is still nominating it - assert!(TargetBagsList::contains(&42)); - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + // now, 90 is not nominating 42 anymore. + assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![11])); + // but 42 is still dangling because 101 is still nominating it + assert!(TargetBagsList::contains(&42)); + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); - // when the last dangling nomination is removed, the danling target is removed. - assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 101, 42)); + // when the last dangling nomination is removed, the danling target is removed. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 101, 42)); - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11])); - assert!(!TargetBagsList::contains(&42)); + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11])); + assert!(!TargetBagsList::contains(&42)); - assert_eq!( - *mock::staking_events().last().unwrap(), - Event::::DanglingNominationDropped { nominator: 101, target: 42 }.into(), - ); - }) + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationDropped { nominator: 101, target: 42 }.into(), + ); + }) } #[test] fn drop_dangling_nomination_failures_work() { - ExtBuilder::default().try_state(false).build_and_execute(|| { - // target is not dangling since it does not exist in the target list. - assert!(Staking::status(&42).is_err()); - assert!(!TargetBagsList::contains(&42)); + ExtBuilder::default() + .try_state(false) + .stake_tracker_try_state(false) + .build_and_execute(|| { + // target is not dangling since it does not exist in the target list. + assert!(Staking::status(&42).is_err()); + assert!(!TargetBagsList::contains(&42)); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), - Error::::NotDanglingTarget, - ); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), + Error::::NotDanglingTarget, + ); - // target is not dangling since it is still bonded. - assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), - Error::::NotDanglingTarget, - ); + // target is not dangling since it is still bonded. + assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), + Error::::NotDanglingTarget, + ); - // target is dangling but voter is not nominating it. - bond_validator(42, 10); + // target is dangling but voter is not nominating it. + bond_validator(42, 10); - assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); - setup_dangling_target_for_nominators(42, vec![101]); - assert!(Staking::status(&42).is_err()); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), - Error::::NotNominator, - ); - }) + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + setup_dangling_target_for_nominators(42, vec![101]); + assert!(Staking::status(&42).is_err()); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), + Error::::NotNominator, + ); + }) } } diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index c9e138b96a7d..b2617c57dfc3 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-05-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -108,8 +108,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1134` // Estimated: `4764` - // Minimum execution time: 61_142_000 picoseconds. - Weight::from_parts(62_583_000, 4764) + // Minimum execution time: 61_346_000 picoseconds. + Weight::from_parts(63_986_000, 4764) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -137,8 +137,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2742` // Estimated: `11506` - // Minimum execution time: 133_409_000 picoseconds. - Weight::from_parts(137_789_000, 11506) + // Minimum execution time: 133_115_000 picoseconds. + Weight::from_parts(137_389_000, 11506) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -170,8 +170,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2738` // Estimated: `8877` - // Minimum execution time: 128_838_000 picoseconds. - Weight::from_parts(132_727_000, 8877) + // Minimum execution time: 130_115_000 picoseconds. + Weight::from_parts(133_942_000, 8877) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -198,10 +198,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1415` // Estimated: `4764` - // Minimum execution time: 62_632_000 picoseconds. - Weight::from_parts(64_185_798, 4764) - // Standard Error: 1_112 - .saturating_add(Weight::from_parts(47_715, 0).saturating_mul(s.into())) + // Minimum execution time: 61_773_000 picoseconds. + Weight::from_parts(64_531_144, 4764) + // Standard Error: 1_573 + .saturating_add(Weight::from_parts(53_571, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -240,12 +240,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 135_885_000 picoseconds. - Weight::from_parts(147_555_024, 8877) - // Standard Error: 4_447 - .saturating_add(Weight::from_parts(1_474_964, 0).saturating_mul(s.into())) + // Minimum execution time: 134_037_000 picoseconds. + Weight::from_parts(145_678_976, 8877) + // Standard Error: 5_183 + .saturating_add(Weight::from_parts(1_449_480, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -283,8 +283,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1644` // Estimated: `4556` - // Minimum execution time: 79_115_000 picoseconds. - Weight::from_parts(82_034_000, 4556) + // Minimum execution time: 79_658_000 picoseconds. + Weight::from_parts(81_457_000, 4556) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } @@ -298,20 +298,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListNodes` (r:3 w:3) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:49 w:49) + /// Storage: `TargetList::ListBags` (r:12 w:12) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3671 + k * (752 ±0)` - // Estimated: `33920 + k * (3566 ±0)` - // Minimum execution time: 99_428_000 picoseconds. - Weight::from_parts(172_946_107, 33920) - // Standard Error: 43_151 - .saturating_add(Weight::from_parts(37_545_879, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(18_u64)) + // Measured: `3103 + k * (757 ±0)` + // Estimated: `6120 + k * (3566 ±0)` + // Minimum execution time: 78_476_000 picoseconds. + Weight::from_parts(2_780_311, 6120) + // Standard Error: 55_789 + .saturating_add(Weight::from_parts(35_357_040, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(16_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(k.into())) } @@ -344,12 +344,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2384 + n * (348 ±0)` + // Measured: `2350 + n * (348 ±0)` // Estimated: `6248 + n * (3033 ±0)` - // Minimum execution time: 112_661_000 picoseconds. - Weight::from_parts(90_042_831, 6248) - // Standard Error: 36_011 - .saturating_add(Weight::from_parts(33_478_365, 0).saturating_mul(n.into())) + // Minimum execution time: 114_109_000 picoseconds. + Weight::from_parts(92_374_250, 6248) + // Standard Error: 40_918 + .saturating_add(Weight::from_parts(32_671_582, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14_u64)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(8_u64)) @@ -376,10 +376,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2430` + // Measured: `2429` // Estimated: `8877` - // Minimum execution time: 95_934_000 picoseconds. - Weight::from_parts(97_624_000, 8877) + // Minimum execution time: 94_864_000 picoseconds. + Weight::from_parts(97_414_000, 8877) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } @@ -393,8 +393,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_872_000 picoseconds. - Weight::from_parts(20_614_000, 4556) + // Minimum execution time: 20_223_000 picoseconds. + Weight::from_parts(20_997_000, 4556) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -408,8 +408,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_905_000 picoseconds. - Weight::from_parts(24_901_000, 4556) + // Minimum execution time: 24_225_000 picoseconds. + Weight::from_parts(24_960_000, 4556) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -421,8 +421,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_846_000 picoseconds. - Weight::from_parts(24_732_000, 8122) + // Minimum execution time: 24_007_000 picoseconds. + Weight::from_parts(24_897_000, 8122) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -432,8 +432,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_438_000 picoseconds. - Weight::from_parts(2_597_000, 0) + // Minimum execution time: 2_497_000 picoseconds. + Weight::from_parts(2_626_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -442,8 +442,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_219_000 picoseconds. - Weight::from_parts(8_685_000, 0) + // Minimum execution time: 7_896_000 picoseconds. + Weight::from_parts(8_402_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -452,8 +452,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_212_000 picoseconds. - Weight::from_parts(8_703_000, 0) + // Minimum execution time: 8_122_000 picoseconds. + Weight::from_parts(8_432_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -462,8 +462,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_193_000 picoseconds. - Weight::from_parts(8_622_000, 0) + // Minimum execution time: 8_027_000 picoseconds. + Weight::from_parts(8_393_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -473,10 +473,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_673_000 picoseconds. - Weight::from_parts(3_260_136, 0) + // Minimum execution time: 2_616_000 picoseconds. + Weight::from_parts(3_281_227, 0) // Standard Error: 32 - .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(10_003, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -490,10 +490,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_081_000 picoseconds. - Weight::from_parts(5_272_000, 990) - // Standard Error: 106_956 - .saturating_add(Weight::from_parts(30_736_628, 0).saturating_mul(i.into())) + // Minimum execution time: 4_905_000 picoseconds. + Weight::from_parts(5_156_000, 990) + // Standard Error: 83_880 + .saturating_add(Weight::from_parts(30_406_155, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -533,12 +533,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 131_018_000 picoseconds. - Weight::from_parts(144_246_801, 8877) - // Standard Error: 4_444 - .saturating_add(Weight::from_parts(1_458_960, 0).saturating_mul(s.into())) + // Minimum execution time: 130_799_000 picoseconds. + Weight::from_parts(142_508_520, 8877) + // Standard Error: 4_715 + .saturating_add(Weight::from_parts(1_440_259, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(16_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -551,10 +551,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `66705` // Estimated: `70170` - // Minimum execution time: 96_853_000 picoseconds. - Weight::from_parts(892_001_373, 70170) - // Standard Error: 57_528 - .saturating_add(Weight::from_parts(4_872_094, 0).saturating_mul(s.into())) + // Minimum execution time: 107_433_000 picoseconds. + Weight::from_parts(1_164_974_155, 70170) + // Standard Error: 76_453 + .saturating_add(Weight::from_parts(6_498_608, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -594,7 +594,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListNodes` (r:1 w:1) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:8 w:8) + /// Storage: `TargetList::ListBags` (r:13 w:13) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:257 w:257) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) @@ -603,15 +603,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `34118 + n * (625 ±0)` - // Estimated: `31763 + n * (3774 ±0)` - // Minimum execution time: 248_954_000 picoseconds. - Weight::from_parts(1_054_655_035, 31763) - // Standard Error: 540_385 - .saturating_add(Weight::from_parts(86_501_516, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(29_u64)) + // Measured: `34145 + n * (625 ±0)` + // Estimated: `31768 + n * (3774 ±3)` + // Minimum execution time: 256_919_000 picoseconds. + Weight::from_parts(1_131_187_427, 31768) + // Standard Error: 504_022 + .saturating_add(Weight::from_parts(84_568_885, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(34_u64)) .saturating_add(T::DbWeight::get().reads((10_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(16_u64)) + .saturating_add(T::DbWeight::get().writes(21_u64)) .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } @@ -640,13 +640,15 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `2743 + l * (7 ±0)` // Estimated: `11506` - // Minimum execution time: 130_367_000 picoseconds. - Weight::from_parts(134_369_938, 11506) - // Standard Error: 6_686 - .saturating_add(Weight::from_parts(185_942, 0).saturating_mul(l.into())) + // Minimum execution time: 129_295_000 picoseconds. + Weight::from_parts(134_342_502, 11506) + // Standard Error: 6_141 + .saturating_add(Weight::from_parts(203_335, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) @@ -667,8 +669,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::VirtualStakers` (r:1 w:1) - /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -680,12 +680,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 142_165_000 picoseconds. - Weight::from_parts(150_545_357, 8877) - // Standard Error: 4_445 - .saturating_add(Weight::from_parts(1_439_599, 0).saturating_mul(s.into())) + // Minimum execution time: 142_841_000 picoseconds. + Weight::from_parts(151_373_760, 8877) + // Standard Error: 4_909 + .saturating_add(Weight::from_parts(1_432_397, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(16_u64)) .saturating_add(T::DbWeight::get().writes(15_u64)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -735,12 +735,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3776 ±0)` // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 957_678_000 picoseconds. - Weight::from_parts(964_225_000, 516555) - // Standard Error: 2_413_573 - .saturating_add(Weight::from_parts(79_822_457, 0).saturating_mul(v.into())) - // Standard Error: 240_499 - .saturating_add(Weight::from_parts(20_562_885, 0).saturating_mul(n.into())) + // Minimum execution time: 963_499_000 picoseconds. + Weight::from_parts(966_544_000, 516555) + // Standard Error: 2_158_092 + .saturating_add(Weight::from_parts(72_956_282, 0).saturating_mul(v.into())) + // Standard Error: 215_042 + .saturating_add(Weight::from_parts(19_482_545, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(410_u64)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -771,12 +771,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `3208 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_903_494_000 picoseconds. - Weight::from_parts(38_991_701_000, 512390) - // Standard Error: 406_095 - .saturating_add(Weight::from_parts(8_454_350, 0).saturating_mul(v.into())) - // Standard Error: 406_095 - .saturating_add(Weight::from_parts(2_716_681, 0).saturating_mul(n.into())) + // Minimum execution time: 36_355_465_000 picoseconds. + Weight::from_parts(36_660_578_000, 512390) + // Standard Error: 422_770 + .saturating_add(Weight::from_parts(3_407_216, 0).saturating_mul(v.into())) + // Standard Error: 422_770 + .saturating_add(Weight::from_parts(6_173_669, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(201_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -799,12 +799,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `58454 + v * (323 ±0)` + // Measured: `58129 + v * (323 ±0)` // Estimated: `516555 + v * (3033 ±0)` - // Minimum execution time: 9_230_123_000 picoseconds. - Weight::from_parts(1_671_253_694, 516555) - // Standard Error: 178_631 - .saturating_add(Weight::from_parts(17_181_912, 0).saturating_mul(v.into())) + // Minimum execution time: 8_890_124_000 picoseconds. + Weight::from_parts(9_016_030_000, 516555) + // Standard Error: 111_852 + .saturating_add(Weight::from_parts(7_039_233, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(206_u64)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) @@ -827,8 +827,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_848_000 picoseconds. - Weight::from_parts(6_161_000, 0) + // Minimum execution time: 5_627_000 picoseconds. + Weight::from_parts(6_134_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -849,8 +849,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_778_000 picoseconds. - Weight::from_parts(5_052_000, 0) + // Minimum execution time: 4_901_000 picoseconds. + Weight::from_parts(5_209_000, 0) .saturating_add(T::DbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -879,10 +879,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2545` + // Measured: `2544` // Estimated: `8877` - // Minimum execution time: 109_628_000 picoseconds. - Weight::from_parts(111_707_000, 8877) + // Minimum execution time: 111_325_000 picoseconds. + Weight::from_parts(114_102_000, 8877) .saturating_add(T::DbWeight::get().reads(15_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } @@ -894,8 +894,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `724` // Estimated: `3510` - // Minimum execution time: 12_843_000 picoseconds. - Weight::from_parts(13_310_000, 3510) + // Minimum execution time: 13_264_000 picoseconds. + Weight::from_parts(13_696_000, 3510) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -905,10 +905,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_051_000 picoseconds. - Weight::from_parts(3_169_000, 0) + // Minimum execution time: 3_052_000 picoseconds. + Weight::from_parts(3_242_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -917,8 +919,6 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::VirtualStakers` (r:1 w:0) - /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) @@ -929,14 +929,14 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1165` // Estimated: `4764` - // Minimum execution time: 56_877_000 picoseconds. - Weight::from_parts(58_435_000, 4764) + // Minimum execution time: 61_779_000 picoseconds. + Weight::from_parts(62_484_000, 4764) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:3 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Storage: `TargetList::ListNodes` (r:2 w:2) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:2 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) @@ -954,12 +954,12 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { // Proof Size summary in bytes: - // Measured: `1863` + // Measured: `1973` // Estimated: `8631` - // Minimum execution time: 93_338_000 picoseconds. - Weight::from_parts(94_432_000, 8631) - .saturating_add(T::DbWeight::get().reads(13_u64)) - .saturating_add(T::DbWeight::get().writes(4_u64)) + // Minimum execution time: 101_638_000 picoseconds. + Weight::from_parts(103_488_000, 8631) + .saturating_add(T::DbWeight::get().reads(14_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) } /// Storage: `Staking::Nominators` (r:6 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) @@ -967,20 +967,20 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:21 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:78 w:78) + /// Storage: `TargetList::ListNodes` (r:180 w:180) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:4 w:4) + /// Storage: `TargetList::ListBags` (r:2 w:2) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn v13_mmb_step() -> Weight { // Proof Size summary in bytes: - // Measured: `47878` - // Estimated: `207300` - // Minimum execution time: 2_239_356_000 picoseconds. - Weight::from_parts(2_284_677_000, 207300) - .saturating_add(T::DbWeight::get().reads(131_u64)) - .saturating_add(T::DbWeight::get().writes(83_u64)) + // Measured: `70141` + // Estimated: `477090` + // Minimum execution time: 2_703_732_000 picoseconds. + Weight::from_parts(2_779_206_000, 477090) + .saturating_add(T::DbWeight::get().reads(231_u64)) + .saturating_add(T::DbWeight::get().writes(183_u64)) } } @@ -1006,8 +1006,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1134` // Estimated: `4764` - // Minimum execution time: 61_142_000 picoseconds. - Weight::from_parts(62_583_000, 4764) + // Minimum execution time: 61_346_000 picoseconds. + Weight::from_parts(63_986_000, 4764) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1035,8 +1035,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2742` // Estimated: `11506` - // Minimum execution time: 133_409_000 picoseconds. - Weight::from_parts(137_789_000, 11506) + // Minimum execution time: 133_115_000 picoseconds. + Weight::from_parts(137_389_000, 11506) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1068,8 +1068,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2738` // Estimated: `8877` - // Minimum execution time: 128_838_000 picoseconds. - Weight::from_parts(132_727_000, 8877) + // Minimum execution time: 130_115_000 picoseconds. + Weight::from_parts(133_942_000, 8877) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -1096,10 +1096,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1415` // Estimated: `4764` - // Minimum execution time: 62_632_000 picoseconds. - Weight::from_parts(64_185_798, 4764) - // Standard Error: 1_112 - .saturating_add(Weight::from_parts(47_715, 0).saturating_mul(s.into())) + // Minimum execution time: 61_773_000 picoseconds. + Weight::from_parts(64_531_144, 4764) + // Standard Error: 1_573 + .saturating_add(Weight::from_parts(53_571, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1138,12 +1138,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 135_885_000 picoseconds. - Weight::from_parts(147_555_024, 8877) - // Standard Error: 4_447 - .saturating_add(Weight::from_parts(1_474_964, 0).saturating_mul(s.into())) + // Minimum execution time: 134_037_000 picoseconds. + Weight::from_parts(145_678_976, 8877) + // Standard Error: 5_183 + .saturating_add(Weight::from_parts(1_449_480, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1181,8 +1181,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1644` // Estimated: `4556` - // Minimum execution time: 79_115_000 picoseconds. - Weight::from_parts(82_034_000, 4556) + // Minimum execution time: 79_658_000 picoseconds. + Weight::from_parts(81_457_000, 4556) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } @@ -1196,20 +1196,20 @@ impl WeightInfo for () { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListNodes` (r:3 w:3) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:49 w:49) + /// Storage: `TargetList::ListBags` (r:12 w:12) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3671 + k * (752 ±0)` - // Estimated: `33920 + k * (3566 ±0)` - // Minimum execution time: 99_428_000 picoseconds. - Weight::from_parts(172_946_107, 33920) - // Standard Error: 43_151 - .saturating_add(Weight::from_parts(37_545_879, 0).saturating_mul(k.into())) - .saturating_add(RocksDbWeight::get().reads(18_u64)) + // Measured: `3103 + k * (757 ±0)` + // Estimated: `6120 + k * (3566 ±0)` + // Minimum execution time: 78_476_000 picoseconds. + Weight::from_parts(2_780_311, 6120) + // Standard Error: 55_789 + .saturating_add(Weight::from_parts(35_357_040, 0).saturating_mul(k.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(k.into()))) - .saturating_add(RocksDbWeight::get().writes(16_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(k.into()))) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(k.into())) } @@ -1242,12 +1242,12 @@ impl WeightInfo for () { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2384 + n * (348 ±0)` + // Measured: `2350 + n * (348 ±0)` // Estimated: `6248 + n * (3033 ±0)` - // Minimum execution time: 112_661_000 picoseconds. - Weight::from_parts(90_042_831, 6248) - // Standard Error: 36_011 - .saturating_add(Weight::from_parts(33_478_365, 0).saturating_mul(n.into())) + // Minimum execution time: 114_109_000 picoseconds. + Weight::from_parts(92_374_250, 6248) + // Standard Error: 40_918 + .saturating_add(Weight::from_parts(32_671_582, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(14_u64)) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(8_u64)) @@ -1274,10 +1274,10 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2430` + // Measured: `2429` // Estimated: `8877` - // Minimum execution time: 95_934_000 picoseconds. - Weight::from_parts(97_624_000, 8877) + // Minimum execution time: 94_864_000 picoseconds. + Weight::from_parts(97_414_000, 8877) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } @@ -1291,8 +1291,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `935` // Estimated: `4556` - // Minimum execution time: 19_872_000 picoseconds. - Weight::from_parts(20_614_000, 4556) + // Minimum execution time: 20_223_000 picoseconds. + Weight::from_parts(20_997_000, 4556) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1306,8 +1306,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1002` // Estimated: `4556` - // Minimum execution time: 23_905_000 picoseconds. - Weight::from_parts(24_901_000, 4556) + // Minimum execution time: 24_225_000 picoseconds. + Weight::from_parts(24_960_000, 4556) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1319,8 +1319,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `935` // Estimated: `8122` - // Minimum execution time: 23_846_000 picoseconds. - Weight::from_parts(24_732_000, 8122) + // Minimum execution time: 24_007_000 picoseconds. + Weight::from_parts(24_897_000, 8122) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1330,8 +1330,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_438_000 picoseconds. - Weight::from_parts(2_597_000, 0) + // Minimum execution time: 2_497_000 picoseconds. + Weight::from_parts(2_626_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1340,8 +1340,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_219_000 picoseconds. - Weight::from_parts(8_685_000, 0) + // Minimum execution time: 7_896_000 picoseconds. + Weight::from_parts(8_402_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1350,8 +1350,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_212_000 picoseconds. - Weight::from_parts(8_703_000, 0) + // Minimum execution time: 8_122_000 picoseconds. + Weight::from_parts(8_432_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::ForceEra` (r:0 w:1) @@ -1360,8 +1360,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_193_000 picoseconds. - Weight::from_parts(8_622_000, 0) + // Minimum execution time: 8_027_000 picoseconds. + Weight::from_parts(8_393_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Invulnerables` (r:0 w:1) @@ -1371,10 +1371,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_673_000 picoseconds. - Weight::from_parts(3_260_136, 0) + // Minimum execution time: 2_616_000 picoseconds. + Weight::from_parts(3_281_227, 0) // Standard Error: 32 - .saturating_add(Weight::from_parts(10_059, 0).saturating_mul(v.into())) + .saturating_add(Weight::from_parts(10_003, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: `Staking::Ledger` (r:11800 w:11800) @@ -1388,10 +1388,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1779 + i * (229 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 5_081_000 picoseconds. - Weight::from_parts(5_272_000, 990) - // Standard Error: 106_956 - .saturating_add(Weight::from_parts(30_736_628, 0).saturating_mul(i.into())) + // Minimum execution time: 4_905_000 picoseconds. + Weight::from_parts(5_156_000, 990) + // Standard Error: 83_880 + .saturating_add(Weight::from_parts(30_406_155, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -1431,12 +1431,12 @@ impl WeightInfo for () { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 131_018_000 picoseconds. - Weight::from_parts(144_246_801, 8877) - // Standard Error: 4_444 - .saturating_add(Weight::from_parts(1_458_960, 0).saturating_mul(s.into())) + // Minimum execution time: 130_799_000 picoseconds. + Weight::from_parts(142_508_520, 8877) + // Standard Error: 4_715 + .saturating_add(Weight::from_parts(1_440_259, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(16_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1449,10 +1449,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `66705` // Estimated: `70170` - // Minimum execution time: 96_853_000 picoseconds. - Weight::from_parts(892_001_373, 70170) - // Standard Error: 57_528 - .saturating_add(Weight::from_parts(4_872_094, 0).saturating_mul(s.into())) + // Minimum execution time: 107_433_000 picoseconds. + Weight::from_parts(1_164_974_155, 70170) + // Standard Error: 76_453 + .saturating_add(Weight::from_parts(6_498_608, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1492,7 +1492,7 @@ impl WeightInfo for () { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListNodes` (r:1 w:1) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:8 w:8) + /// Storage: `TargetList::ListBags` (r:13 w:13) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:257 w:257) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) @@ -1501,15 +1501,15 @@ impl WeightInfo for () { /// The range of component `n` is `[0, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `34118 + n * (625 ±0)` - // Estimated: `31763 + n * (3774 ±0)` - // Minimum execution time: 248_954_000 picoseconds. - Weight::from_parts(1_054_655_035, 31763) - // Standard Error: 540_385 - .saturating_add(Weight::from_parts(86_501_516, 0).saturating_mul(n.into())) - .saturating_add(RocksDbWeight::get().reads(29_u64)) + // Measured: `34145 + n * (625 ±0)` + // Estimated: `31768 + n * (3774 ±3)` + // Minimum execution time: 256_919_000 picoseconds. + Weight::from_parts(1_131_187_427, 31768) + // Standard Error: 504_022 + .saturating_add(Weight::from_parts(84_568_885, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(34_u64)) .saturating_add(RocksDbWeight::get().reads((10_u64).saturating_mul(n.into()))) - .saturating_add(RocksDbWeight::get().writes(16_u64)) + .saturating_add(RocksDbWeight::get().writes(21_u64)) .saturating_add(RocksDbWeight::get().writes((4_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } @@ -1538,13 +1538,15 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `2743 + l * (7 ±0)` // Estimated: `11506` - // Minimum execution time: 130_367_000 picoseconds. - Weight::from_parts(134_369_938, 11506) - // Standard Error: 6_686 - .saturating_add(Weight::from_parts(185_942, 0).saturating_mul(l.into())) + // Minimum execution time: 129_295_000 picoseconds. + Weight::from_parts(134_342_502, 11506) + // Standard Error: 6_141 + .saturating_add(Weight::from_parts(203_335, 0).saturating_mul(l.into())) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) @@ -1565,8 +1567,6 @@ impl WeightInfo for () { /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::VirtualStakers` (r:1 w:1) - /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) @@ -1578,12 +1578,12 @@ impl WeightInfo for () { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2843 + s * (4 ±0)` + // Measured: `2842 + s * (4 ±0)` // Estimated: `8877 + s * (4 ±0)` - // Minimum execution time: 142_165_000 picoseconds. - Weight::from_parts(150_545_357, 8877) - // Standard Error: 4_445 - .saturating_add(Weight::from_parts(1_439_599, 0).saturating_mul(s.into())) + // Minimum execution time: 142_841_000 picoseconds. + Weight::from_parts(151_373_760, 8877) + // Standard Error: 4_909 + .saturating_add(Weight::from_parts(1_432_397, 0).saturating_mul(s.into())) .saturating_add(RocksDbWeight::get().reads(16_u64)) .saturating_add(RocksDbWeight::get().writes(15_u64)) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -1633,12 +1633,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0 + n * (720 ±0) + v * (3776 ±0)` // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 957_678_000 picoseconds. - Weight::from_parts(964_225_000, 516555) - // Standard Error: 2_413_573 - .saturating_add(Weight::from_parts(79_822_457, 0).saturating_mul(v.into())) - // Standard Error: 240_499 - .saturating_add(Weight::from_parts(20_562_885, 0).saturating_mul(n.into())) + // Minimum execution time: 963_499_000 picoseconds. + Weight::from_parts(966_544_000, 516555) + // Standard Error: 2_158_092 + .saturating_add(Weight::from_parts(72_956_282, 0).saturating_mul(v.into())) + // Standard Error: 215_042 + .saturating_add(Weight::from_parts(19_482_545, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(410_u64)) .saturating_add(RocksDbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1669,12 +1669,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `3208 + n * (911 ±0) + v * (395 ±0)` // Estimated: `512390 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 37_903_494_000 picoseconds. - Weight::from_parts(38_991_701_000, 512390) - // Standard Error: 406_095 - .saturating_add(Weight::from_parts(8_454_350, 0).saturating_mul(v.into())) - // Standard Error: 406_095 - .saturating_add(Weight::from_parts(2_716_681, 0).saturating_mul(n.into())) + // Minimum execution time: 36_355_465_000 picoseconds. + Weight::from_parts(36_660_578_000, 512390) + // Standard Error: 422_770 + .saturating_add(Weight::from_parts(3_407_216, 0).saturating_mul(v.into())) + // Standard Error: 422_770 + .saturating_add(Weight::from_parts(6_173_669, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(201_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -1697,12 +1697,12 @@ impl WeightInfo for () { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `58454 + v * (323 ±0)` + // Measured: `58129 + v * (323 ±0)` // Estimated: `516555 + v * (3033 ±0)` - // Minimum execution time: 9_230_123_000 picoseconds. - Weight::from_parts(1_671_253_694, 516555) - // Standard Error: 178_631 - .saturating_add(Weight::from_parts(17_181_912, 0).saturating_mul(v.into())) + // Minimum execution time: 8_890_124_000 picoseconds. + Weight::from_parts(9_016_030_000, 516555) + // Standard Error: 111_852 + .saturating_add(Weight::from_parts(7_039_233, 0).saturating_mul(v.into())) .saturating_add(RocksDbWeight::get().reads(206_u64)) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) @@ -1725,8 +1725,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_848_000 picoseconds. - Weight::from_parts(6_161_000, 0) + // Minimum execution time: 5_627_000 picoseconds. + Weight::from_parts(6_134_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::MinCommission` (r:0 w:1) @@ -1747,8 +1747,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_778_000 picoseconds. - Weight::from_parts(5_052_000, 0) + // Minimum execution time: 4_901_000 picoseconds. + Weight::from_parts(5_209_000, 0) .saturating_add(RocksDbWeight::get().writes(7_u64)) } /// Storage: `Staking::Bonded` (r:1 w:0) @@ -1777,10 +1777,10 @@ impl WeightInfo for () { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2545` + // Measured: `2544` // Estimated: `8877` - // Minimum execution time: 109_628_000 picoseconds. - Weight::from_parts(111_707_000, 8877) + // Minimum execution time: 111_325_000 picoseconds. + Weight::from_parts(114_102_000, 8877) .saturating_add(RocksDbWeight::get().reads(15_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } @@ -1792,8 +1792,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `724` // Estimated: `3510` - // Minimum execution time: 12_843_000 picoseconds. - Weight::from_parts(13_310_000, 3510) + // Minimum execution time: 13_264_000 picoseconds. + Weight::from_parts(13_696_000, 3510) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1803,10 +1803,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_051_000 picoseconds. - Weight::from_parts(3_169_000, 0) + // Minimum execution time: 3_052_000 picoseconds. + Weight::from_parts(3_242_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -1815,8 +1817,6 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::VirtualStakers` (r:1 w:0) - /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) @@ -1827,14 +1827,14 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1165` // Estimated: `4764` - // Minimum execution time: 56_877_000 picoseconds. - Weight::from_parts(58_435_000, 4764) + // Minimum execution time: 61_779_000 picoseconds. + Weight::from_parts(62_484_000, 4764) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } /// Storage: `Staking::Bonded` (r:3 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Storage: `TargetList::ListNodes` (r:2 w:2) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:2 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) @@ -1852,12 +1852,12 @@ impl WeightInfo for () { /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { // Proof Size summary in bytes: - // Measured: `1863` + // Measured: `1973` // Estimated: `8631` - // Minimum execution time: 93_338_000 picoseconds. - Weight::from_parts(94_432_000, 8631) - .saturating_add(RocksDbWeight::get().reads(13_u64)) - .saturating_add(RocksDbWeight::get().writes(4_u64)) + // Minimum execution time: 101_638_000 picoseconds. + Weight::from_parts(103_488_000, 8631) + .saturating_add(RocksDbWeight::get().reads(14_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) } /// Storage: `Staking::Nominators` (r:6 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) @@ -1865,19 +1865,19 @@ impl WeightInfo for () { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:21 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:78 w:78) + /// Storage: `TargetList::ListNodes` (r:180 w:180) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListBags` (r:4 w:4) + /// Storage: `TargetList::ListBags` (r:2 w:2) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn v13_mmb_step() -> Weight { // Proof Size summary in bytes: - // Measured: `47878` - // Estimated: `207300` - // Minimum execution time: 2_239_356_000 picoseconds. - Weight::from_parts(2_284_677_000, 207300) - .saturating_add(RocksDbWeight::get().reads(131_u64)) - .saturating_add(RocksDbWeight::get().writes(83_u64)) + // Measured: `70141` + // Estimated: `477090` + // Minimum execution time: 2_703_732_000 picoseconds. + Weight::from_parts(2_779_206_000, 477090) + .saturating_add(RocksDbWeight::get().reads(231_u64)) + .saturating_add(RocksDbWeight::get().writes(183_u64)) } } diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index b8e6ff59a455..c24f8aa289f5 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -23,28 +23,32 @@ //! ## Overview //! //! The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] -//! trait. Based on those events, maintais a *strictly* sorted list of target lists based on their -//! approval voting power. +//! trait. Based on the emitted events, the goal of this pallet is to maintain a **strictly** +//! sorted list of targets by approval voting. This pallet may also update a voter list, based on +//! the configurations. //! -//! For the voter list, the [`crate::SortingMode`] defines the type of sortition of the list, +//! For the voter list, the [`crate::VoterUpdateMode`] defines the type of sortition of the list, //! namely: //! -//! - [`crate::SortingMode::Lazy`]: will skip the score update in the voter list. -//! - [`crate::SortingMode::Strict`]: will ensure that the score updates are kept sorted +//! - [`crate::VoterUpdateMode::Lazy`]: will skip the score update in the voter list. +//! - [`crate::VoterUpdateMode::Strict`]: will ensure that the score updates are kept sorted //! for the corresponding list. In this case, the [`Config::VoterList`] is *strictly* //! sorted* by [`SortedListProvider::Score`] (note: from the time the sorting mode is strict). //! +//! Note that insertions and removals of voter nodes will be executed regardless of the sorting +//! mode. +//! //! ## Goals //! //! Note: these goals are assuming the both target list and sorted lists have -//! [`crate::SortingMode::Strict`] set. +//! [`crate::VoterUpdateMode::Strict`] set. //! //! The [`OnStakingUpdate`] implementation (in strict mode) aims to achieve the following goals: //! //! * The [`Config::TargetList`] keeps a sorted list of validators, *strictly* sorted by approvals //! (which include self-vote and nominations' stake). //! * The [`Config::VoterList`] keeps a list of voters, *stricly* sorted by bonded stake if it has -//! [`crate::SortingMode::strict`] mode enabled, otherwise the list is kept lazily sorted. +//! [`crate::VoterUpdateMode::Strict`] mode enabled, otherwise the list is kept lazily sorted. //! * The [`Config::TargetList`] sorting must be *always* kept up to date, even in the event of new //! nomination updates, nominator/validator slashes and rewards. This pallet *must* ensure that the //! scores of the targets and voters are always up to date and thus, that the targets and voters in @@ -59,7 +63,7 @@ //! ## Staker status and list invariants //! //! Note: these goals are assuming the both target list and sorted lists have -//! [`crate::SortingMode::Strict`] set. +//! [`crate::VoterUpdateMode::Strict`] set. //! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the //! voter list's score. In addition, if the `VoterList` is in strict mode, the voters' scores are up @@ -75,7 +79,7 @@ //! be removed onced all the voters stop nominating the unbonded account (i.e. the target's score //! drops to 0). //! -//! For further details on the target list invariantes, refer to [`Self`::do_try_state_approvals`] +//! For further details on the target list invariante, refer to [`Self`::do_try_state_approvals`] //! and [`Self::do_try_state_target_sorting`]. //! //! ## Event emitter ordering and staking ledger state updates @@ -94,7 +98,7 @@ use frame_support::{ pallet_prelude::*, traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; -use sp_runtime::traits::Zero; +use sp_runtime::traits::{Saturating, Zero}; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; @@ -105,19 +109,6 @@ pub(crate) mod mock; #[cfg(test)] mod tests; -pub(crate) const LOG_TARGET: &str = "runtime::stake-tracker"; - -// syntactic sugar for logging. -#[macro_export] -macro_rules! log { - ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { - log::$level!( - target: $crate::LOG_TARGET, - concat!("[{:?}] 📚 ", $patter), >::block_number() $(, $values)* - ) - }; -} - /// The balance type of this pallet. pub type BalanceOf = <::Staking as StakingInterface>::Balance; /// The account ID of this pallet. @@ -125,42 +116,37 @@ pub type AccountIdOf = ::AccountId; /// Represents a stake imbalance to be applied to a staker's score. #[derive(Copy, Clone, Debug)] -pub enum StakeImbalance { - /// Represents the reduction of stake by `Balance`. - Negative(Balance), - /// Represents the increase of stake by `Balance`. - Positive(Balance), +pub enum StakeImbalance { + /// Represents the reduction of stake by `Score`. + Negative(Score), + /// Represents the increase of stake by `Score`. + Positive(Score), } -impl StakeImbalance { - fn from(prev_balance: Balance, new_balance: Balance) -> Self { - if prev_balance > new_balance { - StakeImbalance::Negative(prev_balance.defensive_saturating_sub(new_balance)) +impl StakeImbalance { + /// Constructor for a stake imbalance instance based on the previous and next score. + fn from(prev: Score, new: Score) -> Self { + if prev > new { + StakeImbalance::Negative(prev.defensive_saturating_sub(new)) } else { - StakeImbalance::Positive(new_balance.defensive_saturating_sub(prev_balance)) + StakeImbalance::Positive(new.defensive_saturating_sub(prev)) } } } /// Defines the sorting mode of sorted list providers. -/// -/// Strict: all score update events will be autimatically reflected in the sorted list. -/// Lazy: no score update events will be automatically reflected in the sorted list. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub enum SortingMode { +#[derive(Copy, Clone, Debug)] +pub enum VoterUpdateMode { + /// All score update events will be automatically reflected in the sorted list. Strict, + /// Score update events are *not* be automatically reflected in the sorted list. Howeber, node + /// insertion and removals are reflected in the list. Lazy, } -impl Default for SortingMode { - fn default() -> Self { - Self::Strict - } -} - -impl SortingMode { - fn is_lazy_mode(&self) -> bool { - matches!(self, Self::Lazy) +impl VoterUpdateMode { + fn is_strict_mode(&self) -> bool { + matches!(self, Self::Strict) } } @@ -182,27 +168,20 @@ pub mod pallet { /// The stake balance. type Currency: FnInspect>; - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// The staking interface. type Staking: StakingInterface; - /// Something that provides an *always* sorted list of voters. + /// A sorted list provider for staking voters that is kept up to date by this pallet. The + /// sorting by score depends on the sorting mode set by [`Self::VoterUpdateMode`]. type VoterList: SortedListProvider; - /// Something that provides an *always* sorted list of targets by their approval stake. - type TargetList: SortedListProvider< - Self::AccountId, - Score = ::Balance, - >; - } - - #[pallet::storage] - pub type VoterListMode = StorageValue<_, SortingMode, ValueQuery>; + /// A sorted list provider for staking targets that is ketp *always* sorted by the target's + /// stake approvals. + type TargetList: SortedListProvider; - #[pallet::event] - pub enum Event {} + /// The voter list update mode. + type VoterUpdateMode: Get; + } #[pallet::hooks] impl Hooks> for Pallet { @@ -213,48 +192,65 @@ pub mod pallet { } impl Pallet { - /// Returns the balance of a staker based on its current *active* stake, as returned by - /// the staking interface. - pub(crate) fn active_vote_of(who: &T::AccountId) -> BalanceOf { - T::Staking::stake(who).map(|s| s.active).defensive_unwrap_or_default() - } + /// Updates the stake of a voter. + /// + /// It must ensure that there are no duplicate nominations to prevent over-counting the + /// stake approval. + pub(crate) fn do_stake_update_voter( + who: &T::AccountId, + prev_stake: Option>>, + stake: Stake>, + nominations: Vec, + ) { + let voter_weight = Self::to_vote(stake.active); - /// Converts a balance into the staker's vote weight. - pub(crate) fn weight_of(balance: BalanceOf) -> VoteWeight { - ::CurrencyToVote::to_vote( - balance, - T::Currency::total_issuance(), - ) - } + // if voter list is in strict sorting mode, update the voter score too. + if T::VoterUpdateMode::get().is_strict_mode() { + let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( + "staker should exist in VoterList, as per the contract \ + with staking.", + ); + } - /// Fetches and converts a voter's weight into the [`ExtendedBalance`] type for safe - /// computation. - pub(crate) fn to_vote_extended(balance: BalanceOf) -> ExtendedBalance { - ::CurrencyToVote::to_vote( - balance, - T::Currency::total_issuance(), - ) - .into() - } + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote(s.active).into()), + voter_weight.into(), + ); - /// Converts an [`sp_npos_elections::ExtendedBalance`] back to the staking interface's - /// balance. - pub(crate) fn to_currency( - extended: ExtendedBalance, - ) -> ::Balance { - ::CurrencyToVote::to_currency( - extended, - T::Currency::total_issuance(), - ) + // note: this dedup can be removed once the staking pallet ensures no duplicate + // nominations are allowed . + // TODO: replace the dedup by a debug_assert once #4419 is resolved. + let nominations = Self::ensure_dedup(nominations); + + // updates vote weight of nominated targets accordingly. Note: this will + // update the score of up to `T::MaxNominations` validators. + for target in nominations.into_iter() { + Self::update_target_score(&target, stake_imbalance); + } } - /// Returns whether a target should be removed from the target list. - /// - /// A target should be removed from the target list at any point IFF: - /// * it's approvals are 0 AND - /// * it's state is dangling (ledger unbonded). - pub(crate) fn should_remove_target(who: &T::AccountId, score: BalanceOf) -> bool { - score.is_zero() && T::Staking::status(who).is_err() + /// Updates the stake of a target. + pub(crate) fn do_stake_update_target( + who: &T::AccountId, + prev_stake: Option>>, + stake: Stake>, + ) { + let voter_weight = Self::to_vote(stake.active).into(); + let stake_imbalance = StakeImbalance::from( + prev_stake.map_or(Default::default(), |s| Self::to_vote(s.active).into()), + voter_weight, + ); + + Self::update_target_score(who, stake_imbalance); + + // validator is both a target and a voter. update the voter score if the voter list + // is in strict mode. + if T::VoterUpdateMode::get().is_strict_mode() { + let _ = T::VoterList::on_update(who, Self::to_vote(stake.active)).defensive_proof( + "the staker should exist in VoterList, as per the \ + contract with staking.", + ); + } } /// Updates a target's score by increasing/decreasing an imbalance of the current score in @@ -263,72 +259,72 @@ pub mod pallet { who: &T::AccountId, imbalance: StakeImbalance, ) { - // ensure that the target list node exists if it does not yet and perform a few - // defensive checks. + // if target list does not contain target, add it and proceed. if !T::TargetList::contains(who) { - match T::Staking::status(who) { - Err(_) | Ok(StakerStatus::Nominator(_)) => { - defensive!("update target score was called on an unbonded ledger or nominator, not expected."); - return - }, - Ok(StakerStatus::Validator) => { - defensive!( - "active validator was not part of the target list, something is wrong." - ); - return - }, - Ok(StakerStatus::Idle) => { - // if stash is idle and not part of the target list yet, initialize it and - // proceed. - T::TargetList::on_insert(who.clone(), Zero::zero()) - .expect("staker does not exist in the list as per check above; qed."); - }, - } + T::TargetList::on_insert(who.clone(), Zero::zero()) + .expect("staker does not exist in the list as per check above; qed."); } // update target score. - let removed = match imbalance { + match imbalance { StakeImbalance::Positive(imbalance) => { - let _ = T::TargetList::on_increase(who, Self::to_currency(imbalance)) - .defensive_proof( - "staker should exist in the list, otherwise returned earlier.", - ); - false + let _ = T::TargetList::on_increase(who, imbalance).defensive_proof( + "staker should exist in the list, otherwise returned earlier.", + ); }, StakeImbalance::Negative(imbalance) => { if let Ok(current_score) = T::TargetList::get_score(who) { - let balance = - Self::to_vote_extended(current_score).saturating_sub(imbalance); + let balance = current_score.saturating_sub(imbalance); // the target is removed from the list IFF score is 0 and the target is - // dangling (i.e. not bonded). - if Self::should_remove_target(who, Self::to_currency(balance)) { + // either dangling (i.e. not bonded) or currently registered as a nominator. + let remove_target = balance.is_zero() && + T::Staking::status(who).map(|s| s.is_nominator()).unwrap_or(true); + + if remove_target { let _ = T::TargetList::on_remove(who).defensive_proof( "staker exists in the list as per the check above; qed.", ); - true } else { // update the target score without removing it. - let _ = T::TargetList::on_update(who, Self::to_currency(balance)) - .defensive_proof( - "staker exists in the list as per the check above; qed.", - ); - false + let _ = T::TargetList::on_update(who, balance).defensive_proof( + "staker exists in the list as per the check above; qed.", + ); } } else { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); - false } }, }; + } - log!( - debug, - "update_score of {:?} by {:?}. removed target node? {}", - who, - imbalance, - removed - ); + // ------ Helpers + + /// Helper to convert the balance of a staker into its vote weight. + pub(crate) fn to_vote(balance: BalanceOf) -> VoteWeight { + ::CurrencyToVote::to_vote( + balance, + T::Currency::total_issuance(), + ) + } + + /// Helper to fetch te active stake of a staker and convert it to vote weight. + pub(crate) fn vote_of(who: &T::AccountId) -> VoteWeight { + let active = T::Staking::stake(who).map(|s| s.active).defensive_unwrap_or_default(); + Self::to_vote(active) + } + + /// Returns a dedup list of accounts. + /// + /// Note: this dedup can be removed once (and if) the staking pallet ensures no duplicate + /// nominations are allowed . + /// + /// TODO: replace this helper method by a debug_assert if #4419 ever prevents the nomination + /// of duplicated target. + pub(crate) fn ensure_dedup(mut v: Vec) -> Vec { + use sp_std::collections::btree_set::BTreeSet; + + v.drain(..).collect::>().into_iter().collect::>() } } } @@ -386,35 +382,50 @@ impl Pallet { // build map of approvals stakes from the `VoterList` POV. for voter in T::VoterList::iter() { if let Some(nominations) = ::nominations(&voter) { - let score = >>::get_score(&voter) - .map_err(|_| "nominator score must exist in voter bags list")?; - // sanity check. let active_stake = T::Staking::stake(&voter) - .map(|s| Self::weight_of(s.active)) + .map(|s| Self::to_vote(s.active)) .expect("active voter has bonded stake; qed."); - // if the voter list is in lazy mode, we don't expect the stake of the voter to - // match the score in the list at all times. - if !VoterListMode::::get().is_lazy_mode() { + // if the voter list is in strict mode, we expect the stake of the voter to match + // the score in the list at all times. The approvals calculation also depends on + // the sorting of the voter list: + // * if the voter list is strictly sorted, use the nominator's scores to calculate + // the approvals. + // * if the voter list is lazily sorted, use the active stake of the nominator to + // calculat the approvals. + let stake = if T::VoterUpdateMode::get().is_strict_mode() { + // voter list is strictly sorted, use the voter list score to calculate the + // target's approvals. + let score = + >>::get_score(&voter) + .map_err(|_| "nominator score must exist in voter bags list")?; + frame_support::ensure!( active_stake == score, "voter score must be the same as its active stake" ); - } + + score + } else { + active_stake + }; + + // update the approvals map with the voter's active stake. + // note: must remove the dedup nominations, which is also done by the + // stake-tracker. + let nominations = Self::ensure_dedup(nominations); for nomination in nominations { - if let Some(stake) = approvals_map.get_mut(&nomination) { - *stake += score as sp_npos_elections::ExtendedBalance; - } else { - approvals_map.insert(nomination, score.into()); - } + *approvals_map.entry(nomination).or_default() += + stake as sp_npos_elections::ExtendedBalance; } } else { // if it is in the voter list but it's not a nominator, it should be a validator // and part of the target list. frame_support::ensure!( - T::Staking::status(&voter) == Ok(StakerStatus::Validator), + T::Staking::status(&voter) == Ok(StakerStatus::Validator) && + T::TargetList::contains(&voter), "wrong state of voter" ); frame_support::ensure!( @@ -463,10 +474,11 @@ impl Pallet { "bonded and active validator should also be part of the voter list" ); // return self-stake (ie. active bonded). - T::Staking::stake(&target).map(|s| Self::weight_of(s.active)).ok() + T::Staking::stake(&target).map(|s| Self::to_vote(s.active)).ok() }, Ok(StakerStatus::Nominator(_)) => { - panic!("staker with nominator status should not be part of the target list"); + // an idle/dangling target may become a nominator. + None }, }; @@ -481,21 +493,18 @@ impl Pallet { } } - // if the target list is in lazy mode, we don't expect the stake approvals of the target - // to be correct at all times. // compare calculated approvals per target with target list state. for (target, calculated_stake) in approvals_map.iter() { let stake_in_list = T::TargetList::get_score(target).expect("target must exist; qed."); - let stake_in_list = Self::to_vote_extended(stake_in_list); if *calculated_stake != stake_in_list { - log!( - error, - "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", - target, - stake_in_list, - calculated_stake, - ); + log::error!( + target: "runtime::stake-tracker", + "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", + target, + stake_in_list, + calculated_stake, + ); return Err("target score in the target list is different than the expected".into()) } @@ -541,7 +550,7 @@ impl Pallet { pub fn do_try_state_voter_sorting() -> Result<(), sp_runtime::TryRuntimeError> { // if the voter list is in lazy mode, we don't expect the nodes to be sorted at all times. // skip checks. - if !VoterListMode::::get().is_lazy_mode() { + if T::VoterUpdateMode::get().is_strict_mode() { return Ok(()) } @@ -560,53 +569,18 @@ impl OnStakingUpdate> for Pallet { /// When a nominator's stake is updated, all the nominated targets must be updated /// accordingly. /// - /// Note: it is assumed that `who`'s staking ledger state is updated *before* this method is - /// called. + /// The score of the node associated with `who` in the *VoterList* will be updated if the + /// the mode is [`VoterUpdateMode::Strict`]. The approvals of the nominated targets (by `who`) + /// are always updated. fn on_stake_update( who: &T::AccountId, prev_stake: Option>>, stake: Stake>, ) { match T::Staking::status(who) { - Ok(StakerStatus::Nominator(nominations)) => { - // if voters are in lazy mode, return without updating the stake. - if VoterListMode::::get().is_lazy_mode() { - return - } - - let voter_weight = Self::weight_of(stake.active); - - let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( - "staker should exist in VoterList, as per the contract \ - with staking.", - ); - - let stake_imbalance = StakeImbalance::from( - prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), - voter_weight.into(), - ); - - // updates vote weight of nominated targets accordingly. Note: this will - // update the score of up to `T::MaxNominations` validators. - for target in nominations.into_iter() { - Self::update_target_score(&target, stake_imbalance); - } - }, - Ok(StakerStatus::Validator) => { - let voter_weight = Self::weight_of(stake.active); - let stake_imbalance = StakeImbalance::from( - prev_stake.map_or(Default::default(), |s| Self::to_vote_extended(s.active)), - voter_weight.into(), - ); - - Self::update_target_score(who, stake_imbalance); - - // validator is both a target and a voter. - let _ = T::VoterList::on_update(who, voter_weight).defensive_proof( - "the staker should exist in VoterList, as per the \ - contract with staking.", - ); - }, + Ok(StakerStatus::Nominator(nominations)) => + Self::do_stake_update_voter(who, prev_stake, stake, nominations), + Ok(StakerStatus::Validator) => Self::do_stake_update_target(who, prev_stake, stake), Ok(StakerStatus::Idle) => (), // nothing to see here. Err(_) => { defensive!( @@ -622,7 +596,7 @@ impl OnStakingUpdate> for Pallet { /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { - let self_stake = self_stake.unwrap_or_default().active; + let self_stake = Self::to_vote(self_stake.unwrap_or_default().active).into(); match T::TargetList::on_insert(who.clone(), self_stake) { Ok(_) => (), @@ -634,13 +608,10 @@ impl OnStakingUpdate> for Pallet { T::Staking::status(who).is_err() ); - let self_stake = Self::to_vote_extended(self_stake); Self::update_target_score(who, StakeImbalance::Positive(self_stake)); }, } - log!(debug, "on_validator_add: {:?}. role: {:?}", who, T::Staking::status(who),); - // a validator is also a nominator. Self::on_nominator_add(who, vec![]) } @@ -650,21 +621,18 @@ impl OnStakingUpdate> for Pallet { /// While idling, the target node is not removed from the target list but its score is /// updated. fn on_validator_idle(who: &T::AccountId) { - let self_stake = Self::weight_of(Self::active_vote_of(who)); + let self_stake = Self::vote_of(who); Self::update_target_score(who, StakeImbalance::Negative(self_stake.into())); // validator is a nominator too. Self::on_nominator_idle(who, vec![]); - - log!(debug, "on_validator_idle: {:?}, decreased self-stake {}", who, self_stake); } - /// A validator has been set as inactive/removed from the staking POV. The target node is - /// removed from the target list IFF its score is 0. Otherwise, its score should be kept up to - /// date as if the validator was active. + /// A validator has been set as inactive/removed from the staking POV. + /// + /// The target node is removed from the target list IFF its score is 0. Otherwise, its score + /// should be kept up to date as if the validator was active. fn on_validator_remove(who: &T::AccountId) { - log!(debug, "on_validator_remove: {:?} with status {:?}", who, T::Staking::status(who)); - // validator must be idle before removing completely. Perform some sanity checks too. match T::Staking::status(who) { Ok(StakerStatus::Idle) => (), // proceed @@ -692,16 +660,24 @@ impl OnStakingUpdate> for Pallet { }; } + /// A nominator has been added to the system. + /// + /// Even in lazy mode, inserting voter list nodes on new nominator must be done. + /// /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is /// called. fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { - let nominator_vote = Self::weight_of(Self::active_vote_of(who)); + let nominator_vote = Self::vote_of(who); + let nominations = Self::ensure_dedup(nominations); + // the new voter node will be added even if the voter is in lazy mode. In lazy mode, we + // ensure that the nodes exist in the voter list, even though they may not have the updated + // score at all times. let _ = T::VoterList::on_insert(who.clone(), nominator_vote).defensive_proof( "the nominator must not exist in the list as per the contract with staking.", ); - // If who is a nominator, update the vote weight of the nominations if they exist. Note: + // if `who` is a nominator, update the vote weight of the nominations if they exist. Note: // this will update the score of up to `T::MaxNominations` validators. match T::Staking::status(who).defensive() { Ok(StakerStatus::Nominator(_)) => @@ -710,8 +686,6 @@ impl OnStakingUpdate> for Pallet { }, Ok(StakerStatus::Idle) | Ok(StakerStatus::Validator) | Err(_) => (), // nada. }; - - log!(debug, "on_nominator_add: {:?}. role: {:?}", who, T::Staking::status(who),); } /// A nominator has been idle. From the `T::VotertList` PoV, chilling a nominator is the same as @@ -726,18 +700,13 @@ impl OnStakingUpdate> for Pallet { /// Fired when someone removes their intention to nominate and is completely removed from /// the staking state. /// + /// Even in lazy mode, removing voter list nodes on nominator remove must be done. + /// /// Note: the number of nodes that are updated is bounded by the maximum number of /// nominators, which is defined in the staking pallet. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { - let nominator_vote = Self::weight_of(Self::active_vote_of(who)); - - log!( - debug, - "remove nominations from {:?} with {:?} weight. impacting {:?}.", - who, - nominator_vote, - nominations, - ); + let nominator_vote = Self::vote_of(who); + let nominations = Self::ensure_dedup(nominations); // updates the nominated target's score. for t in nominations.iter() { @@ -760,21 +729,18 @@ impl OnStakingUpdate> for Pallet { prev_nominations: Vec, nominations: Vec, ) { - let nominator_vote = Self::weight_of(Self::active_vote_of(who)); + let nominator_vote = Self::vote_of(who); - log!( - debug, - "on_nominator_update: {:?}, with {:?}. previous nominations: {:?} -> new nominations {:?}", - who, nominator_vote, prev_nominations, nominations, - ); + let nominations = Self::ensure_dedup(nominations); + let prev_nominations = Self::ensure_dedup(prev_nominations); - // new nominations + // new nominations. for target in nominations.iter() { if !prev_nominations.contains(target) { Self::update_target_score(target, StakeImbalance::Positive(nominator_vote.into())); } } - // removed nominations + // removed nominations. for target in prev_nominations.iter() { if !nominations.contains(target) { Self::update_target_score(target, StakeImbalance::Negative(nominator_vote.into())); @@ -782,6 +748,36 @@ impl OnStakingUpdate> for Pallet { } } + /// This is called when a staker is slashed. + /// + /// From the stake-tracker POV, no direct changes should be made to the target or voter list in + /// this event handler, since the stake updates from a slash will be indirectly performed + /// through the call to `on_stake_update`. + /// + /// However, if a slash of a nominator results on its active stake becoming 0, the stake + /// tracker *requests* the staking interface to chill the nominator in order to ensure that + /// their nominations are dropped. This way, we ensure that in the event of a validator and all + /// its nominators are 100% slashed, the target can be reaped/killed without leaving + /// nominations behind. + fn on_slash( + stash: &T::AccountId, + _slashed_active: BalanceOf, + _slashed_unlocking: &BTreeMap>, + slashed_total: BalanceOf, + ) { + let active_after_slash = T::Staking::stake(stash) + .defensive_unwrap_or_default() + .active + .saturating_sub(slashed_total); + + match (active_after_slash.is_zero(), T::Staking::status(stash)) { + (true, Ok(StakerStatus::Nominator(_))) => { + let _ = T::Staking::chill(stash).defensive(); + }, + _ => (), // do nothing. + }; + } + // no-op events. /// The score of the staker `who` is updated through the `on_stake_update` calls following the @@ -791,14 +787,4 @@ impl OnStakingUpdate> for Pallet { /// The score of the staker `who` is updated through the `on_stake_update` calls following the /// withdraw. fn on_withdraw(_who: &T::AccountId, _amount: BalanceOf) {} - - /// The score of the staker `who` is updated through the `on_stake_update` calls following the - /// slash. - fn on_slash( - _stash: &T::AccountId, - _slashed_active: BalanceOf, - _slashed_unlocking: &BTreeMap>, - _slashed_total: BalanceOf, - ) { - } } diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 3953a1a4d8e5..abc8b999e453 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -69,11 +69,16 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); } -const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = +const VOTER_THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = [100, 200, 300, 400, 500, 600, 700, 800, 900]; +const TARGET_THRESHOLDS: [u128; 9] = [100, 200, 300, 400, 500, 600, 700, 800, 900]; + parameter_types! { - pub static BagThresholds: &'static [VoteWeight] = &THRESHOLDS; + pub static VoterBagThresholds: &'static [VoteWeight] = &VOTER_THRESHOLDS; + pub static TargetBagThresholds: &'static [u128] = &TARGET_THRESHOLDS; + + pub static VoterUpdateMode: crate::VoterUpdateMode = crate::VoterUpdateMode::Strict; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -81,7 +86,7 @@ impl pallet_bags_list::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type ScoreProvider = StakingMock; - type BagThresholds = BagThresholds; + type BagThresholds = VoterBagThresholds; type Score = VoteWeight; } @@ -90,16 +95,16 @@ impl pallet_bags_list::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type ScoreProvider = pallet_bags_list::Pallet; - type BagThresholds = BagThresholds; - type Score = ::Balance; + type BagThresholds = TargetBagThresholds; + type Score = u128; } impl pallet_stake_tracker::Config for Test { type Currency = Balances; - type RuntimeEvent = RuntimeEvent; type Staking = StakingMock; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type VoterUpdateMode = VoterUpdateMode; } pub struct StakingMock {} @@ -273,10 +278,16 @@ parameter_types! { pub static Bonded: Vec = Default::default(); } -pub(crate) fn get_scores>( -) -> Vec<(AccountId, Balance)> { - let scores: Vec<_> = L::iter().map(|e| (e, L::get_score(&e).unwrap())).collect(); - scores +pub(crate) fn target_scores() -> Vec<(AccountId, u128)> { + TargetBagsList::iter() + .map(|e| (e, TargetBagsList::get_score(&e).unwrap())) + .collect::>() +} + +pub(crate) fn voter_scores() -> Vec<(AccountId, Balance)> { + VoterBagsList::iter() + .map(|e| (e, VoterBagsList::get_score(&e).unwrap())) + .collect::>() } pub(crate) fn populate_lists() { @@ -308,6 +319,8 @@ pub(crate) fn score_of_target(who: AccountId) -> Balance { as ScoreProvider>::score( &who, ) + .try_into() + .unwrap() } pub(crate) fn add_nominator_with_nominations( @@ -463,6 +476,11 @@ impl ExtBuilder { self } + pub fn voter_update_mode(self, mode: crate::VoterUpdateMode) -> Self { + VoterUpdateMode::set(mode); + self + } + #[allow(dead_code)] pub fn try_state(self, enable: bool) -> Self { DisableTryRuntimeChecks::set(!enable); @@ -486,9 +504,8 @@ impl ExtBuilder { } // move past genesis to register events. System::set_block_number(1); - - test() }); + ext.execute_with(test); if !DisableTryRuntimeChecks::get() { ext.execute_with(|| { diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 9c6221c25b03..23ae00778fea 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -17,7 +17,7 @@ #![cfg(test)] -use crate::{mock::*, SortingMode, StakeImbalance, VoterListMode}; +use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; use frame_support::assert_ok; @@ -116,7 +116,7 @@ fn on_stake_update_works() { let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); assert_eq!( nomination_score_after, - nomination_score_before - (stake_before.unwrap().active - new_stake.active) + nomination_score_before - (stake_before.unwrap().active - new_stake.active) as u128 ); }); @@ -148,38 +148,44 @@ fn on_stake_update_works() { // the stake imbalance of previous and the new stake, in order to not touch the nomination's // weight in the total target score). let target_score_after = TargetBagsList::get_score(&10).unwrap(); - assert_eq!(target_score_after, target_score_before - stake_imbalance); + assert_eq!(target_score_after, target_score_before - stake_imbalance as u128); }) } #[test] fn on_stake_update_lazy_voters_works() { - ExtBuilder::default().populate_lists().build_and_execute(|| { - VoterListMode::::set(SortingMode::Lazy); + ExtBuilder::default() + .populate_lists() + .voter_update_mode(crate::VoterUpdateMode::Lazy) + .build_and_execute(|| { + assert!(VoterBagsList::contains(&1)); + let stake_before = stake_of(1); - assert!(VoterBagsList::contains(&1)); - let stake_before = stake_of(1); + let nominations = ::nominations(&1).unwrap(); + assert!(nominations.len() == 1); - let nominations = ::nominations(&1).unwrap(); - assert!(nominations.len() == 1); - let nomination_score_before = TargetBagsList::get_score(&nominations[0]).unwrap(); + let target_score_before = TargetBagsList::get_score(&10).unwrap(); - // manually change the stake of the voter. - let new_stake = Stake { total: 10, active: 10 }; - // assert imbalance of the operation is negative. - assert!(stake_before.unwrap().active > new_stake.active); + // manually change the stake of the voter. + let new_stake = Stake { total: 10, active: 10 }; + // assert imbalance of the operation is negative. + assert!(stake_before.unwrap().active > new_stake.active); + let stake_imbalance = stake_before.unwrap().active - new_stake.total; - TestNominators::mutate(|n| { - n.insert(1, (new_stake, nominations.clone())); - }); + TestNominators::mutate(|n| { + n.insert(1, (new_stake, nominations.clone())); + }); - >::on_stake_update(&1, stake_before, new_stake); + >::on_stake_update(&1, stake_before, new_stake); - // score of voter did not update, since the voter list is lazily updated. - assert_eq!(VoterBagsList::get_score(&1).unwrap(), stake_before.unwrap().active); - let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); - assert_eq!(nomination_score_after, nomination_score_before,); - }); + // score of voter did not update, since the voter list is lazily updated. + assert_eq!(VoterBagsList::get_score(&1).unwrap(), stake_before.unwrap().active); + + // however, the target's approvals are *always* updated, regardless of the voter's + // sorting mode. + let target_score_after = TargetBagsList::get_score(&10).unwrap(); + assert_eq!(target_score_after, target_score_before - stake_imbalance as u128); + }); } #[test] @@ -224,7 +230,7 @@ fn on_stake_update_sorting_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { // [(10, 100), (11, 100), (1, 100), (2, 100)] - let voter_scores_before = get_scores::(); + let voter_scores_before = voter_scores(); assert_eq!(voter_scores_before, [(10, 100), (11, 100), (1, 100), (2, 100)]); // noop, nothing changes. @@ -234,7 +240,7 @@ fn on_stake_update_sorting_works() { initial_stake, initial_stake.unwrap(), ); - assert_eq!(voter_scores_before, get_scores::()); + assert_eq!(voter_scores_before, voter_scores()); // now let's change the self-vote of 11 and call `on_stake_update` again. let nominations = ::nominations(&11).unwrap(); @@ -384,7 +390,7 @@ fn on_nominator_remove_works() { // now, the score of the nominated by 1 has less `nominator_score` stake than before the // nominator was removed. let nomination_score_after = TargetBagsList::get_score(&nominations[0]).unwrap(); - assert!(nomination_score_after == nomination_score_before - nominator_score); + assert!(nomination_score_after == nomination_score_before - nominator_score as u128); }) } @@ -504,7 +510,7 @@ mod staking_integration { #[test] fn on_remove_stakers_with_nominations_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + assert_eq!(target_scores(), vec![(10, 300), (11, 200)]); assert!(VoterBagsList::contains(&1)); assert_eq!(VoterBagsList::get_score(&1), Ok(100)); @@ -521,52 +527,39 @@ mod staking_integration { #[test] fn on_nominator_update_works() { ExtBuilder::default().populate_lists().build_and_execute(|| { - assert_eq!( - get_scores::(), - vec![(10, 100), (11, 100), (1, 100), (2, 100)] - ); - assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); + assert_eq!(voter_scores(), vec![(10, 100), (11, 100), (1, 100), (2, 100)]); + assert_eq!(target_scores(), vec![(10, 300), (11, 200)]); add_validator(20, 500); // removes nomination from 10 and adds nomination to new validator, 20. update_nominations_of(2, vec![11, 20]); - assert_eq!( - get_scores::(), - [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)] - ); + assert_eq!(voter_scores(), [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)]); // target list has been updated: - assert_eq!(get_scores::(), vec![(20, 600), (11, 200), (10, 200)]); + assert_eq!(target_scores(), vec![(20, 600), (11, 200), (10, 200)]); }) } #[test] fn on_nominator_update_lazy_voter_works() { - ExtBuilder::default().populate_lists().build_and_execute(|| { - // sets voter list to lazy mode. - VoterListMode::::set(SortingMode::Lazy); - - assert_eq!( - get_scores::(), - vec![(10, 100), (11, 100), (1, 100), (2, 100)] - ); - assert_eq!(get_scores::(), vec![(10, 300), (11, 200)]); - - add_validator(20, 500); - // removes nomination from 10 and adds nomination to new validator, 20. - update_nominations_of(2, vec![11, 20]); - - // voter list has been updated because a new voter (20) has been added, not stake - // updated. - assert_eq!( - get_scores::(), - [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)] - ); - - // target list has been updated: - assert_eq!(get_scores::(), vec![(20, 600), (11, 200), (10, 200)]); - }) + ExtBuilder::default() + .populate_lists() + .voter_update_mode(crate::VoterUpdateMode::Lazy) + .build_and_execute(|| { + assert_eq!(voter_scores(), vec![(10, 100), (11, 100), (1, 100), (2, 100)]); + assert_eq!(target_scores(), vec![(10, 300), (11, 200)]); + + add_validator(20, 500); + // removes nomination from 10 and adds nomination to new validator, 20. + update_nominations_of(2, vec![11, 20]); + + // even in lazy mode, the new voter node is inserted. + assert_eq!(voter_scores(), [(20, 500), (10, 100), (11, 100), (1, 100), (2, 100)]); + + // target list has been updated: + assert_eq!(target_scores(), vec![(20, 600), (11, 200), (10, 200)]); + }) } #[test] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 53d482811eae..7a61c452b6e7 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -73,6 +73,12 @@ pub enum StakerStatus { Nominator(Vec), } +impl StakerStatus { + pub fn is_nominator(&self) -> bool { + matches!(self, Self::Nominator(_)) + } +} + /// A struct that reflects stake that an account has in the staking system. Provides a set of /// methods to operate on it's properties. Aimed at making `StakingInterface` more concise. #[derive(RuntimeDebug, Clone, Copy, Eq, PartialEq, Default)] From d726d0f6d6af1b82234953f46671d7bc231478aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 13:33:32 +0200 Subject: [PATCH 102/133] fixes zepter --- polkadot/runtime/westend/src/lib.rs | 1 - substrate/frame/staking/Cargo.toml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 74ff8a27a731..283aa9c5be69 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1747,7 +1747,6 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_session, SessionBench::] [pallet_staking, Staking] - [pallet_stake_tracker, StakeTracker] [pallet_sudo, Sudo] [frame_system, SystemBench::] [pallet_timestamp, Timestamp] diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 998c8fce3cf8..bab9062a5883 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -89,6 +89,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-migrations/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", From 3d4452f1cb4aed62bd8a74ad06109f41a49df583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 13:45:48 +0200 Subject: [PATCH 103/133] ensures mmb bench checks are deteministic --- substrate/frame/staking/src/benchmarking.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index b63f00129d38..0aca10f20a25 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1183,6 +1183,8 @@ mod benchmarks { ) .unwrap(); + let targets_count_before = T::TargetList::count(); + // drop targets from target list nominated by the one nominator to be migrated. let (_to_migrate, mut nominations) = Nominators::::iter() .map(|(n, noms)| (n, noms.targets.into_inner())) @@ -1193,13 +1195,13 @@ mod benchmarks { nominations.sort(); nominations.dedup(); + // drop targets nominated by the first nominator. for t in nominations.iter() { assert_ok!(T::TargetList::on_remove(&t)); } - // targets nominated by first nominator will be dropped from the target list. - // note: +1 because there is one extra validator added by the test setup. - assert_eq!(T::TargetList::count(), n_validators + 1 - nominations.len() as u32); + // confirm targets dropped. + assert!(T::TargetList::count() < targets_count_before); #[block] { @@ -1207,7 +1209,7 @@ mod benchmarks { .unwrap(); } - assert_eq!(T::TargetList::count(), n_validators + 1); + assert_eq!(T::TargetList::count(), targets_count_before); } impl_benchmark_test_suite!( From d2251764f6a3d93d1ce8bc352f4da9789cc0df56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 14:52:13 +0200 Subject: [PATCH 104/133] clippy nits --- .../test-staking-e2e/src/mock.rs | 17 +++++++++++------ .../election-provider-support/src/lib.rs | 8 ++++++-- substrate/frame/staking/src/mock.rs | 1 - substrate/frame/staking/src/pallet/impls.rs | 19 ------------------- substrate/frame/staking/src/tests.rs | 1 + .../frame/staking/stake-tracker/src/lib.rs | 9 ++++----- 6 files changed, 22 insertions(+), 33 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 125f04a0c5a2..50c266d4dba8 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -50,6 +50,7 @@ use pallet_election_provider_multi_phase::{ unsigned::MinerConfig, Call, ElectionCompute, GeometricDepositBase, QueuedSolution, SolutionAccuracyOf, }; +use pallet_stake_tracker::VoterUpdateMode; use pallet_staking::StakerStatus; use parking_lot::RwLock; use std::sync::Arc; @@ -83,7 +84,7 @@ frame_support::construct_runtime!( pub(crate) type AccountId = u64; pub(crate) type AccountIndex = u32; pub(crate) type BlockNumber = u32; -pub(crate) type Balance = u64; +pub(crate) type Balance = u128; pub(crate) type VoterIndex = u16; pub(crate) type TargetIndex = u16; pub(crate) type Moment = u32; @@ -232,11 +233,11 @@ impl MinerConfig for Runtime { } const VOTERS_THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; -const TARGETS_THRESHOLDS: [Balance; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; +const TARGETS_THRESHOLDS: [u128; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; parameter_types! { pub static VoterBagThresholds: &'static [VoteWeight] = &VOTERS_THRESHOLDS; - pub static TargetBagThresholds: &'static [Balance] = &TARGETS_THRESHOLDS; + pub static TargetBagThresholds: &'static [u128] = &TARGETS_THRESHOLDS; pub const SessionsPerEra: sp_staking::SessionIndex = 2; pub static BondingDuration: sp_staking::EraIndex = 28; pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. @@ -256,17 +257,21 @@ type TargetBagsListInstance = pallet_bags_list::Instance2; impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - type ScoreProvider = Staking; + type ScoreProvider = pallet_bags_list::Pallet; type BagThresholds = TargetBagThresholds; - type Score = VoteWeight; + type Score = u128; +} + +parameter_types! { + pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Strict; } impl pallet_stake_tracker::Config for Runtime { type Currency = Balances; - type RuntimeEvent = RuntimeEvent; type Staking = Staking; type VoterList = VoterBagsList; type TargetList = TargetBagsList; + type VoterUpdateMode = UpdateMode; } pub struct BalanceToU256; diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 1d64504c6189..2ce79b54ccad 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -570,11 +570,15 @@ pub trait SortedListProvider { /// /// Returns a boolean and it is only available in the context of `try-runtime` checks. #[cfg(feature = "try-runtime")] - fn in_position(id: &AccountId) -> Result; + fn in_position(_id: &AccountId) -> Result { + unimplemented!() + } /// Check internal state of the list. Only meant for debugging. #[cfg(feature = "try-runtime")] - fn try_state() -> Result<(), TryRuntimeError>; + fn try_state() -> Result<(), TryRuntimeError> { + Ok(()) + } /// If `who` changes by the returned amount they are guaranteed to have a worst case change /// in their list position. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 637c49b8b2d2..7177ac1abdee 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -396,7 +396,6 @@ impl crate::pallet::pallet::Config for Test { type MaxExposurePageSize = MaxExposurePageSize; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; - // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = VoterBagsList; type TargetList = TargetBagsList; type NominationsQuota = WeightedNominationsQuota<16>; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b3e1dca816b2..d936503e1aa2 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1750,15 +1750,6 @@ impl SortedListProvider for UseValidatorsMap { // nothing to do upon regenerate. 0 } - #[cfg(feature = "try-runtime")] - fn in_position(_: &T::AccountId) -> Result { - unimplemented!() - } - #[cfg(feature = "try-runtime")] - fn try_state() -> Result<(), TryRuntimeError> { - Ok(()) - } - fn unsafe_clear() { #[allow(deprecated)] Validators::::remove_all(); @@ -1830,16 +1821,6 @@ impl SortedListProvider for UseNominatorsAndValidatorsM // nothing to do upon regenerate. 0 } - - #[cfg(feature = "try-runtime")] - fn in_position(_: &T::AccountId) -> Result { - unimplemented!() - } - #[cfg(feature = "try-runtime")] - fn try_state() -> Result<(), TryRuntimeError> { - Ok(()) - } - fn unsafe_clear() { // NOTE: Caller must ensure this doesn't lead to too many storage accesses. This is a // condition of SortedListProvider::unsafe_clear. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 33d081808fb3..9d835368fdc7 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1978,6 +1978,7 @@ fn reap_stash_works_with_existential_deposit_zero() { ExtBuilder::default() .existential_deposit(0) .balance_factor(10) + .stake_tracker_try_state(false) .build_and_execute(|| { // given assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index c24f8aa289f5..b1be2c8778d4 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -770,11 +770,10 @@ impl OnStakingUpdate> for Pallet { .active .saturating_sub(slashed_total); - match (active_after_slash.is_zero(), T::Staking::status(stash)) { - (true, Ok(StakerStatus::Nominator(_))) => { - let _ = T::Staking::chill(stash).defensive(); - }, - _ => (), // do nothing. + if let (true, Ok(StakerStatus::Nominator(_))) = + (active_after_slash.is_zero(), T::Staking::status(stash)) + { + let _ = T::Staking::chill(stash).defensive(); }; } From a56f7654ce098794b6eaa3e7eb0afe586e5843fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 15:12:08 +0200 Subject: [PATCH 105/133] taplo nit fixes --- substrate/frame/staking/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index bab9062a5883..63774dc18dcf 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -89,8 +89,8 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "pallet-stake-tracker/runtime-benchmarks", "pallet-migrations/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "rand_chacha", "sp-runtime/runtime-benchmarks", From 80895adc9083e8b8e54b59c5631433fe41c23c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 10 May 2024 19:27:44 +0200 Subject: [PATCH 106/133] clippy nit --- substrate/frame/staking/stake-tracker/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 23ae00778fea..dc7442c2e112 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -61,7 +61,7 @@ fn update_target_score_works() { let current_score = TargetBagsList::get_score(&10).unwrap(); crate::Pallet::::update_target_score( &10, - StakeImbalance::Negative(current_score.into()), + StakeImbalance::Negative(current_score), ); assert_eq!(TargetBagsList::get_score(&10), Ok(0)); From 6219b32609fcb3aada757baeb80ac887f86e85f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 3 Jun 2024 12:07:56 +0100 Subject: [PATCH 107/133] Stake tracker improvements (migration and try-state checks OK in Polkadot) (#4673) Changes in the migration code introduced in this PR: - Migration removes duplicate nominations in all nominators, if they exist (changes by calling `fn do_add_nominator` with dedup nominations) - Migration removes all the non active validator nominations to avoid adding dangling nominations (changes by calling `fn do_add_nominator` if necessary) - Migration iterates through all `Nominators` map first and through all the `Validators` map to insert all the validators that are not nominated to the target list (with self-stake only). - Moves stake-tracker related try-state checks to the staking pallet (no try-state checks in the stake-tracker pallet anymore). - Runs benchmarks for MMB migration step with bench bot. The migration code has been validated against the Polkadot using the externalities tests in [polkadot/runtime/westend/src/lib.rs](https://github.com/paritytech/polkadot-sdk/pull/4436/files/46a80f14ba8990b014d8f9df36727c77e2f3e929#diff-5264d812f7aadfc486efffd3322b11c8dee5e8ddf2e77e0a9e70b573f3d2afdd). Upon running the migrations, we ensure that: - All validators have been added to the target list with their correct approvals score (as per the try-state checks). - All nominations are "cleaned" (see def. of clean above) - Try-state checks related to stake-tracker and approvals pass. Note: Same as https://github.com/paritytech/polkadot-sdk/pull/4436 but with a non-messed up git history. Merging into `gpestana/stake-tracker_integration`. --------- Co-authored-by: Ankan Co-authored-by: command-bot <> --- Cargo.lock | 897 +++++++++--------- polkadot/runtime/westend/src/lib.rs | 5 +- .../westend/src/weights/pallet_staking.rs | 549 +++++++---- substrate/bin/node/runtime/src/lib.rs | 2 +- .../test-staking-e2e/src/mock.rs | 2 +- substrate/frame/staking/Cargo.toml | 4 +- substrate/frame/staking/src/benchmarking.rs | 34 +- .../src/migrations/v13_stake_tracker/mod.rs | 295 ++++-- .../src/migrations/v13_stake_tracker/tests.rs | 57 +- substrate/frame/staking/src/mock.rs | 24 +- substrate/frame/staking/src/pallet/impls.rs | 187 +++- substrate/frame/staking/src/pallet/mod.rs | 59 +- substrate/frame/staking/src/tests.rs | 242 +++-- .../frame/staking/stake-tracker/Cargo.toml | 3 - .../frame/staking/stake-tracker/src/lib.rs | 262 +---- .../frame/staking/stake-tracker/src/mock.rs | 18 - .../frame/staking/stake-tracker/src/tests.rs | 20 +- 17 files changed, 1390 insertions(+), 1270 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0ee0ea4c6fb..96ca31f11d59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +checksum = "b155716bab55763c95ba212806cf43d05bcc70e5f35b02bad20cf5ec7fe11fed" dependencies = [ "arrayvec 0.7.4", "bytes", @@ -156,9 +156,9 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", "syn-solidity", "tiny-keccak", ] @@ -262,9 +262,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "approx" @@ -284,9 +284,9 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -515,7 +515,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -603,7 +603,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -644,9 +644,9 @@ dependencies = [ [[package]] name = "array-bytes" -version = "6.2.2" +version = "6.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" +checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293" [[package]] name = "arrayref" @@ -691,7 +691,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "synstructure", @@ -703,7 +703,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -1061,22 +1061,21 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite 0.2.14", ] [[package]] name = "async-executor" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" dependencies = [ "async-task", "concurrent-queue", @@ -1103,10 +1102,10 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-executor", - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", "blocking", "futures-lite 2.3.0", "once_cell", @@ -1134,17 +1133,17 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ - "async-lock 3.3.0", + "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.0", + "polling 3.7.1", "rustix 0.38.34", "slab", "tracing", @@ -1162,12 +1161,12 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.3.1", + "event-listener-strategy", "pin-project-lite 0.2.14", ] @@ -1201,12 +1200,12 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afe66191c335039c7bb78f99dc7520b0cbb166b3a1cb33a03f53d8a1c6f2afda" +checksum = "329972aa325176e89114919f2a80fdae4f4c040f66a370b1a1159c6c0f94e7aa" dependencies = [ - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", @@ -1261,9 +1260,9 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1278,9 +1277,9 @@ version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1325,9 +1324,9 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1464,12 +1463,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease 0.2.20", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "regex", "rustc-hash", "shlex", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1631,12 +1630,11 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "async-channel 2.2.1", - "async-lock 3.3.0", + "async-channel 2.3.1", "async-task", "futures-io", "futures-lite 2.3.0", @@ -2391,9 +2389,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" [[package]] name = "byteorder" @@ -2430,9 +2428,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -2474,9 +2472,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", @@ -2645,9 +2643,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -2735,7 +2733,7 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -2747,9 +2745,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -2936,9 +2934,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" dependencies = [ "nom", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -2974,7 +2972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" dependencies = [ "strum 0.26.2", - "strum_macros 0.26.2", + "strum_macros 0.26.3", "unicode-width", ] @@ -3034,9 +3032,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.11.3" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba00838774b4ab0233e355d26710fbfc8327a05c017f6dc4873f876d1f79f78" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if", "cpufeatures", @@ -3465,9 +3463,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -3540,9 +3538,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -3631,7 +3629,7 @@ dependencies = [ "cumulus-test-runtime", "futures", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -3744,7 +3742,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-consensus", "sp-api", "sp-block-builder", @@ -3769,7 +3767,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-parachain-primitives", "polkadot-primitives", @@ -3967,9 +3965,9 @@ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4219,7 +4217,7 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-availability-recovery", "polkadot-collator-protocol", "polkadot-core-primitives", @@ -4528,9 +4526,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4567,10 +4565,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "scratch", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4585,9 +4583,9 @@ version = "1.0.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928bc249a7e3cd554fd2e8e08a426e9670c50bbfc9a621653cfa9accc9641783" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4677,7 +4675,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -4688,7 +4686,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -4699,9 +4697,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4711,7 +4709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "rustc_version 0.4.0", "syn 1.0.109", @@ -4807,9 +4805,9 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4869,12 +4867,12 @@ dependencies = [ "common-path", "derive-syn-parse 0.2.0", "once_cell", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "regex", - "syn 2.0.61", + "syn 2.0.66", "termcolor", - "toml 0.8.12", + "toml 0.8.13", "walkdir", ] @@ -4918,7 +4916,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -5009,9 +5007,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -5087,7 +5085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -5099,9 +5097,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5119,9 +5117,9 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5130,9 +5128,9 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5223,11 +5221,12 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", + "typeid", ] [[package]] @@ -5242,9 +5241,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5310,43 +5309,22 @@ dependencies = [ [[package]] name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite 0.2.14", -] - -[[package]] -name = "event-listener" -version = "5.3.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite 0.2.14", ] -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite 0.2.14", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.3.1", "pin-project-lite 0.2.14", ] @@ -5367,7 +5345,7 @@ checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" dependencies = [ "blake3", "fs-err", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", ] @@ -5380,9 +5358,9 @@ dependencies = [ "blake2 0.10.6", "fs-err", "prettier-please", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5452,7 +5430,7 @@ dependencies = [ "expander 0.0.4", "indexmap 1.9.3", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "thiserror", @@ -5509,9 +5487,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file-per-thread-logger" @@ -5547,7 +5525,7 @@ dependencies = [ "log", "num-traits", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "scale-info", ] @@ -5563,7 +5541,7 @@ dependencies = [ "futures", "log", "num-traits", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "relay-utils", ] @@ -5778,11 +5756,11 @@ dependencies = [ "frame-support", "parity-scale-codec", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "scale-info", "sp-arithmetic", - "syn 2.0.61", + "syn 2.0.66", "trybuild", ] @@ -5949,11 +5927,11 @@ dependencies = [ "itertools 0.11.0", "macro_magic", "proc-macro-warning", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "regex", "sp-crypto-hashing", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5962,18 +5940,18 @@ version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6220,9 +6198,9 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6463,7 +6441,7 @@ dependencies = [ "futures-timer", "no-std-compat", "nonzero_ext", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "portable-atomic", "quanta", "rand 0.8.5", @@ -6622,9 +6600,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex-literal" @@ -6682,13 +6660,13 @@ dependencies = [ [[package]] name = "honggfuzz" -version = "0.5.55" +version = "0.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" dependencies = [ "arbitrary", "lazy_static", - "memmap2 0.5.10", + "memmap2 0.9.4", "rustc_version 0.4.0", ] @@ -6859,7 +6837,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "async-io 2.3.2", + "async-io 2.3.3", "core-foundation", "fnv", "futures", @@ -6916,7 +6894,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -6936,7 +6914,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", ] @@ -6997,9 +6975,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -7225,7 +7203,7 @@ dependencies = [ "futures-util", "hyper", "jsonrpsee-types", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "rustc-hash", @@ -7265,9 +7243,9 @@ checksum = "7d0bb047e79a143b32ea03974a6bf59b62c2a4c5f5d42a381c907a8bbb3f75c0" dependencies = [ "heck 0.4.1", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -7511,7 +7489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parking_lot 0.12.2", + "parking_lot 0.12.3", ] [[package]] @@ -7522,7 +7500,7 @@ checksum = "b644c70b92285f66bfc2032922a79000ea30af7bc2ab31902992a5dcb9b434f6" dependencies = [ "kvdb", "num_cpus", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "regex", "rocksdb", "smallvec", @@ -7568,9 +7546,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libflate" @@ -7703,7 +7681,7 @@ dependencies = [ "multihash 0.17.0", "multistream-select", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "quick-protobuf", "rand 0.8.5", @@ -7723,7 +7701,7 @@ dependencies = [ "futures", "libp2p-core", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "smallvec", "trust-dns-resolver 0.22.0", ] @@ -7885,7 +7863,7 @@ dependencies = [ "libp2p-identity", "libp2p-tls", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "quinn-proto", "rand 0.8.5", "rustls 0.20.9", @@ -8001,7 +7979,7 @@ dependencies = [ "futures-rustls", "libp2p-core", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "quicksink", "rw-stream-sink", "soketto", @@ -8097,9 +8075,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -8154,9 +8132,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lioness" @@ -8208,7 +8186,7 @@ dependencies = [ "multihash 0.17.0", "network-interface", "nohash-hasher", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "prost 0.11.9", "prost-build 0.11.9", @@ -8333,7 +8311,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -8345,9 +8323,9 @@ dependencies = [ "const-random", "derive-syn-parse 0.1.5", "macro_magic_core_macros", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -8356,9 +8334,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -8369,7 +8347,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -8485,7 +8463,7 @@ dependencies = [ "hex", "log", "num-traits", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "relay-utils", "sp-arithmetic", ] @@ -8581,9 +8559,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -8615,7 +8593,7 @@ dependencies = [ "hashlink", "lioness", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", @@ -8631,7 +8609,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-offchain", @@ -8684,7 +8662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -8791,7 +8769,7 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "synstructure", @@ -8816,7 +8794,7 @@ checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "synstructure", @@ -8870,7 +8848,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -9214,9 +9192,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -9402,9 +9380,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -9415,9 +9393,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.2.3+3.2.1" +version = "300.3.0+3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" +checksum = "eba8804a1c5765b18c4b3f907e6897ebabeedebc9830e1a0046c4a4cf44663e1" dependencies = [ "cc", ] @@ -9469,7 +9447,7 @@ dependencies = [ "itertools 0.11.0", "petgraph", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -10131,7 +10109,7 @@ dependencies = [ "polkavm-linker", "sp-runtime", "tempfile", - "toml 0.8.12", + "toml 0.8.13", "twox-hash", ] @@ -10177,9 +10155,9 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -10297,7 +10275,7 @@ dependencies = [ "pallet-staking", "pallet-timestamp", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "scale-info", "sp-core", "sp-io", @@ -10320,7 +10298,7 @@ dependencies = [ "pallet-balances", "pallet-election-provider-support-benchmarking", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "scale-info", "sp-arithmetic", @@ -11392,7 +11370,6 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", - "log", "pallet-bags-list", "pallet-balances", "parity-scale-codec", @@ -11443,10 +11420,10 @@ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "sp-runtime", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -11477,7 +11454,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "scale-info", "serde", "sp-core", @@ -12075,7 +12052,7 @@ dependencies = [ "log", "lz4", "memmap2 0.5.10", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "siphasher", "snap", @@ -12104,7 +12081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -12127,7 +12104,7 @@ dependencies = [ "impl-trait-for-tuples", "lru 0.8.1", "parity-util-mem-derive", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "primitive-types", "smallvec", "winapi", @@ -12139,7 +12116,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "syn 1.0.109", "synstructure", ] @@ -12169,9 +12146,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core 0.9.10", @@ -12562,9 +12539,9 @@ checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -12603,9 +12580,9 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -12628,9 +12605,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" dependencies = [ "atomic-waker", "fastrand 2.1.0", @@ -12661,9 +12638,9 @@ checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -12674,15 +12651,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -12952,7 +12929,7 @@ dependencies = [ "futures", "futures-timer", "lazy_static", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-network-protocol", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -12986,7 +12963,7 @@ dependencies = [ "futures", "futures-timer", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -13042,7 +13019,7 @@ dependencies = [ "log", "merlin", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13083,7 +13060,7 @@ dependencies = [ "kvdb-memorydb", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-erasure-coding", "polkadot-node-jaeger", "polkadot-node-primitives", @@ -13199,7 +13176,7 @@ dependencies = [ "kvdb", "kvdb-memorydb", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -13462,7 +13439,7 @@ dependencies = [ "log", "mick-jaeger", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-primitives", "sc-network", @@ -13562,7 +13539,7 @@ version = "1.0.0" dependencies = [ "async-trait", "futures", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-erasure-coding", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -13624,7 +13601,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "polkadot-node-jaeger", "polkadot-node-metrics", @@ -13658,7 +13635,7 @@ dependencies = [ "futures", "futures-timer", "orchestra", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -14113,7 +14090,7 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-db", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", @@ -14558,9 +14535,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -14570,7 +14547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -14612,9 +14589,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" dependencies = [ "cfg-if", "concurrent-queue", @@ -14682,7 +14659,7 @@ dependencies = [ "log", "nix 0.26.4", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "smallvec", "symbolic-demangle", "tempfile", @@ -14742,8 +14719,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ - "proc-macro2 1.0.82", - "syn 2.0.61", + "proc-macro2 1.0.85", + "syn 2.0.66", ] [[package]] @@ -14762,7 +14739,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28f53e8b192565862cf99343194579a022eb9c7dd3a8d03134734803c7b3125" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "syn 1.0.109", ] @@ -14772,8 +14749,8 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ - "proc-macro2 1.0.82", - "syn 2.0.61", + "proc-macro2 1.0.85", + "syn 2.0.66", ] [[package]] @@ -14833,7 +14810,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "version_check", @@ -14845,7 +14822,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "version_check", ] @@ -14856,9 +14833,9 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -14872,9 +14849,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -14915,7 +14892,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "thiserror", ] @@ -14927,7 +14904,7 @@ checksum = "5d6fa99d535dd930d1249e6c79cb3c2915f9172a540fe2b02a4c8f9ca954721e" dependencies = [ "dtoa", "itoa", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "prometheus-client-derive-encode", ] @@ -14937,9 +14914,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -14986,12 +14963,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.12.4", + "prost-derive 0.12.6", ] [[package]] @@ -15018,9 +14995,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", @@ -15030,10 +15007,10 @@ dependencies = [ "once_cell", "petgraph", "prettyplease 0.2.20", - "prost 0.12.4", - "prost-types 0.12.4", + "prost 0.12.6", + "prost-types 0.12.6", "regex", - "syn 2.0.61", + "syn 2.0.66", "tempfile", ] @@ -15045,22 +15022,22 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] [[package]] name = "prost-derive" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -15074,11 +15051,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.12.4", + "prost 0.12.6", ] [[package]] @@ -15249,7 +15226,7 @@ version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", ] [[package]] @@ -15489,9 +15466,9 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -16044,12 +16021,12 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.61", + "syn 2.0.66", "unicode-ident", ] @@ -16199,7 +16176,7 @@ dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] @@ -16236,7 +16213,7 @@ dependencies = [ "log", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.3", + "rustls-webpki 0.102.4", "subtle 2.5.0", "zeroize", ] @@ -16303,9 +16280,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.3" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -16314,9 +16291,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -16409,8 +16386,8 @@ dependencies = [ "multihash 0.17.0", "multihash-codetable", "parity-scale-codec", - "prost 0.12.4", - "prost-build 0.12.4", + "prost 0.12.6", + "prost-build 0.12.6", "quickcheck", "rand 0.8.5", "sc-client-api", @@ -16436,7 +16413,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-proposer-metrics", @@ -16504,9 +16481,9 @@ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -16560,7 +16537,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-executor", "sc-transaction-pool-api", "sc-utils", @@ -16596,7 +16573,7 @@ dependencies = [ "log", "parity-db", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "quickcheck", "rand 0.8.5", "sc-client-api", @@ -16623,7 +16600,7 @@ dependencies = [ "futures-timer", "log", "mockall", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-client-api", "sc-network-types", "sc-utils", @@ -16647,7 +16624,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16689,7 +16666,7 @@ dependencies = [ "num-rational", "num-traits", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16758,7 +16735,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -16799,7 +16776,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-consensus-beefy", "sc-rpc", "serde", @@ -16839,7 +16816,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "sc-block-builder", "sc-chain-spec", @@ -16945,7 +16922,7 @@ dependencies = [ "futures-timer", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-client-api", "sc-consensus", "sp-api", @@ -16993,7 +16970,7 @@ dependencies = [ "env_logger 0.11.3", "num_cpus", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "paste", "regex", "sc-executor-common", @@ -17055,7 +17032,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "paste", "rustix 0.36.17", "sc-allocator", @@ -17090,7 +17067,7 @@ name = "sc-keystore" version = "25.0.0" dependencies = [ "array-bytes", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "serde_json", "sp-application-crypto", "sp-core", @@ -17113,7 +17090,7 @@ dependencies = [ "mixnet", "multiaddr", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-client-api", "sc-network", "sc-network-types", @@ -17151,11 +17128,11 @@ dependencies = [ "multistream-select", "once_cell", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "partial_sort", "pin-project", - "prost 0.12.4", - "prost-build 0.12.4", + "prost 0.12.6", + "prost-build 0.12.6", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17200,7 +17177,7 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build 0.12.4", + "prost-build 0.12.6", "sc-consensus", "sc-network-types", "sp-consensus", @@ -17242,8 +17219,8 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "prost 0.12.4", - "prost-build 0.12.4", + "prost 0.12.6", + "prost-build 0.12.6", "sc-client-api", "sc-network", "sc-network-types", @@ -17287,8 +17264,8 @@ dependencies = [ "log", "mockall", "parity-scale-codec", - "prost 0.12.4", - "prost-build 0.12.4", + "prost 0.12.6", + "prost-build 0.12.6", "quickcheck", "sc-block-builder", "sc-client-api", @@ -17323,7 +17300,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17395,7 +17372,7 @@ dependencies = [ "num_cpus", "once_cell", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "sc-block-builder", "sc-client-api", @@ -17438,7 +17415,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pretty_assertions", "sc-block-builder", "sc-chain-spec", @@ -17520,7 +17497,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pretty_assertions", "rand 0.8.5", "sc-block-builder", @@ -17575,7 +17552,7 @@ dependencies = [ "jsonrpsee", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "sc-chain-spec", @@ -17638,7 +17615,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -17670,7 +17647,7 @@ version = "0.30.0" dependencies = [ "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sp-core", ] @@ -17681,7 +17658,7 @@ dependencies = [ "env_logger 0.11.3", "log", "parity-db", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-client-api", "sc-keystore", "sp-api", @@ -17753,7 +17730,7 @@ dependencies = [ "futures", "libp2p", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "sc-network", @@ -17776,7 +17753,7 @@ dependencies = [ "libc", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "regex", "rustc-hash", "sc-client-api", @@ -17799,9 +17776,9 @@ name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -17817,7 +17794,7 @@ dependencies = [ "linked-hash-map", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-block-builder", "sc-client-api", "sc-transaction-pool-api", @@ -17863,7 +17840,7 @@ dependencies = [ "futures-timer", "lazy_static", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "prometheus", "sp-arithmetic", "tokio-test", @@ -17890,7 +17867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -17906,9 +17883,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6e7ed6919cb46507fb01ff1654309219f62b4d603822501b0b80d42f6f21ef" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -17918,21 +17895,21 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185f2b7aa7e02d418e453790dde16890256bbd2bcd04b7dc5348811052b53f49" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "serde_derive_internals", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "schnellru" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0cf7da6fc4477944d5529807234f66802fcb618fc62b9c05bedca7f9be6c43" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -18185,9 +18162,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -18212,24 +18189,24 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -18255,9 +18232,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -18307,7 +18284,7 @@ dependencies = [ "futures", "lazy_static", "log", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "serial_test_derive", ] @@ -18317,9 +18294,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -18658,7 +18635,7 @@ dependencies = [ "log", "lru 0.11.1", "no-std-net", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project", "rand 0.8.5", "rand_chacha 0.3.1", @@ -19163,9 +19140,9 @@ dependencies = [ "blake2 0.10.6", "expander 2.1.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -19288,7 +19265,7 @@ dependencies = [ "futures", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "schnellru", "sp-api", "sp-consensus", @@ -19441,7 +19418,7 @@ dependencies = [ "merlin", "parity-bip39", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "paste", "primitive-types", "rand 0.8.5", @@ -19512,7 +19489,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -19549,7 +19526,7 @@ version = "0.1.0" dependencies = [ "quote 1.0.36", "sp-crypto-hashing", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -19557,26 +19534,26 @@ name = "sp-database" version = "10.0.0" dependencies = [ "kvdb", - "parking_lot 0.12.2", + "parking_lot 0.12.3", ] [[package]] name = "sp-debug-derive" version = "14.0.0" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -19591,7 +19568,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.25.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "environmental", "parity-scale-codec", @@ -19661,7 +19638,7 @@ name = "sp-keystore" version = "0.34.0" dependencies = [ "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "rand_chacha 0.3.1", "sp-core", @@ -19822,7 +19799,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -19845,22 +19822,22 @@ dependencies = [ "Inflector", "expander 2.1.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "Inflector", "expander 2.1.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -19935,7 +19912,7 @@ dependencies = [ "hash-db", "log", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pretty_assertions", "rand 0.8.5", "smallvec", @@ -19979,7 +19956,7 @@ version = "14.0.0" [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" [[package]] name = "sp-storage" @@ -19995,7 +19972,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "19.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "impl-serde", "parity-scale-codec", @@ -20040,7 +20017,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "parity-scale-codec", "tracing", @@ -20081,7 +20058,7 @@ dependencies = [ "memory-db", "nohash-hasher", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "scale-info", "schnellru", @@ -20117,10 +20094,10 @@ name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "sp-version", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -20137,7 +20114,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#37b1544b51aeba183350d4c8d76987c32e6c9ca7" +source = "git+https://github.com/paritytech/polkadot-sdk#f66e693a6befef0956a3129254fbe568247c9c57" dependencies = [ "impl-trait-for-tuples", "log", @@ -20208,7 +20185,7 @@ checksum = "4743ce898933fbff7bbf414f497c459a782d496269644b3d650a398ae6a487ba" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "serde", "serde_json", @@ -20233,7 +20210,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -20501,7 +20478,7 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -20576,7 +20553,7 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", ] @@ -20596,7 +20573,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" dependencies = [ - "strum_macros 0.26.2", + "strum_macros 0.26.3", ] [[package]] @@ -20606,7 +20583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "rustversion", "syn 1.0.109", @@ -20614,15 +20591,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "f7993a8e3a9e88a00351486baae9522c91b123a088f76469e5bd5cc17198ea87" dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.82", + "heck 0.5.0", + "proc-macro2 1.0.85", "quote 1.0.36", "rustversion", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -20904,7 +20881,7 @@ version = "2.0.0" dependencies = [ "futures", "parity-scale-codec", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", @@ -20936,7 +20913,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum 0.26.2", "tempfile", - "toml 0.8.12", + "toml 0.8.13", "walkdir", "wasm-opt", ] @@ -21077,18 +21054,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.61" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "unicode-ident", ] @@ -21100,9 +21077,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -21117,7 +21094,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "syn 1.0.109", "unicode-xid 0.2.4", @@ -21358,9 +21335,9 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] @@ -21380,20 +21357,20 @@ version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -21534,16 +21511,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "pin-project-lite 0.2.14", "signal-hook-registry", "socket2 0.5.7", @@ -21553,13 +21530,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -21659,21 +21636,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.13", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -21702,15 +21679,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.9", ] [[package]] @@ -21776,9 +21753,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -21818,9 +21795,9 @@ dependencies = [ "assert_matches", "expander 2.1.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -21844,7 +21821,7 @@ dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "regex", "sharded-slab", "smallvec", @@ -21872,9 +21849,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ed83be775d85ebb0e272914fff6462c39b3ddd6dc67b5c1c41271aad280c69" +checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" dependencies = [ "hash-db", "log", @@ -21963,7 +21940,7 @@ dependencies = [ "ipconfig", "lazy_static", "lru-cache", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "resolv-conf", "smallvec", "thiserror", @@ -21983,7 +21960,7 @@ dependencies = [ "ipconfig", "lru-cache", "once_cell", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "resolv-conf", "smallvec", @@ -22001,9 +21978,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe21c256d6fba8499cf9d9b1c24971bec43a369d81c52e024adc7670cf112df" +checksum = "33a5f13f11071020bb12de7a16b925d2d58636175c20c11dc5f96cb64bb6c9b3" dependencies = [ "dissimilar", "glob", @@ -22011,7 +21988,7 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml 0.8.12", + "toml 0.8.13", ] [[package]] @@ -22058,6 +22035,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "typeid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" + [[package]] name = "typenum" version = "1.17.0" @@ -22271,9 +22254,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "w3f-bls" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" +checksum = "9c5da5fa2c6afa2c9158eaa7cd9aee249765eb32b5fb0c63ad8b9e79336a47ec" dependencies = [ "ark-bls12-377", "ark-bls12-381", @@ -22304,9 +22287,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -22369,9 +22352,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -22403,9 +22386,9 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -22436,16 +22419,16 @@ version = "0.3.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "wasm-encoder" -version = "0.207.0" +version = "0.209.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d996306fb3aeaee0d9157adbe2f670df0236caf19f6728b221e92d0f27b3fe17" +checksum = "7b4a05336882dae732ce6bd48b7e11fe597293cb72c13da4f35d7d5f8d53b2a7" dependencies = [ "leb128", ] @@ -22761,9 +22744,9 @@ dependencies = [ [[package]] name = "wast" -version = "207.0.0" +version = "209.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e40be9fd494bfa501309487d2dc0b3f229be6842464ecbdc54eac2679c84c93" +checksum = "8fffef2ff6147e4d12e972765fd75332c6a11c722571d4ab7a780d81ffc8f0a4" dependencies = [ "bumpalo", "leb128", @@ -22774,9 +22757,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.207.0" +version = "1.209.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb2b15e2d5f300f5e1209e7dc237f2549edbd4203655b6c6cab5cf180561ee7" +checksum = "42203ec0271d113f8eb1f77ebc624886530cecb35915a7f63a497131f16e4d24" dependencies = [ "wast", ] @@ -22990,9 +22973,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.17" +version = "0.7.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0e39d2c603fdc0504b12b458cf1f34e0b937ed2f4f2dc20796e3e86f34e11f" +checksum = "cd8dc749a1b03f3c255a3064a4f5c0ee5ed09b7c6bc6d4525d31f779cd74d7fc" dependencies = [ "bytemuck", "safe_arch", @@ -23304,9 +23287,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] @@ -23395,7 +23378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "rustix 0.38.34", ] @@ -23485,10 +23468,10 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", "staging-xcm", - "syn 2.0.61", + "syn 2.0.66", "trybuild", ] @@ -23573,7 +23556,7 @@ dependencies = [ "futures", "log", "nohash-hasher", - "parking_lot 0.12.2", + "parking_lot 0.12.3", "rand 0.8.5", "static_assertions", ] @@ -23608,16 +23591,16 @@ version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] @@ -23628,9 +23611,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.85", "quote 1.0.36", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 283aa9c5be69..578f822352d5 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -583,7 +583,7 @@ parameter_types! { pub const VoterBagThresholds: &'static [u64] = &bag_thresholds::VOTER_THRESHOLDS; pub const TargetBagThresholds: &'static [u128] = &bag_thresholds::TARGET_THRESHOLDS; - pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; + pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -1685,8 +1685,7 @@ pub mod migrations { } /// Unreleased migrations. Add new ones here: - pub type Unreleased = - (pallet_staking::migrations::single_block::v15::MigrateV14ToV15,); + pub type Unreleased = (); } /// Unchecked extrinsic type as expected by this runtime. diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 0db16d5d47db..5914b2667cb8 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-27, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-06-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -52,43 +52,57 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1009` + // Measured: `1068` // Estimated: `4764` - // Minimum execution time: 40_585_000 picoseconds. - Weight::from_parts(41_800_000, 0) + // Minimum execution time: 54_643_000 picoseconds. + Weight::from_parts(55_847_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `1921` + // Measured: `2596` // Estimated: `8877` - // Minimum execution time: 81_809_000 picoseconds. - Weight::from_parts(84_387_000, 0) + // Minimum execution time: 122_367_000 picoseconds. + Weight::from_parts(125_973_000, 0) .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(8)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -100,23 +114,29 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2128` + // Measured: `2634` // Estimated: `8877` - // Minimum execution time: 89_419_000 picoseconds. - Weight::from_parts(91_237_000, 0) + // Minimum execution time: 121_036_000 picoseconds. + Weight::from_parts(123_470_000, 0) .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().reads(15)) + .saturating_add(T::DbWeight::get().writes(8)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -124,23 +144,29 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1223` + // Measured: `1342` // Estimated: `4764` - // Minimum execution time: 45_152_000 picoseconds. - Weight::from_parts(46_460_819, 0) + // Minimum execution time: 56_542_000 picoseconds. + Weight::from_parts(58_269_306, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 972 - .saturating_add(Weight::from_parts(55_473, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Standard Error: 1_008 + .saturating_add(Weight::from_parts(56_385, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -151,22 +177,28 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -174,15 +206,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2753 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 82_762_000 picoseconds. - Weight::from_parts(91_035_077, 0) + // Minimum execution time: 123_405_000 picoseconds. + Weight::from_parts(135_753_362, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_771 - .saturating_add(Weight::from_parts(1_217_871, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(11)) + // Standard Error: 5_266 + .saturating_add(Weight::from_parts(1_333_676, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(17)) + .saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -198,8 +230,14 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxValidatorsCount` (r:1 w:0) /// Proof: `Staking::MaxValidatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:0) + /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:1 w:1) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -210,42 +248,49 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1301` + // Measured: `1536` // Estimated: `4556` - // Minimum execution time: 50_555_000 picoseconds. - Weight::from_parts(52_052_000, 0) + // Minimum execution time: 73_988_000 picoseconds. + Weight::from_parts(76_337_000, 0) .saturating_add(Weight::from_parts(0, 4556)) - .saturating_add(T::DbWeight::get().reads(11)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(9)) } - /// Storage: `Staking::Ledger` (r:1 w:0) + /// Storage: `Staking::Ledger` (r:129 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:129 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:128 w:128) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:128 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:2 w:2) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:34 w:34) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1778 + k * (572 ±0)` - // Estimated: `4556 + k * (3033 ±0)` - // Minimum execution time: 35_037_000 picoseconds. - Weight::from_parts(35_081_878, 0) - .saturating_add(Weight::from_parts(0, 4556)) - // Standard Error: 5_473 - .saturating_add(Weight::from_parts(6_667_924, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) + // Measured: `3558 + k * (747 ±0)` + // Estimated: `33341 + k * (3566 ±0)` + // Minimum execution time: 95_021_000 picoseconds. + Weight::from_parts(123_030_564, 0) + .saturating_add(Weight::from_parts(0, 33341)) + // Standard Error: 35_124 + .saturating_add(Weight::from_parts(36_381_254, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(17)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(k.into()))) + .saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 3033).saturating_mul(k.into())) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(k.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1 w:0) + /// Storage: `Staking::Bonded` (r:17 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::MinNominatorBond` (r:1 w:0) /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1 w:1) + /// Storage: `Staking::Nominators` (r:17 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::MaxNominatorsCount` (r:1 w:0) /// Proof: `Staking::MaxNominatorsCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -253,28 +298,33 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForNominators` (r:1 w:1) - /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:16 w:16) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1797 + n * (102 ±0)` - // Estimated: `6248 + n * (2520 ±0)` - // Minimum execution time: 62_098_000 picoseconds. - Weight::from_parts(60_154_061, 0) + // Measured: `2281 + n * (348 ±0)` + // Estimated: `6248 + n * (3033 ±0)` + // Minimum execution time: 105_592_000 picoseconds. + Weight::from_parts(81_899_502, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 19_257 - .saturating_add(Weight::from_parts(3_839_855, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(n.into())) + // Standard Error: 35_783 + .saturating_add(Weight::from_parts(32_338_384, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(8)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -286,6 +336,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -294,13 +348,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `1747` + // Measured: `2340` // Estimated: `6248` - // Minimum execution time: 54_993_000 picoseconds. - Weight::from_parts(56_698_000, 0) + // Minimum execution time: 88_979_000 picoseconds. + Weight::from_parts(90_225_000, 0) .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(9)) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -312,8 +366,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `4556` - // Minimum execution time: 18_100_000 picoseconds. - Weight::from_parts(18_547_000, 0) + // Minimum execution time: 18_741_000 picoseconds. + Weight::from_parts(19_262_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -328,8 +382,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `932` // Estimated: `4556` - // Minimum execution time: 23_428_000 picoseconds. - Weight::from_parts(24_080_000, 0) + // Minimum execution time: 24_413_000 picoseconds. + Weight::from_parts(25_222_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -342,8 +396,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `865` // Estimated: `8122` - // Minimum execution time: 21_159_000 picoseconds. - Weight::from_parts(21_706_000, 0) + // Minimum execution time: 21_348_000 picoseconds. + Weight::from_parts(22_182_000, 0) .saturating_add(Weight::from_parts(0, 8122)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -354,8 +408,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_910_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(1_934_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -365,8 +419,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_076_000 picoseconds. - Weight::from_parts(7_349_000, 0) + // Minimum execution time: 6_704_000 picoseconds. + Weight::from_parts(7_205_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -376,8 +430,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_067_000 picoseconds. - Weight::from_parts(7_389_000, 0) + // Minimum execution time: 6_636_000 picoseconds. + Weight::from_parts(6_955_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -387,8 +441,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_148_000 picoseconds. - Weight::from_parts(7_446_000, 0) + // Minimum execution time: 6_667_000 picoseconds. + Weight::from_parts(7_129_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -399,11 +453,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_025_000 picoseconds. - Weight::from_parts(2_229_953, 0) + // Minimum execution time: 2_039_000 picoseconds. + Weight::from_parts(2_276_512, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 67 - .saturating_add(Weight::from_parts(11_785, 0).saturating_mul(v.into())) + // Standard Error: 75 + .saturating_add(Weight::from_parts(12_036, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1502 w:1502) @@ -417,11 +471,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `680 + i * (227 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 4_321_000 picoseconds. - Weight::from_parts(4_407_000, 0) + // Minimum execution time: 4_163_000 picoseconds. + Weight::from_parts(4_245_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 37_239 - .saturating_add(Weight::from_parts(21_300_598, 0).saturating_mul(i.into())) + // Standard Error: 37_120 + .saturating_add(Weight::from_parts(21_925_265, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -430,26 +484,32 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1 w:1) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:1 w:1) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -457,15 +517,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2753 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 78_908_000 picoseconds. - Weight::from_parts(84_886_373, 0) + // Minimum execution time: 120_134_000 picoseconds. + Weight::from_parts(131_611_869, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_376 - .saturating_add(Weight::from_parts(1_217_850, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(13)) - .saturating_add(T::DbWeight::get().writes(12)) + // Standard Error: 5_038 + .saturating_add(Weight::from_parts(1_335_951, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(17)) + .saturating_add(T::DbWeight::get().writes(16)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -476,11 +536,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `66639` // Estimated: `70104` - // Minimum execution time: 136_389_000 picoseconds. - Weight::from_parts(1_207_241_524, 0) + // Minimum execution time: 125_461_000 picoseconds. + Weight::from_parts(927_976_913, 0) .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 77_138 - .saturating_add(Weight::from_parts(6_443_948, 0).saturating_mul(s.into())) + // Standard Error: 57_690 + .saturating_add(Weight::from_parts(4_831_497, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -498,83 +558,111 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::ErasValidatorReward` (r:1 w:0) /// Proof: `Staking::ErasValidatorReward` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) + /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::VirtualStakers` (r:65 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:65 w:65) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:65 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:65 w:65) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStakersPaged` (r:1 w:0) - /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasRewardPoints` (r:1 w:0) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::ErasValidatorPrefs` (r:1 w:0) /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:65 w:0) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:65 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:65 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:8 w:8) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:65 w:65) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:3 w:3) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8249 + n * (396 ±0)` - // Estimated: `10779 + n * (3774 ±0)` - // Minimum execution time: 130_222_000 picoseconds. - Weight::from_parts(167_236_150, 0) - .saturating_add(Weight::from_parts(0, 10779)) - // Standard Error: 34_051 - .saturating_add(Weight::from_parts(39_899_917, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(14)) - .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) + // Measured: `8999 + n * (645 ±0)` + // Estimated: `17769 + n * (3774 ±3)` + // Minimum execution time: 210_946_000 picoseconds. + Weight::from_parts(255_089_468, 0) + .saturating_add(Weight::from_parts(0, 17769)) + // Standard Error: 45_994 + .saturating_add(Weight::from_parts(89_944_022, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(28)) + .saturating_add(T::DbWeight::get().reads((10_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1922 + l * (5 ±0)` + // Measured: `2597 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 79_136_000 picoseconds. - Weight::from_parts(82_129_497, 0) + // Minimum execution time: 119_360_000 picoseconds. + Weight::from_parts(123_258_796, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 3_867 - .saturating_add(Weight::from_parts(75_156, 0).saturating_mul(l.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) + // Standard Error: 4_980 + .saturating_add(Weight::from_parts(83_927, 0).saturating_mul(l.into())) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(8)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:1) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::SlashingSpans` (r:1 w:1) /// Proof: `Staking::SlashingSpans` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Balances::Locks` (r:1 w:1) - /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) - /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:1) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::CounterForNominators` (r:1 w:1) /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:1) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Payee` (r:0 w:1) /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Staking::SpanSlash` (r:0 w:100) @@ -582,15 +670,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2127 + s * (4 ±0)` + // Measured: `2753 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 89_375_000 picoseconds. - Weight::from_parts(91_224_907, 0) + // Minimum execution time: 134_590_000 picoseconds. + Weight::from_parts(137_403_871, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 3_424 - .saturating_add(Weight::from_parts(1_219_542, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(11)) + // Standard Error: 4_133 + .saturating_add(Weight::from_parts(1_322_316, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 4).saturating_mul(s.into())) } @@ -600,16 +688,20 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:110 w:0) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:110 w:0) + /// Storage: `Staking::Bonded` (r:111 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:110 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:110 w:0) + /// Storage: `Staking::Nominators` (r:111 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:11 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:11 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `Staking::ValidatorCount` (r:1 w:0) /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Staking::MinimumValidatorCount` (r:1 w:0) @@ -632,17 +724,17 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[0, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + n * (716 ±0) + v * (3594 ±0)` - // Estimated: `456136 + n * (3566 ±4) + v * (3566 ±0)` - // Minimum execution time: 520_905_000 picoseconds. - Weight::from_parts(523_771_000, 0) - .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 2_142_714 - .saturating_add(Weight::from_parts(68_631_588, 0).saturating_mul(v.into())) - // Standard Error: 213_509 - .saturating_add(Weight::from_parts(19_343_025, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(184)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) + // Measured: `0 + n * (716 ±0) + v * (3772 ±0)` + // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` + // Minimum execution time: 869_142_000 picoseconds. + Weight::from_parts(874_703_000, 0) + .saturating_add(Weight::from_parts(0, 516555)) + // Standard Error: 1_916_556 + .saturating_add(Weight::from_parts(60_523_432, 0).saturating_mul(v.into())) + // Standard Error: 190_974 + .saturating_add(Weight::from_parts(18_981_553, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(388)) + .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(8)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(v.into()))) @@ -669,15 +761,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3108 + n * (907 ±0) + v * (391 ±0)` + // Measured: `3142 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 36_848_619_000 picoseconds. - Weight::from_parts(37_362_442_000, 0) + // Minimum execution time: 36_931_542_000 picoseconds. + Weight::from_parts(37_274_119_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 415_031 - .saturating_add(Weight::from_parts(5_204_987, 0).saturating_mul(v.into())) - // Standard Error: 415_031 - .saturating_add(Weight::from_parts(4_132_636, 0).saturating_mul(n.into())) + // Standard Error: 377_146 + .saturating_add(Weight::from_parts(3_948_980, 0).saturating_mul(v.into())) + // Standard Error: 377_146 + .saturating_add(Weight::from_parts(4_835_554, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -685,23 +777,31 @@ impl pallet_staking::WeightInfo for WeightInfo { .saturating_add(Weight::from_parts(0, 3566).saturating_mul(n.into())) .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) } - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:0) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:201 w:0) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1001 w:0) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1001 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1001 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1001 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `946 + v * (50 ±0)` - // Estimated: `3510 + v * (2520 ±0)` - // Minimum execution time: 2_512_817_000 picoseconds. - Weight::from_parts(119_401_374, 0) - .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 8_463 - .saturating_add(Weight::from_parts(4_860_364, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(v.into())) + // Measured: `58105 + v * (323 ±0)` + // Estimated: `516555 + v * (3033 ±0)` + // Minimum execution time: 9_187_779_000 picoseconds. + Weight::from_parts(9_238_084_000, 0) + .saturating_add(Weight::from_parts(0, 516555)) + // Standard Error: 111_859 + .saturating_add(Weight::from_parts(7_084_998, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(206)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) + .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) } /// Storage: `Staking::MinCommission` (r:0 w:1) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -721,8 +821,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_686_000 picoseconds. - Weight::from_parts(3_881_000, 0) + // Minimum execution time: 3_607_000 picoseconds. + Weight::from_parts(3_819_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -744,8 +844,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_143_000 picoseconds. - Weight::from_parts(3_424_000, 0) + // Minimum execution time: 3_221_000 picoseconds. + Weight::from_parts(3_406_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -765,6 +865,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:2 w:2) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:2 w:2) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:1 w:1) @@ -773,13 +877,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `1870` + // Measured: `2455` // Estimated: `6248` - // Minimum execution time: 66_946_000 picoseconds. - Weight::from_parts(69_382_000, 0) + // Minimum execution time: 99_926_000 picoseconds. + Weight::from_parts(102_789_000, 0) .saturating_add(Weight::from_parts(0, 6248)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(15)) + .saturating_add(T::DbWeight::get().writes(9)) } /// Storage: `Staking::MinCommission` (r:1 w:0) /// Proof: `Staking::MinCommission` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -789,8 +893,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `658` // Estimated: `3510` - // Minimum execution time: 11_278_000 picoseconds. - Weight::from_parts(11_603_000, 0) + // Minimum execution time: 11_542_000 picoseconds. + Weight::from_parts(11_866_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -801,11 +905,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_963_000 picoseconds. - Weight::from_parts(2_077_000, 0) + // Minimum execution time: 1_860_000 picoseconds. + Weight::from_parts(1_982_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Staking::VirtualStakers` (r:1 w:0) + /// Proof: `Staking::VirtualStakers` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) @@ -816,23 +922,70 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { // Proof Size summary in bytes: - // Measured: `1014` + // Measured: `1099` // Estimated: `4764` - // Minimum execution time: 40_258_000 picoseconds. - Weight::from_parts(41_210_000, 0) + // Minimum execution time: 53_417_000 picoseconds. + Weight::from_parts(54_329_000, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } - - // TODO: run CI bot benchmarks + /// Storage: `Staking::Bonded` (r:3 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:2 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:2 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:1 w:1) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { - Weight::default() + // Proof Size summary in bytes: + // Measured: `1758` + // Estimated: `8631` + // Minimum execution time: 84_706_000 picoseconds. + Weight::from_parts(86_977_000, 0) + .saturating_add(Weight::from_parts(0, 8631)) + .saturating_add(T::DbWeight::get().reads(13)) + .saturating_add(T::DbWeight::get().writes(4)) } - + /// Storage: `Staking::Nominators` (r:84 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:83 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:21 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1006 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1000 w:78) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListBags` (r:4 w:4) + /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) + /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) + /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn v13_mmb_step() -> Weight { - Weight::default() + // Proof Size summary in bytes: + // Measured: `167489` + // Estimated: `2645990` + // Minimum execution time: 10_465_670_000 picoseconds. + Weight::from_parts(10_570_173_000, 0) + .saturating_add(Weight::from_parts(0, 2645990)) + .saturating_add(T::DbWeight::get().reads(2199)) + .saturating_add(T::DbWeight::get().writes(83)) } } diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f5385403c0e3..7c6c29f2614a 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -704,7 +704,7 @@ impl pallet_staking::Config for Runtime { } parameter_types! { - pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; + pub const VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; } impl pallet_stake_tracker::Config for Runtime { diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 50c266d4dba8..3bdd9be17bdf 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -263,7 +263,7 @@ impl pallet_bags_list::Config for Runtime { } parameter_types! { - pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Strict; + pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Lazy; } impl pallet_stake_tracker::Config for Runtime { diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index 63774dc18dcf..ec19f4303f9f 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -31,6 +31,7 @@ pallet-session = { path = "../session", default-features = false, features = [ "historical", ] } pallet-authorship = { path = "../authorship", default-features = false } +pallet-stake-tracker = { path = "./stake-tracker", default-features = false } sp-application-crypto = { path = "../../primitives/application-crypto", default-features = false, features = ["serde"] } frame-election-provider-support = { path = "../election-provider-support", default-features = false } log = { workspace = true } @@ -45,9 +46,8 @@ sp-tracing = { path = "../../primitives/tracing" } sp-core = { path = "../../primitives/core" } sp-npos-elections = { path = "../../primitives/npos-elections" } pallet-timestamp = { path = "../timestamp" } -pallet-stake-tracker = { path = "./stake-tracker" } pallet-staking-reward-curve = { path = "reward-curve" } -pallet-bags-list = { path = "../bags-list" } +pallet-bags-list = { path = "../bags-list", default-features = false, features = ["try-runtime"] } pallet-migrations = { path = "../migrations" } substrate-test-utils = { path = "../../test-utils" } frame-benchmarking = { path = "../benchmarking" } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 0aca10f20a25..c619b5f94959 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1145,7 +1145,7 @@ mod benchmarks { assert_eq!( Staking::::status(&voter), - Ok(StakerStatus::Nominator(vec![dangling_target.clone(), other_target.clone()])) + Ok(StakerStatus::Nominator(vec![other_target.clone(), dangling_target.clone()])) ); #[extrinsic_call] @@ -1214,7 +1214,7 @@ mod benchmarks { impl_benchmark_test_suite!( Staking, - crate::mock::ExtBuilder::default().has_stakers(true).set_voter_list_lazy(), + crate::mock::ExtBuilder::default().has_stakers(true), crate::mock::Test, exec_name = build_and_execute ); @@ -1228,7 +1228,7 @@ mod tests { #[test] fn create_validators_with_nominators_for_era_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { let v = 10; let n = 100; @@ -1254,7 +1254,7 @@ mod tests { #[test] fn create_validator_with_nominators_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { let n = 10; let (validator_stash, nominators) = create_validator_with_nominators::( @@ -1285,7 +1285,7 @@ mod tests { #[test] fn add_slashing_spans_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { let n = 10; let (validator_stash, _nominators) = create_validator_with_nominators::( @@ -1315,28 +1315,4 @@ mod tests { } }); } - - // TODO: SelectedBenchmark not exposed by v2? - /* - #[test] - fn test_payout_all() { - ExtBuilder::default().build_and_execute(|| { - let v = 10; - let n = 100; - - let selected_benchmark = SelectedBenchmark::payout_all; - let c = vec![ - (frame_benchmarking::BenchmarkParameter::v, v), - (frame_benchmarking::BenchmarkParameter::n, n), - ]; - - assert_ok!( - >::unit_test_instance( - &selected_benchmark, - &c, - ) - ); - }); - } - */ } diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 02ef5cd5da88..097e8f4a468f 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -20,35 +20,72 @@ //! sorted list of targets with a bags-list. use super::PALLET_MIGRATIONS_ID; -use crate::{log, weights, Config, Nominators, Pallet}; +use crate::{log, weights, Config, Nominations, Nominators, Pallet, StakerStatus, Validators}; +use codec::{Decode, Encode, MaxEncodedLen}; use core::marker::PhantomData; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{SortedListProvider, VoteWeight}; use frame_support::{ + ensure, migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, - traits::Defensive, + traits::{Defensive, DefensiveSaturating}, }; -use sp_runtime::traits::CheckedAdd; +use scale_info::TypeInfo; use sp_staking::StakingInterface; use sp_std::prelude::*; #[cfg(test)] mod tests; +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, PartialEq, Debug, Clone)] +pub enum Processing { + Nominators, + Validators, + Done, +} +impl Default for Processing { + fn default() -> Self { + Processing::Nominators + } +} + /// V13 Multi-block migration to introduce the stake-tracker pallet. /// -/// A step of the migration consists of processing one nominator in the [`Nominators`] list. All -/// nominatior's target nominations are processed per step (bound by upper bound of the max -/// nominations). +/// A step of the migration consists of processing one nominator in the [`Nominators`] list or one +/// validators in the [`Validators`] list, depending on the cursor's state. +/// +/// The migration has two phases: +/// * [`Processing::Nominators`]: iterates over the nominators list and updates the approvals stake +/// of the nominated targets associated with each of the nominators. +/// * [`Processing::Validators`]: iterates over the validators list and, if the validator does not +/// exist in the target list, add it with self-stake as score. +/// +/// First, the migration processes all the nominators and then the validators. When a validator is +/// added to the target list during the [`Processing::Validators`], it indicates that the validator +/// has no nominations. /// /// The goals of the migration are: -/// - Insert all the nominated targets into the [`SortedListProvider`] target list. -/// - Ensure the target score (total stake) is the sum of the self stake and all its nominations +/// * Insert all the nominated targets into the [`SortedListProvider`] target list. +/// * Ensure the target score (total stake) is the sum of the self stake and all its nominations /// stake. -/// - Ensure the new targets in the list are sorted per total stake (as per the underlying +/// * Ensure the new targets in the list are sorted per total stake (as per the underlying /// [`SortedListProvider`]). +/// * Ensure that there is no duplicate nominations per nominator. +/// +/// ## Potential changes to nominations state during the migration. +/// +/// When migrating a nominator, we need to ensure that the nominator is not nominating duplicate +/// targets. In addition, this migration also "cleans" the nominations by dropping all nominations +/// of targets that are not active validators. This logic is implemented by +/// [`MigrationV13::clean_nominations`]. In sum, the followinf invariants hold true after +/// processing each nominator: +/// +/// 1. A nominator has no duplicate nominations; +/// 2. A nominators is nominating only active validators; +/// 3. A nominator has at least one nomination, otherwise it is chilled. pub struct MigrationV13(PhantomData<(T, W)>); impl SteppedMigration for MigrationV13 { - type Cursor = T::AccountId; + // nominator cursor and validator cursor. + type Cursor = (Option, Processing); type Identifier = MigrationId<18>; /// Identifier of this migration which should be globally unique. @@ -67,63 +104,203 @@ impl SteppedMigration for MigrationV13 return Err(SteppedMigrationError::InsufficientWeight { required }); } - // Do as much progress as possible per step. + // do as much progress as possible per step. while meter.try_consume(required).is_ok() { - // 1. get next validator in the Validators map. - let mut iter = if let Some(ref last_nom) = cursor { - Nominators::::iter_from(Nominators::::hashed_key_for(last_nom)) - } else { - // first step, start from beginning of the validator's map. - Nominators::::iter() - }; + let new_cursor = match cursor { + None => { + // start processing first nominator. + if let Some((nominator, nominations)) = Nominators::::iter().next() { + Self::process_nominator(&nominator, nominations)?; + Some((Some(nominator), Processing::Nominators)) + } else { + Some((None, Processing::Validators)) + } + }, + Some((maybe_nominator, Processing::Nominators)) => { + let mut iter = if let Some(last_nominator) = maybe_nominator { + Nominators::::iter_from(Nominators::::hashed_key_for(last_nominator)) + } else { + Nominators::::iter() + }; - if let Some((nominator, _)) = iter.next() { - let nominator_stake = - Pallet::::stake(&nominator).defensive_unwrap_or_default().total; - let nominations = Nominators::::get(&nominator) - .map(|n| n.targets.into_inner()) - .unwrap_or_default(); - - log!( - info, - "multi-block migrations: processing nominator {:?} with {} nominations. remaining {} nominators to migrate.", - nominator, - nominations.len(), - iter.count() - ); - - // iter over up to `MaxNominationsOf` targets of `nominator`. - for target in nominations.into_iter() { - if let Ok(current_stake) = T::TargetList::get_score(&target) { - // target is not in the target list. update with nominator's stake. - - if let Some(total_stake) = current_stake.checked_add(&nominator_stake) { - let _ = T::TargetList::on_update(&target, total_stake).defensive(); - } else { - log!(error, "target stake overflow. exit."); - return Err(SteppedMigrationError::Failed) - } + if let Some((nominator, nominations)) = iter.next() { + Self::process_nominator(&nominator, nominations)?; + Some((Some(nominator), Processing::Nominators)) } else { - // target is not in the target list, insert new node and consider self - // stake. - let self_stake = Pallet::::stake(&target).defensive_unwrap_or_default(); - if let Some(total_stake) = self_stake.total.checked_add(&nominator_stake) { - let _ = T::TargetList::on_insert(target, total_stake).defensive(); - } else { - log!(error, "target stake overflow. exit."); - return Err(SteppedMigrationError::Failed) - } + // no more nominators to process, go to next phase. + Some((None, Processing::Validators)) } - } + }, + Some((maybe_validator, Processing::Validators)) => { + // process validator. + let mut iter = if let Some(last_validator) = maybe_validator { + Validators::::iter_from(Validators::::hashed_key_for(last_validator)) + } else { + Validators::::iter() + }; - // progress cursor. - cursor = Some(nominator) - } else { - // done, return earlier. + // nominators have been all processed, start processing validators. + if let Some((validator, _)) = iter.next() { + Self::process_validator(&validator); + Some((Some(validator), Processing::Validators)) + } else { + Some((None, Processing::Done)) + } + }, + Some((_, Processing::Done)) => Some((None, Processing::Done)), + }; + + // progress or terminate. + if new_cursor.clone().unwrap_or_default().1 == Processing::Done { return Ok(None) + } else { + cursor = new_cursor; } } Ok(cursor) } } + +impl MigrationV13 { + fn process_nominator( + nominator: &T::AccountId, + nominations: Nominations, + ) -> Result<(), SteppedMigrationError> { + let nominator_vote = Pallet::::weight_of(nominator); + // clean the nominations before migrating. This will ensure that the voter is not + // nominating duplicate and/or dangling targets. + let nominations = Self::clean_nominations(nominator, nominations)?; + + // iter over up to `MaxNominationsOf` targets of `nominator` and insert or + // update the target's approval's score. + for target in nominations.into_iter() { + if ::TargetList::contains(&target) { + Self::update_target(&target, nominator_vote)?; + } else { + Self::insert_target(&target, nominator_vote)?; + } + } + Ok(()) + } + + fn process_validator(validator: &T::AccountId) { + if !::TargetList::contains(validator) && + as StakingInterface>::status(validator) == Ok(StakerStatus::Validator) + { + let self_stake = Pallet::::weight_of(validator); + ::TargetList::on_insert(validator.clone(), self_stake.into()) + .expect("node does not exist, checked above; qed."); + } + } + + /// Inserts a new target in the list. + /// + /// Note: the caller must ensure that the target node does not exist in the list yet. + /// Oterhwise, use [`Self::update_target`]. + fn insert_target( + who: &T::AccountId, + nomination_stake: VoteWeight, + ) -> Result<(), SteppedMigrationError> { + let init_stake = match as StakingInterface>::status(&who) { + Ok(StakerStatus::Validator) => { + let self_stake = Pallet::::weight_of(&who); + let total_stake = self_stake.defensive_saturating_add(nomination_stake); + total_stake + }, + _ => nomination_stake, + }; + + match ::TargetList::on_insert(who.clone(), init_stake.into()) { + Err(e) => { + log!(error, "inserting {:?} in TL: {:?}", who, e); + Err(SteppedMigrationError::Failed) + }, + Ok(_) => Ok(()), + } + } + + /// Updates the target score in the target list. + /// + /// Note: the caller must ensure that the target node already exists in the list. Otherwise, + /// use [`Self::insert_target`]. + fn update_target( + who: &T::AccountId, + nomination_stake: VoteWeight, + ) -> Result<(), SteppedMigrationError> { + let current_stake = + ::TargetList::get_score(&who).expect("node is in the list"); + + let total_stake = current_stake.defensive_saturating_add(nomination_stake.into()); + let _ = ::TargetList::on_update(&who, total_stake.into()).map_err(|e| { + log!(error, "updating TL score of {:?}: {:?}", who, e); + SteppedMigrationError::Failed + })?; + + Ok(()) + } + + /// Cleans up the nominations of `who`. + /// + /// After calling this method, the following invariants are respected: + /// - `stash` has no duplicate nominations; + /// - `stash` has no dangling nominations (i.e. nomination of non-active validator stashes). + /// + /// If the clean set of nominations is empty, `who` is chilled. + /// + /// When successful, the final nominations of the stash are returned. + pub(crate) fn clean_nominations( + who: &T::AccountId, + raw_nominations: Nominations, + ) -> Result, SteppedMigrationError> { + use sp_std::collections::btree_set::BTreeSet; + + ensure!( + Pallet::::status(who).map(|x| x.is_nominator()).unwrap_or(false), + SteppedMigrationError::Failed + ); + + let mut raw_targets = raw_nominations.targets.into_inner(); + let count_before = raw_targets.len(); + + // remove duplicate nominations. + let dedup_noms: Vec = + raw_targets.drain(..).collect::>().into_iter().collect::>(); + + // remove all non-validator nominations. + let targets = dedup_noms + .into_iter() + .filter(|n| Pallet::::status(n) == Ok(StakerStatus::Validator)) + .collect::>(); + + if targets.len() == 0 { + // if no nominations are left, chill the nominator. + let _ = as StakingInterface>::chill(&who) + .map_err(|e| { + log!(error, "error when chilling {:?}", who); + e + }) + .defensive(); + } else if count_before > targets.len() { + // force update the nominations. + let bounded_targets = targets + .clone() + .into_iter() + .collect::>() + .try_into() + .expect( + "new bound should be within the existent set of targets, thus it should fit; qed.", + ); + + let nominations = Nominations { + targets: bounded_targets, + submitted_in: raw_nominations.submitted_in, + suppressed: raw_nominations.suppressed, + }; + + >::do_add_nominator(who, nominations); + } + + Ok(targets) + } +} diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index c853d4795fea..3747c1ecdf0a 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -21,12 +21,11 @@ use crate::{ bond_nominator, bond_validator, run_to_block, AllPalletsWithSystem, ExtBuilder, MigratorServiceWeight, Staking, System, TargetBagsList, Test as T, }, - testing_utils, weights::{SubstrateWeight, WeightInfo as _}, Nominators, }; use frame_election_provider_support::SortedListProvider; -use frame_support::{assert_ok, traits::OnRuntimeUpgrade}; +use frame_support::traits::OnRuntimeUpgrade; use pallet_migrations::WeightInfo as _; #[test] @@ -135,54 +134,8 @@ fn mb_migration_target_list_dangling_validators_works() { } #[test] -fn mb_migration_target_list_single_step_bench_works() { - ExtBuilder::default() - .has_stakers(false) - .max_winners(1000) - // skip checks as not all the steps are applied. - .stake_tracker_try_state(false) - .build_and_execute(|| { - // setup: - // 1000 validators; - // 5 nominators; - // 16 nominations. - let _ = testing_utils::create_validators_with_nominators_for_era::( - 1000, 5, 16, true, None, - ); - assert_eq!(TargetBagsList::count(), 1000); - - // drop targets from target list nominated by the one nominator to be migrated. - let (_to_migrate, mut nominations) = Nominators::::iter() - .map(|(n, noms)| (n, noms.targets.into_inner())) - .next() - .unwrap(); - - // remove duplicates. - nominations.sort(); - nominations.dedup(); - - for t in nominations.iter() { - assert_ok!(TargetBagsList::on_remove(&t)); - } - - // targets nominated by first nominator will be dropped from the target list. - assert_eq!(TargetBagsList::count(), 1000 - nominations.len() as u32); - assert!(Staking::do_try_state(System::block_number()).is_err()); - - // allocate 1 step per block. - let limit = ::WeightInfo::progress_mbms_none() + - pallet_migrations::Pallet::::exec_migration_max_weight() + - SubstrateWeight::::v13_mmb_step(); - MigratorServiceWeight::set(&limit); - - AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs - - // migrate first nominator, which will add back all the targets to the target list. - run_to_block(2); - - // migration done, try state checks pass. - assert_eq!(TargetBagsList::count(), 1000); - Staking::do_try_state(System::block_number()).unwrap(); - assert!(Staking::do_try_state(System::block_number()).is_ok()); - }) +fn mb_migration_target_list_duplicate_validators_works() { + ExtBuilder::default().has_stakers(false).build_and_execute(|| { + // TODO + }) } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 7177ac1abdee..50249c692ab5 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -363,7 +363,7 @@ impl OnStakingUpdate for EventTracker { } parameter_types! { - pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Strict; + pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; } impl pallet_stake_tracker::Config for Test { @@ -450,8 +450,6 @@ pub(crate) type TestCall = ::RuntimeCall; parameter_types! { // if true, skips the try-state for the test running. pub static SkipTryStateCheck: bool = false; - // if true, skips the stake-tracker try-state for the tests running. - pub static SkipStakeTrackerTryStateCheck: bool = false; } pub struct ExtBuilder { @@ -567,12 +565,8 @@ impl ExtBuilder { SkipTryStateCheck::set(!enable); self } - pub fn stake_tracker_try_state(self, enable: bool) -> Self { - SkipStakeTrackerTryStateCheck::set(!enable); - self - } - pub fn set_voter_list_lazy(self) -> Self { - VoterUpdateMode::set(pallet_stake_tracker::VoterUpdateMode::Lazy); + pub fn set_voter_list_strict(self) -> Self { + VoterUpdateMode::set(pallet_stake_tracker::VoterUpdateMode::Strict); self } pub fn max_winners(self, max: u32) -> Self { @@ -721,18 +715,6 @@ impl ExtBuilder { }) .unwrap(); } - - // run the stake tracker try state checks too to leverage the test coverage of the - // staking pallet tests. - #[cfg(feature = "try-runtime")] - if !SkipStakeTrackerTryStateCheck::get() { - StakeTracker::do_try_state() - .map_err(|err| { - println!(" 🕵️‍♂️ StakeTracker try_state failure: {:?}", err); - err - }) - .unwrap() - } }); } } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d936503e1aa2..81a3c9c4a46a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -411,6 +411,44 @@ impl Pallet { } } + /// Removes dangling nominations from a nominator. + /// + /// If `maybe_target` is `None`, search for *all* dangling nominations and drop them. Otherwise + /// drop only one dangling target. + /// + /// IMPORTANT NOTE: if `maybe_target` is set, it is assumed that the target is indeed dangling. + /// No further checks are performed in this method. + pub(crate) fn do_drop_dangling_nominations( + nominator: &T::AccountId, + target: Option<&T::AccountId>, + ) -> Result>, DispatchError> { + let nominations_after = match (target, Self::status(&nominator)) { + (None, Ok(StakerStatus::Nominator(nominations))) => { + // target not set, filter out all non-validator nominations. + nominations + .into_iter() + .filter(|n| Self::status(n) == Ok(StakerStatus::Validator)) + .collect::>() + }, + (Some(target), Ok(StakerStatus::Nominator(nominations))) => { + debug_assert!(Self::status(&target).is_err() && T::TargetList::contains(&target),); + + nominations.iter().cloned().filter(|n| n != target).collect::>() + }, + // not a nominator, return earlier. + (_, _) => return Err(Error::::NotNominator.into()), + }; + + // no dangling nominations, return earlier. + if nominations_after.len().is_zero() { + return Err(Error::::NotDanglingTarget.into()); + } + + ::nominate(nominator, nominations_after.clone())?; // TODO remove clone? + + Ok(BoundedVec::truncate_from(nominations_after)) + } + /// Actually make a payment to a staker. This uses the currency's reward function /// to pay the right payee for the given staker account. fn make_payout( @@ -2064,7 +2102,7 @@ impl sp_staking::StakingUnchecked for Pallet { #[cfg(any(test, feature = "try-runtime"))] impl Pallet { - pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { + pub fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { ensure!( T::VoterList::iter().all(|x| >::contains_key(&x) || >::contains_key(&x) || @@ -2079,7 +2117,9 @@ impl Pallet { Self::check_exposures()?; Self::check_paged_exposures()?; Self::check_count()?; - Self::ensure_disabled_validators_sorted() + Self::ensure_disabled_validators_sorted()?; + Self::do_try_state_approvals()?; + Self::do_try_state_target_sorting() } /// Invariants: @@ -2404,4 +2444,147 @@ impl Pallet { ); Ok(()) } + + /// Stake-tracker: checks if the approvals stake of the targets in the target list are correct. + /// + /// These try-state checks generate a map with approval stake of all the targets based on + /// the staking state of stakers in the voter and target lists. In doing so, we are able to + /// verify that the current voter and target lists and scores are in sync with the staking + /// data and perform other sanity checks as the approvals map is calculated. + /// + /// NOTE: this is an expensive state check since it iterates over all the nodes in the + /// target and voter list providers. + /// + /// Invariants: + /// + /// * Target List: + /// * The sum of the calculated approvals stake is the same as the current approvals in + /// the target list per target. + /// * The target score of an active validator is the sum of all of its nominators' stake + /// and the self-stake; + /// * The target score of an idle validator (i.e. chilled) is the sum of its nominator's + /// stake. An idle target may not be part of the target list, if it has no nominations. + /// * The target score of a "dangling" target (ie. idle AND unbonded validator) must + /// always be > 0. We expect the stake-tracker to have cleaned up dangling targets with 0 + /// score. + /// * The number of target nodes in the target list matches the number of + /// (active_validators + idle_validators + dangling_targets_score_with_score). + pub fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { + use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; + let mut approvals_map: BTreeMap = BTreeMap::new(); + + // build map of approvals stakes from the `Nominators` storage map POV. + for (voter, nominations) in Nominators::::iter() { + let vote = Self::weight_of(&voter); + let nominations = nominations.targets; + + // fail if nominator has duplicate nominations, unexpected in the context of + // keeping track of the stake approvals. + let count_before = nominations.len(); + let dedup_noms: Vec = nominations + .clone() + .drain(..) + .collect::>() + .into_iter() + .collect::>(); + + ensure!( + count_before == dedup_noms.len(), + "nominator has duplicate nominations, unexpected." + ); + + for target in nominations.into_iter() { + if let Some(approvals) = approvals_map.get_mut(&target) { + *approvals += vote.into(); + } else { + // new addition to the map. add self-stake if validator is active. + let _ = match Self::status(&target) { + Ok(StakerStatus::Validator) => { + let self_stake = Pallet::::weight_of(&target); + approvals_map.insert(target, vote.saturating_add(self_stake).into()) + }, + _ => approvals_map.insert(target, vote.into()), + }; + } + } + } + + // add active validators without any nominations. + for (validator, _) in Validators::::iter() { + // do not add validator if it is not in a good state. + match Self::inspect_bond_state(&validator) { + Ok(LedgerIntegrityState::Ok) | Err(_) => (), + _ => continue, + } + + if !approvals_map.contains_key(&validator) { + // skip if for some reason there is a nominator being nominated. + match Self::status(&validator) { + Ok(StakerStatus::Nominator(_)) => { + log!( + warn, + "nominated staker {:?} is a nominator, not a validator.", + validator + ); + }, + _ => { + let self_stake = Pallet::::weight_of(&validator); + approvals_map.insert(validator, self_stake.into()); + }, + } + } + } + + let mut mismatch_approvals = 0; + + // compare calculated approvals per target with target list state. + for (target, calculated_stake) in approvals_map.iter() { + let stake_in_list = T::TargetList::get_score(target).unwrap(); + + if *calculated_stake != stake_in_list { + mismatch_approvals += 1; + + log!( + error, + "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?} -- weight self-stake: {:?}", + target, + stake_in_list, + calculated_stake, + Pallet::::weight_of(&target), + ); + } + } + + frame_support::ensure!( + approvals_map.keys().count() == T::TargetList::iter().count(), + "calculated approvals count is different from total of target list.", + ); + + if !mismatch_approvals.is_zero() { + log!(error, "{} targets with unexpected score in list", mismatch_approvals); + return Err("final calculated approvals != target list scores".into()); + } + + Ok(()) + } + + /// Try-state: checks if targets in the target list are sorted by score. + /// + /// Invariant + /// * All targets in the target list are sorted by their score (approvals). + /// + /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if + /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we + /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the + /// correct position in the list (bag or otherwise), given its score. + pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { + for t in T::TargetList::iter() { + frame_support::ensure!( + T::TargetList::in_position(&t).expect("target exists"), + "target list is not sorted" + ); + } + + Ok(()) + } } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 979af80b238b..401829472985 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -37,11 +37,11 @@ use sp_runtime::{ }; use sp_staking::{ - EraIndex, OnStakingUpdate, Page, SessionIndex, StakerStatus, + EraIndex, OnStakingUpdate, Page, SessionIndex, StakingAccount::{self, Controller, Stash}, StakingInterface, }; -use sp_std::prelude::*; +use sp_std::{collections::btree_set::BTreeSet, prelude::*}; mod impls; @@ -51,7 +51,7 @@ use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, DisablingStrategy, EraPayout, EraRewardPoints, Exposure, ExposurePage, Forcing, LedgerIntegrityState, MaxNominationsOf, NegativeImbalanceOf, Nominations, NominationsQuota, PositiveImbalanceOf, - RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + RewardDestination, SessionInterface, StakerStatus, StakingLedger, UnappliedSlash, UnlockChunk, ValidatorPrefs, }; @@ -795,8 +795,8 @@ pub mod pallet { ForceEra { mode: Forcing }, /// Report of a controller batch deprecation. ControllerBatchDeprecated { failures: u32 }, - /// A dangling nomination has been successfully dropped. - DanglingNominationDropped { nominator: T::AccountId, target: T::AccountId }, + /// A set of dangling nominations have been successfully dropped. + DanglingNominationsDropped { nominator: T::AccountId, count: u32 }, } #[pallet::error] @@ -1231,9 +1231,15 @@ pub mod pallet { .map(|t| T::Lookup::lookup(t).map_err(DispatchError::from)) .map(|n| { n.and_then(|n| { - // a good target nomination must be a valiator (active or idle). The - // validator must not be blocked. - if Self::status(&n).is_ok() && + // a good target nomination must be an active validator or a Idle staker. + // The validator must not be blocked. + let validator_or_idle = Self::status(&n) + .map(|status| { + status == StakerStatus::Validator || status == StakerStatus::Idle + }) + .unwrap_or(false); + + if validator_or_idle && (old.contains(&n) || !Validators::::get(&n).blocked) { Ok(n) @@ -1243,6 +1249,11 @@ pub mod pallet { }) }) .collect::, _>>()? + // remove duplicate nominations. + .drain(..) + .collect::>() + .into_iter() + .collect::>() .try_into() .map_err(|_| Error::::TooManyNominators)?; @@ -2096,7 +2107,7 @@ pub mod pallet { Ok(()) } - /// Removes nomination from a chilled and unbonded target. + /// Removes nomination of a non-active validator. /// /// In the case that an unboded target still has nominations lingering, the approvals stake /// for the "dangling" target needs to remain in the target list. This extrinsic allows @@ -2121,28 +2132,16 @@ pub mod pallet { Error::::NotDanglingTarget ); - match Self::status(&nominator) { - Ok(StakerStatus::Nominator(nominations)) => { - let count_before = nominations.len(); - - let nominations_after = - nominations.into_iter().filter(|n| *n != target).collect::>(); - - if nominations_after.len() != count_before { - ::nominate(&nominator, nominations_after)?; + Self::do_drop_dangling_nominations(&nominator, Some(&target)) + .map(|_| { + Self::deposit_event(Event::::DanglingNominationsDropped { + nominator, + count: 1, + }); - Self::deposit_event(Event::::DanglingNominationDropped { - nominator, - target, - }); - - Ok(Pays::No.into()) - } else { - Ok(Pays::Yes.into()) - } - }, - _ => Err(Error::::NotNominator.into()), - } + Pays::No.into() + }) + .map_err(|err| err.into()) } } } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 9d835368fdc7..689b7e232e4b 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1291,25 +1291,19 @@ fn bond_extra_works() { #[test] fn bond_extra_controller_bad_state_works() { - ExtBuilder::default() - .try_state(false) - .stake_tracker_try_state(false) - .build_and_execute(|| { - assert_eq!(StakingLedger::::get(StakingAccount::Stash(31)).unwrap().stash, 31); + ExtBuilder::default().try_state(false).build_and_execute(|| { + assert_eq!(StakingLedger::::get(StakingAccount::Stash(31)).unwrap().stash, 31); - // simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41. - Bonded::::insert(31, 41); + // simulate ledger in bad state: the controller 41 is associated to the stash 31 and 41. + Bonded::::insert(31, 41); - // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching - // the ledger associated with the controller 41, its stash is 41 (and not 31). - assert_eq!(Ledger::::get(41).unwrap().stash, 41); + // we confirm that the ledger is in bad state: 31 has 41 as controller and when fetching + // the ledger associated with the controller 41, its stash is 41 (and not 31). + assert_eq!(Ledger::::get(41).unwrap().stash, 41); - // if the ledger is in this bad state, the `bond_extra` should fail. - assert_noop!( - Staking::bond_extra(RuntimeOrigin::signed(31), 10), - Error::::BadState - ); - }) + // if the ledger is in this bad state, the `bond_extra` should fail. + assert_noop!(Staking::bond_extra(RuntimeOrigin::signed(31), 10), Error::::BadState); + }) } #[test] @@ -1884,7 +1878,6 @@ fn reward_to_stake_works() { .set_status(41, StakerStatus::Idle) .set_stake(21, 2000) .try_state(false) - .stake_tracker_try_state(false) .build_and_execute(|| { assert_eq!(Staking::validator_count(), 2); // Confirm account 10 and 20 are validators @@ -1978,7 +1971,7 @@ fn reap_stash_works_with_existential_deposit_zero() { ExtBuilder::default() .existential_deposit(0) .balance_factor(10) - .stake_tracker_try_state(false) + .try_state(false) .build_and_execute(|| { // given assert_eq!(Balances::balance_locked(STAKING_ID, &11), 10 * 1000); @@ -2076,6 +2069,7 @@ fn switching_roles() { #[test] fn wrong_vote_errors() { ExtBuilder::default() + .nominate(true) .add_staker( 61, 61, @@ -2101,10 +2095,26 @@ fn wrong_vote_errors() { Error::::BadTarget ); - // however, nominating an `Idle` validator is OK. + // nominating a nominator fails. + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + assert_noop!( + Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 101]), + Error::::BadTarget + ); + + // nominating an `Idle` validator works. assert_eq!(Staking::status(&41), Ok(StakerStatus::Idle)); assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 31, 41])); + assert_eq!( + Staking::status(&61).unwrap(), + StakerStatus::Nominator(vec![11, 21, 31, 41]) + ); + + // nominating duplicate targets does not fail, but the final nominations list is + // deduplicated. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(61), vec![11, 21, 11, 11, 21, 21])); + assert_eq!(Staking::status(&61).unwrap(), StakerStatus::Nominator(vec![11, 21])); }); } @@ -2231,6 +2241,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { .nominate(false) .minimum_validator_count(1) .set_stake(31, 1000) + .try_state(false) .build_and_execute(|| { // ensure all have equal stake. assert_eq!( @@ -2283,6 +2294,7 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { .nominate(false) .set_stake(31, 1000) .minimum_validator_count(1) + .try_state(false) .build_and_execute(|| { // ensure all have equal stake. assert_eq!( @@ -2341,35 +2353,32 @@ fn new_era_elects_correct_number_of_validators() { #[test] fn phragmen_should_not_overflow() { - ExtBuilder::default() - .stake_tracker_try_state(false) - .nominate(false) - .build_and_execute(|| { - // This is the maximum value that we can have as the outcome of CurrencyToVote. - type Votes = u64; + ExtBuilder::default().try_state(false).nominate(false).build_and_execute(|| { + // This is the maximum value that we can have as the outcome of CurrencyToVote. + type Votes = u64; - let _ = Staking::chill(RuntimeOrigin::signed(10)); - let _ = Staking::chill(RuntimeOrigin::signed(20)); + let _ = Staking::chill(RuntimeOrigin::signed(10)); + let _ = Staking::chill(RuntimeOrigin::signed(20)); - bond_validator(3, Votes::max_value() as Balance); - bond_validator(5, Votes::max_value() as Balance); + bond_validator(3, Votes::max_value() as Balance); + bond_validator(5, Votes::max_value() as Balance); - bond_nominator(7, Votes::max_value() as Balance, vec![3, 5]); - bond_nominator(9, Votes::max_value() as Balance, vec![3, 5]); + bond_nominator(7, Votes::max_value() as Balance, vec![3, 5]); + bond_nominator(9, Votes::max_value() as Balance, vec![3, 5]); - mock::start_active_era(1); + mock::start_active_era(1); - assert_eq_uvec!(validator_controllers(), vec![3, 5]); + assert_eq_uvec!(validator_controllers(), vec![3, 5]); - // We can safely convert back to values within [u64, u128]. - assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); - assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); - }) + // We can safely convert back to values within [u64, u128]. + assert!(Staking::eras_stakers(active_era(), &3).total > Votes::max_value() as Balance); + assert!(Staking::eras_stakers(active_era(), &5).total > Votes::max_value() as Balance); + }) } #[test] fn reward_validator_slashing_validator_does_not_overflow() { - ExtBuilder::default().stake_tracker_try_state(false).build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { let stake = u64::MAX as Balance * 2; let reward_slash = u64::MAX as Balance * 2; @@ -5160,7 +5169,7 @@ mod sorted_list_provider_integration { #[test] fn nominator_bond_unbond_chill_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().set_voter_list_strict().build_and_execute(|| { Balances::make_free_balance_be(&42, 100); // initial stakers. @@ -5228,7 +5237,7 @@ mod sorted_list_provider_integration { #[test] fn validator_validate_chill_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().set_voter_list_strict().build_and_execute(|| { Balances::make_free_balance_be(&42, 100); // initial targets. @@ -5253,11 +5262,12 @@ mod sorted_list_provider_integration { assert_eq!(VoterBagsList::score(&42), 20); assert_eq!(TargetBagsList::score(&42), 20); - // stash 42 chills, thus it should be part of the target bags list but not in the voter - // list. And it is `Idle` status. + // stash 42 chills and no one nominates it, thus its score is 0 and it sis not part of + // the target bags list. In addition, it is not in the voter list. And it is `Idle` + // status. assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); assert!(!VoterBagsList::contains(&42)); - assert!(TargetBagsList::contains(&42)); + assert!(!TargetBagsList::contains(&42)); assert_eq!(Staking::status(&42), Ok(StakerStatus::Idle)); // the target score of 42 is 0, since it is chilled and it has no nominations. assert_eq!(TargetBagsList::score(&42), 0); @@ -5601,7 +5611,7 @@ mod election_data_provider { #[test] fn lazy_quota_npos_voters_works_above_quota() { ExtBuilder::default() - .stake_tracker_try_state(false) + .try_state(false) .nominate(false) .has_stakers(true) .add_staker( @@ -5634,7 +5644,7 @@ mod election_data_provider { #[test] fn nominations_quota_limits_size_work() { ExtBuilder::default() - .stake_tracker_try_state(false) + .try_state(false) .nominate(false) .has_stakers(true) .add_staker(71, 70, 333, StakerStatus::::Nominator(vec![11, 21, 31, 41])) @@ -6234,12 +6244,12 @@ fn change_of_absolute_max_nominations() { fn nomination_quota_max_changes_decoding() { use frame_election_provider_support::ElectionDataProvider; ExtBuilder::default() - .stake_tracker_try_state(false) .add_staker(60, 61, 10, StakerStatus::Nominator(vec![11])) .add_staker(70, 71, 10, StakerStatus::Nominator(vec![11, 21, 31])) .add_staker(30, 330, 10, StakerStatus::Nominator(vec![11, 21, 31, 41])) .add_staker(50, 550, 10, StakerStatus::Nominator(vec![11, 21, 31, 41])) .balance_factor(10) + .try_state(false) .build_and_execute(|| { // pre-condition. assert_eq!(MaxNominationsOf::::get(), 16); @@ -7841,10 +7851,10 @@ mod stake_tracker { assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11, 11, 11])); assert_eq!(nominators_of(&11), vec![101, 100]); - // even though the nominations of 101 have duplicate targets as 11. - assert_eq!(Nominators::::get(&101).unwrap().targets, vec![11, 11, 11]); + // however, the nominations are dedup. + assert_eq!(Nominators::::get(&101).unwrap().targets, vec![11]); // the approvals stake of 11 is self_stake + active stake of 101 and 100. duplicate - // nominations in the same voter is dedup by the stake tracker. + // nominations in the same voter are dedup. assert_eq!( TargetBagsList::score(&11), Staking::active_stake(&11).unwrap() + @@ -8255,10 +8265,10 @@ mod stake_tracker { // the chilled validator score drops to 0, since it had only self-stake before chill. assert_eq!(>::score(&11), 0); - // 11 is still part of the targets list although the score is 0, since its status is - // Idle. However, it has been removed from the nominator sand validators lists. + // since score of 11 is 0, it is removed from the target list. Since it is idle, it is + // nor part of the nominator and validator lists. assert_eq!(Staking::status(&11), Ok(StakerStatus::Idle)); - assert_eq!(voters_and_targets().1, [(21, 1000), (31, 500), (11, 0)]); + assert_eq!(voters_and_targets().1, [(21, 1000), (31, 500)]); assert!(!Nominators::::contains_key(&11)); assert!(!Validators::::contains_key(&11)); @@ -8271,8 +8281,6 @@ mod stake_tracker { assert_eq!( target_bags_events(), [ - BagsEvent::Rebagged { who: 11, from: 1000, to: 100 }, - BagsEvent::ScoreUpdated { who: 11, new_score: 0 }, BagsEvent::Rebagged { who: 11, from: 100, to: 2000 }, BagsEvent::ScoreUpdated { who: 11, new_score: 1100 }, BagsEvent::Rebagged { who: 21, from: 1000, to: 10000 }, @@ -8572,91 +8580,81 @@ mod stake_tracker { #[test] fn drop_dangling_nomination_works() { - ExtBuilder::default() - .try_state(false) - .stake_tracker_try_state(false) - .build_and_execute(|| { - // setup. - bond_validator(42, 10); + ExtBuilder::default().try_state(false).build_and_execute(|| { + // setup. + bond_validator(42, 10); - assert_ok!(Staking::bond( - RuntimeOrigin::signed(90), - 500, - RewardDestination::Staked - )); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11])); - assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(90), 500, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11])); - // target is dangling with nominations from 101 and 90. - setup_dangling_target_for_nominators(42, vec![101, 90]); + // target is dangling with nominations from 101 and 90. + setup_dangling_target_for_nominators(42, vec![101, 90]); - // 101 is now nominating 42.. - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); - // .. which is unbonded.. - assert!(Staking::status(&42).is_err()); - // .. and still part of the target list (thus dangling). - assert!(TargetBagsList::contains(&42)); + // 101 is now nominating 42.. + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + // .. which is unbonded.. + assert!(Staking::status(&42).is_err()); + // .. and still part of the target list (thus dangling). + assert!(TargetBagsList::contains(&42)); - // remove 90 as dangling nomination. - assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); + // remove 90 as dangling nomination. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); - assert_eq!( - *mock::staking_events().last().unwrap(), - Event::::DanglingNominationDropped { nominator: 90, target: 42 }.into(), - ); + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationsDropped { nominator: 90, count: 1 }.into(), + ); - // now, 90 is not nominating 42 anymore. - assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![11])); - // but 42 is still dangling because 101 is still nominating it - assert!(TargetBagsList::contains(&42)); - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); + // now, 90 is not nominating 42 anymore. + assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![11])); + // but 42 is still dangling because 101 is still nominating it + assert!(TargetBagsList::contains(&42)); + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11, 42])); - // when the last dangling nomination is removed, the danling target is removed. - assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 101, 42)); + // when the last dangling nomination is removed, the danling target is removed. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 101, 42)); - assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11])); - assert!(!TargetBagsList::contains(&42)); + assert_ok!(Staking::status(&101), StakerStatus::Nominator(vec![11])); + assert!(!TargetBagsList::contains(&42)); - assert_eq!( - *mock::staking_events().last().unwrap(), - Event::::DanglingNominationDropped { nominator: 101, target: 42 }.into(), - ); - }) + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationsDropped { nominator: 101, count: 1 }.into(), + ); + }) } #[test] fn drop_dangling_nomination_failures_work() { - ExtBuilder::default() - .try_state(false) - .stake_tracker_try_state(false) - .build_and_execute(|| { - // target is not dangling since it does not exist in the target list. - assert!(Staking::status(&42).is_err()); - assert!(!TargetBagsList::contains(&42)); + ExtBuilder::default().try_state(false).build_and_execute(|| { + // target is not dangling since it does not exist in the target list. + assert!(Staking::status(&42).is_err()); + assert!(!TargetBagsList::contains(&42)); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), - Error::::NotDanglingTarget, - ); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 10, 42), + Error::::NotDanglingTarget, + ); - // target is not dangling since it is still bonded. - assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), - Error::::NotDanglingTarget, - ); + // target is not dangling since it is still bonded. + assert_eq!(Staking::status(&31), Ok(StakerStatus::Validator)); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 42, 10), + Error::::NotDanglingTarget, + ); - // target is dangling but voter is not nominating it. - bond_validator(42, 10); + // target is dangling but voter is not nominating it. + bond_validator(42, 10); - assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); - setup_dangling_target_for_nominators(42, vec![101]); - assert!(Staking::status(&42).is_err()); - assert_noop!( - Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), - Error::::NotNominator, - ); - }) + assert_eq!(Staking::status(&101), Ok(StakerStatus::Nominator(vec![11, 21]))); + setup_dangling_target_for_nominators(42, vec![101]); + assert!(Staking::status(&42).is_err()); + assert_noop!( + Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 11, 42), + Error::::NotNominator, + ); + }) } } diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index cd694293d150..a25867bb86a3 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -24,8 +24,6 @@ frame-election-provider-support = { default-features = false, path = "../../elec frame-support = { default-features = false, path = "../../support" } frame-system = { default-features = false, path = "../../system" } -log = { version = "0.4.17", default-features = false } - # Optional imports for benchmarking frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } @@ -48,7 +46,6 @@ std = [ "frame-election-provider-support/std", "frame-support/std", "frame-system/std", - "log/std", "pallet-bags-list/std", "pallet-balances/std", "scale-info/std", diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index b1be2c8778d4..176a0116f52a 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -79,9 +79,6 @@ //! be removed onced all the voters stop nominating the unbonded account (i.e. the target's score //! drops to 0). //! -//! For further details on the target list invariante, refer to [`Self`::do_try_state_approvals`] -//! and [`Self::do_try_state_target_sorting`]. -//! //! ## Event emitter ordering and staking ledger state updates //! //! It is important to ensure that the events are emitted from staking (i.e. the calls into @@ -154,7 +151,6 @@ impl VoterUpdateMode { pub mod pallet { use crate::*; use frame_election_provider_support::{ExtendedBalance, VoteWeight}; - use frame_system::pallet_prelude::BlockNumberFor; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -183,14 +179,6 @@ pub mod pallet { type VoterUpdateMode: Get; } - #[pallet::hooks] - impl Hooks> for Pallet { - #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state() - } - } - impl Pallet { /// Updates the stake of a voter. /// @@ -276,12 +264,8 @@ pub mod pallet { if let Ok(current_score) = T::TargetList::get_score(who) { let balance = current_score.saturating_sub(imbalance); - // the target is removed from the list IFF score is 0 and the target is - // either dangling (i.e. not bonded) or currently registered as a nominator. - let remove_target = balance.is_zero() && - T::Staking::status(who).map(|s| s.is_nominator()).unwrap_or(true); - - if remove_target { + // the target is removed from the list IFF score is 0. + if balance.is_zero() { let _ = T::TargetList::on_remove(who).defensive_proof( "staker exists in the list as per the check above; qed.", ); @@ -309,7 +293,7 @@ pub mod pallet { } /// Helper to fetch te active stake of a staker and convert it to vote weight. - pub(crate) fn vote_of(who: &T::AccountId) -> VoteWeight { + pub fn vote_of(who: &T::AccountId) -> VoteWeight { let active = T::Staking::stake(who).map(|s| s.active).defensive_unwrap_or_default(); Self::to_vote(active) } @@ -321,7 +305,7 @@ pub mod pallet { /// /// TODO: replace this helper method by a debug_assert if #4419 ever prevents the nomination /// of duplicated target. - pub(crate) fn ensure_dedup(mut v: Vec) -> Vec { + pub fn ensure_dedup(mut v: Vec) -> Vec { use sp_std::collections::btree_set::BTreeSet; v.drain(..).collect::>().into_iter().collect::>() @@ -329,242 +313,6 @@ pub mod pallet { } } -#[cfg(any(test, feature = "try-runtime"))] -impl Pallet { - /// Try-state checks for the stake-tracker pallet. - /// - /// 1. `do_try_state_approvals`: checks the current approval stake in the target list compared - /// with the staking state. - /// 2. `do_try_state_target_sorting`: checks if the target list is sorted by score (approvals). - /// 3. `do_try_state_voter_sorting`: checks if the voter list is sorted by score (stake). - pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state_approvals()?; - Self::do_try_state_target_sorting()?; - Self::do_try_state_voter_sorting()?; - - Ok(()) - } - - /// Try-state: checks if the approvals stake of the targets in the target list are correct. - /// - /// These try-state checks generate a map with approval stake of all the targets based on - /// the staking state of stakers in the voter and target lists. In doing so, we are able to - /// verify that the current voter and target lists and scores are in sync with the staking - /// data and perform other sanity checks as the approvals map is calculated. - /// - /// NOTE: this is an expensive state check since it iterates over all the nodes in the - /// target and voter list providers. - /// - /// Invariants: - /// - /// * Target List: - /// * The sum of the calculated approvals stake is the same as the current approvals in - /// the target list per target. - /// * The target score of an active validator is the sum of all of its nominators' stake - /// and the self-stake; - /// * The target score of an idle validator (i.e. chilled) is the sum of its nominator's - /// stake. An idle target may not be part of the target list, if it has no nominations. - /// * The target score of a "dangling" target (ie. idle AND unbonded validator) must - /// always be > 0. We expect the stake-tracker to have cleaned up dangling targets with 0 - /// score. - /// * The number of target nodes in the target list matches the number of - /// (active_validators + idle_validators + dangling_targets_score_with_score). - /// - /// * Voter List: - /// * The voter score is the same as the active stake of the corresponding stash. - /// * An active validator should also be part of the voter list. - /// * An idle validator should not be part of the voter list. - /// * A dangling target shoud not be part of the voter list. - pub(crate) fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { - let mut approvals_map: BTreeMap, sp_npos_elections::ExtendedBalance> = - BTreeMap::new(); - - // build map of approvals stakes from the `VoterList` POV. - for voter in T::VoterList::iter() { - if let Some(nominations) = ::nominations(&voter) { - // sanity check. - let active_stake = T::Staking::stake(&voter) - .map(|s| Self::to_vote(s.active)) - .expect("active voter has bonded stake; qed."); - - // if the voter list is in strict mode, we expect the stake of the voter to match - // the score in the list at all times. The approvals calculation also depends on - // the sorting of the voter list: - // * if the voter list is strictly sorted, use the nominator's scores to calculate - // the approvals. - // * if the voter list is lazily sorted, use the active stake of the nominator to - // calculat the approvals. - let stake = if T::VoterUpdateMode::get().is_strict_mode() { - // voter list is strictly sorted, use the voter list score to calculate the - // target's approvals. - let score = - >>::get_score(&voter) - .map_err(|_| "nominator score must exist in voter bags list")?; - - frame_support::ensure!( - active_stake == score, - "voter score must be the same as its active stake" - ); - - score - } else { - active_stake - }; - - // update the approvals map with the voter's active stake. - // note: must remove the dedup nominations, which is also done by the - // stake-tracker. - let nominations = Self::ensure_dedup(nominations); - - for nomination in nominations { - *approvals_map.entry(nomination).or_default() += - stake as sp_npos_elections::ExtendedBalance; - } - } else { - // if it is in the voter list but it's not a nominator, it should be a validator - // and part of the target list. - frame_support::ensure!( - T::Staking::status(&voter) == Ok(StakerStatus::Validator) && - T::TargetList::contains(&voter), - "wrong state of voter" - ); - frame_support::ensure!( - T::TargetList::contains(&voter), - "if voter is in voter list and it's not a nominator, it must be a target" - ); - } - } - - // add self-vote of active targets to calculated approvals from the `TargetList` POV. - for target in T::TargetList::iter() { - // also checks invariant: all active targets are also voters. - let maybe_self_stake = match T::Staking::status(&target) { - Err(_) => { - // if target is "dangling" (i.e unbonded but still in the `TargetList`), it - // should NOT be part of the voter list. - frame_support::ensure!( - !T::VoterList::contains(&target), - "dangling target (i.e. unbonded) should not be part of the voter list" - ); - - // if target is dangling, its target score should > 0 (otherwise it should - // have been removed from the list). - frame_support::ensure!( - T::TargetList::get_score(&target).expect("target must have score") > Zero::zero(), - "dangling target (i.e. unbonded) is part of the `TargetList` IFF it's approval voting > 0" - ); - // no self-stake and it should not be part of the target list. - None - }, - Ok(StakerStatus::Idle) => { - // target is idle and not part of the voter list. - frame_support::ensure!( - !T::VoterList::contains(&target), - "chilled validator (idle target) should not be part of the voter list" - ); - - // no sef-stake but since it's chilling, it should be part of the TL even - // with score = 0. - Some(0) - }, - Ok(StakerStatus::Validator) => { - // active target should be part of the voter list. - frame_support::ensure!( - T::VoterList::contains(&target), - "bonded and active validator should also be part of the voter list" - ); - // return self-stake (ie. active bonded). - T::Staking::stake(&target).map(|s| Self::to_vote(s.active)).ok() - }, - Ok(StakerStatus::Nominator(_)) => { - // an idle/dangling target may become a nominator. - None - }, - }; - - if let Some(score) = maybe_self_stake { - if let Some(stake) = approvals_map.get_mut(&target) { - *stake += score as sp_npos_elections::ExtendedBalance; - } else { - approvals_map.insert(target, score.into()); - } - } else { - // unbonded target: it does not have self-stake. - } - } - - // compare calculated approvals per target with target list state. - for (target, calculated_stake) in approvals_map.iter() { - let stake_in_list = T::TargetList::get_score(target).expect("target must exist; qed."); - - if *calculated_stake != stake_in_list { - log::error!( - target: "runtime::stake-tracker", - "try-runtime: score of {:?} in `TargetList` list: {:?}, calculated sum of all stake: {:?}", - target, - stake_in_list, - calculated_stake, - ); - - return Err("target score in the target list is different than the expected".into()) - } - } - - frame_support::ensure!( - approvals_map.keys().count() == T::TargetList::iter().count(), - "calculated approvals count is different from total of target list.", - ); - - Ok(()) - } - - /// Try-state: checks if targets in the target list are sorted by score. - /// - /// Invariant - /// * All targets in the target list are sorted by their score (approvals). - /// - /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if - /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we - /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the - /// correct position in the list (bag or otherwise), given its score. - pub fn do_try_state_target_sorting() -> Result<(), sp_runtime::TryRuntimeError> { - for t in T::TargetList::iter() { - frame_support::ensure!( - T::TargetList::in_position(&t).expect("target exists"), - "target list is not sorted" - ); - } - - Ok(()) - } - - /// Try-state: checks if voters in the voter list are sorted by score (stake). - /// - /// Invariant - /// * All voters in the voter list are sorted by their score. - /// - /// NOTE: unfortunatelly, it is not trivial to check if the sort correctness of the list if - /// the `SortedListProvider` is implemented by bags list due to score bucketing. Thus, we - /// leverage the [`SortedListProvider::in_position`] to verify if the target is in the - /// correct position in the list (bag or otherwise), given its score. - pub fn do_try_state_voter_sorting() -> Result<(), sp_runtime::TryRuntimeError> { - // if the voter list is in lazy mode, we don't expect the nodes to be sorted at all times. - // skip checks. - if T::VoterUpdateMode::get().is_strict_mode() { - return Ok(()) - } - - for t in T::VoterList::iter() { - frame_support::ensure!( - T::VoterList::in_position(&t).expect("voter exists"), - "voter list is not sorted" - ); - } - - Ok(()) - } -} - impl OnStakingUpdate> for Pallet { /// When a nominator's stake is updated, all the nominated targets must be updated /// accordingly. @@ -656,7 +404,7 @@ impl OnStakingUpdate> for Pallet { } } else { // target is not part of the list. Given the contract with staking and the checks above, - // this may actually be called. So do nothing and skip defensive warns. + // this may actually be called. Do nothing and skip defensive warns. }; } diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index abc8b999e453..cdc10896b200 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -461,10 +461,6 @@ pub(crate) fn voter_bags_events() -> Vec>() } -parameter_types! { - pub static DisableTryRuntimeChecks: bool = false; -} - #[derive(Default, Copy, Clone)] pub struct ExtBuilder { populate_lists: bool, @@ -481,12 +477,6 @@ impl ExtBuilder { self } - #[allow(dead_code)] - pub fn try_state(self, enable: bool) -> Self { - DisableTryRuntimeChecks::set(!enable); - self - } - pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); @@ -506,13 +496,5 @@ impl ExtBuilder { System::set_block_number(1); }); ext.execute_with(test); - - if !DisableTryRuntimeChecks::get() { - ext.execute_with(|| { - StakeTracker::do_try_state() - .map_err(|err| println!(" 🕵️‍♂️ try_state failure: {:?}", err)) - .unwrap(); - }); - } } } diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index dc7442c2e112..53e204f49abc 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -59,15 +59,11 @@ fn update_target_score_works() { assert_eq!(TargetBagsList::get_score(&10), Ok(300)); let current_score = TargetBagsList::get_score(&10).unwrap(); - crate::Pallet::::update_target_score( - &10, - StakeImbalance::Negative(current_score), - ); - assert_eq!(TargetBagsList::get_score(&10), Ok(0)); + crate::Pallet::::update_target_score(&10, StakeImbalance::Negative(current_score)); - // disables the try runtime checks since the score of 10 was updated manually, so the target - // list was not updated accordingly. - DisableTryRuntimeChecks::set(true); + // score dropped to 0, node is removed. + assert!(!TargetBagsList::contains(&10)); + assert!(TargetBagsList::get_score(&10).is_err()); }) } @@ -449,13 +445,7 @@ mod staking_integration { chill_staker(2); assert_eq!(StakingMock::status(&2), Ok(StakerStatus::Idle)); - // a chilled validator is kepts in the target list. - assert!(TargetBagsList::contains(&2)); - assert!(!VoterBagsList::contains(&2)); - - remove_staker(2); - assert!(StakingMock::status(&2).is_err()); - // a chilled validator is kepts in the target list if its score is 0. + // a chilled validator is dropped from the target list if its score is 0. assert!(!TargetBagsList::contains(&2)); assert!(!VoterBagsList::contains(&2)); }) From 1aa1c80311a8ea4c8386216dae1e8112b3f70dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 3 Jun 2024 18:03:11 +0200 Subject: [PATCH 108/133] fixes umbrella runtime and stake-tracker mock after master merge --- Cargo.lock | 1 + substrate/frame/staking/stake-tracker/src/mock.rs | 4 ++++ umbrella/Cargo.toml | 8 +++++++- umbrella/src/lib.rs | 4 ++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 261b241a07ff..72314e50173c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14148,6 +14148,7 @@ dependencies = [ "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index cdc10896b200..f4270a55ce9a 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -250,6 +250,10 @@ impl StakingInterface for StakingMock { unreachable!(); } + fn is_virtual_staker(_who: &Self::AccountId) -> bool { + unreachable!() + } + #[cfg(feature = "runtime-benchmarks")] fn add_era_stakers( _current_era: &sp_staking::EraIndex, diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index d790b4f5949c..ab51c27f4e8f 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -143,6 +143,7 @@ std = [ "pallet-staking-reward-fn?/std", "pallet-staking-runtime-api?/std", "pallet-staking?/std", + "pallet-stake-tracker?/std", "pallet-state-trie-migration?/std", "pallet-statement?/std", "pallet-sudo?/std", @@ -536,7 +537,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime = ["assets-common", "binary-merkle-tree", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-cumulus", "bp-bridge-hub-kusama", "bp-bridge-hub-polkadot", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "bp-header-chain", "bp-kusama", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-bulletin", "bp-polkadot-core", "bp-relayers", "bp-rococo", "bp-runtime", "bp-test-utils", "bp-westend", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "rococo-runtime-constants", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "westend-runtime-constants", "xcm-fee-payment-runtime-api", "xcm-procedural"] +runtime = ["assets-common", "binary-merkle-tree", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-cumulus", "bp-bridge-hub-kusama", "bp-bridge-hub-polkadot", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "bp-header-chain", "bp-kusama", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-bulletin", "bp-polkadot-core", "bp-relayers", "bp-rococo", "bp-runtime", "bp-test-utils", "bp-westend", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-stake-tracker", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "rococo-runtime-constants", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "westend-runtime-constants", "xcm-fee-payment-runtime-api", "xcm-procedural"] node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ "frame-support-procedural?/tuples-96", @@ -1234,6 +1235,11 @@ path = "../substrate/frame/staking/runtime-api" default-features = false optional = true +[dependencies.pallet-stake-tracker] +path = "../substrate/frame/staking/stake-tracker" +default-features = false +optional = true + [dependencies.pallet-state-trie-migration] path = "../substrate/frame/state-trie-migration" default-features = false diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 78b34ba179b7..29710c8be189 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -673,6 +673,10 @@ pub use pallet_staking_reward_fn; #[cfg(feature = "pallet-staking-runtime-api")] pub use pallet_staking_runtime_api; +/// Keeps track of the staking target's approval stakes. +#[cfg(feature = "pallet-stake-tracker")] +pub use pallet_stake_tracker; + /// FRAME pallet migration of trie. #[cfg(feature = "pallet-state-trie-migration")] pub use pallet_state_trie_migration; From 4bf868a6e8eaca653bf6127350526d35f9e45dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 3 Jun 2024 18:18:55 +0200 Subject: [PATCH 109/133] nits --- umbrella/Cargo.toml | 6 ++++-- umbrella/src/lib.rs | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index ab51c27f4e8f..7fb0e44c4c74 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -140,10 +140,10 @@ std = [ "pallet-session?/std", "pallet-skip-feeless-payment?/std", "pallet-society?/std", + "pallet-stake-tracker?/std", "pallet-staking-reward-fn?/std", "pallet-staking-runtime-api?/std", "pallet-staking?/std", - "pallet-stake-tracker?/std", "pallet-state-trie-migration?/std", "pallet-statement?/std", "pallet-sudo?/std", @@ -322,6 +322,7 @@ runtime-benchmarks = [ "pallet-session-benchmarking?/runtime-benchmarks", "pallet-skip-feeless-payment?/runtime-benchmarks", "pallet-society?/runtime-benchmarks", + "pallet-stake-tracker?/runtime-benchmarks", "pallet-staking?/runtime-benchmarks", "pallet-state-trie-migration?/runtime-benchmarks", "pallet-sudo?/runtime-benchmarks", @@ -451,6 +452,7 @@ try-runtime = [ "pallet-session?/try-runtime", "pallet-skip-feeless-payment?/try-runtime", "pallet-society?/try-runtime", + "pallet-stake-tracker?/try-runtime", "pallet-staking?/try-runtime", "pallet-state-trie-migration?/try-runtime", "pallet-statement?/try-runtime", @@ -537,7 +539,7 @@ with-tracing = [ "sp-tracing?/with-tracing", "sp-tracing?/with-tracing", ] -runtime = ["assets-common", "binary-merkle-tree", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-cumulus", "bp-bridge-hub-kusama", "bp-bridge-hub-polkadot", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "bp-header-chain", "bp-kusama", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-bulletin", "bp-polkadot-core", "bp-relayers", "bp-rococo", "bp-runtime", "bp-test-utils", "bp-westend", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-stake-tracker", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "rococo-runtime-constants", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "westend-runtime-constants", "xcm-fee-payment-runtime-api", "xcm-procedural"] +runtime = ["assets-common", "binary-merkle-tree", "bp-asset-hub-rococo", "bp-asset-hub-westend", "bp-bridge-hub-cumulus", "bp-bridge-hub-kusama", "bp-bridge-hub-polkadot", "bp-bridge-hub-rococo", "bp-bridge-hub-westend", "bp-header-chain", "bp-kusama", "bp-messages", "bp-parachains", "bp-polkadot", "bp-polkadot-bulletin", "bp-polkadot-core", "bp-relayers", "bp-rococo", "bp-runtime", "bp-test-utils", "bp-westend", "bp-xcm-bridge-hub", "bp-xcm-bridge-hub-router", "bridge-hub-common", "bridge-runtime-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", "cumulus-pallet-parachain-system-proc-macro", "cumulus-pallet-session-benchmarking", "cumulus-pallet-solo-to-para", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-ping", "cumulus-primitives-aura", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-primitives-proof-size-hostfunction", "cumulus-primitives-storage-weight-reclaim", "cumulus-primitives-timestamp", "cumulus-primitives-utility", "frame-benchmarking", "frame-benchmarking-pallet-pov", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-executive", "frame-metadata-hash-extension", "frame-support", "frame-support-procedural", "frame-support-procedural-tools-derive", "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", "pallet-alliance", "pallet-asset-conversion", "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", "pallet-assets", "pallet-atomic-swap", "pallet-aura", "pallet-authority-discovery", "pallet-authorship", "pallet-babe", "pallet-bags-list", "pallet-balances", "pallet-beefy", "pallet-beefy-mmr", "pallet-bounties", "pallet-bridge-grandpa", "pallet-bridge-messages", "pallet-bridge-parachains", "pallet-bridge-relayers", "pallet-broker", "pallet-child-bounties", "pallet-collator-selection", "pallet-collective", "pallet-collective-content", "pallet-contracts", "pallet-contracts-proc-macro", "pallet-contracts-uapi", "pallet-conviction-voting", "pallet-core-fellowship", "pallet-delegated-staking", "pallet-democracy", "pallet-dev-mode", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-fast-unstake", "pallet-glutton", "pallet-grandpa", "pallet-identity", "pallet-im-online", "pallet-indices", "pallet-insecure-randomness-collective-flip", "pallet-lottery", "pallet-membership", "pallet-message-queue", "pallet-migrations", "pallet-mixnet", "pallet-mmr", "pallet-multisig", "pallet-nft-fractionalization", "pallet-nfts", "pallet-nfts-runtime-api", "pallet-nis", "pallet-node-authorization", "pallet-nomination-pools", "pallet-nomination-pools-benchmarking", "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", "pallet-paged-list", "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-ranked-collective", "pallet-recovery", "pallet-referenda", "pallet-remark", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", "pallet-salary", "pallet-scheduler", "pallet-scored-pool", "pallet-session", "pallet-session-benchmarking", "pallet-skip-feeless-payment", "pallet-society", "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-staking-reward-fn", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-statement", "pallet-sudo", "pallet-timestamp", "pallet-tips", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "pallet-transaction-storage", "pallet-treasury", "pallet-tx-pause", "pallet-uniques", "pallet-utility", "pallet-vesting", "pallet-whitelist", "pallet-xcm", "pallet-xcm-benchmarks", "pallet-xcm-bridge-hub", "pallet-xcm-bridge-hub-router", "parachains-common", "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", "polkadot-runtime-metrics", "polkadot-runtime-parachains", "polkadot-sdk-frame", "rococo-runtime-constants", "sc-chain-spec-derive", "sc-tracing-proc-macro", "slot-range-helper", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-ethereum", "snowbridge-outbound-queue-merkle-tree", "snowbridge-outbound-queue-runtime-api", "snowbridge-pallet-ethereum-client", "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-inbound-queue", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", "snowbridge-runtime-common", "snowbridge-system-runtime-api", "sp-api", "sp-api-proc-macro", "sp-application-crypto", "sp-arithmetic", "sp-authority-discovery", "sp-block-builder", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", "sp-core", "sp-crypto-ec-utils", "sp-crypto-hashing", "sp-crypto-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-genesis-builder", "sp-inherents", "sp-io", "sp-keyring", "sp-keystore", "sp-metadata-ir", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", "sp-runtime", "sp-runtime-interface", "sp-runtime-interface-proc-macro", "sp-session", "sp-staking", "sp-state-machine", "sp-statement-store", "sp-std", "sp-storage", "sp-timestamp", "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", "sp-version", "sp-version-proc-macro", "sp-wasm-interface", "sp-weights", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", "substrate-bip39", "testnet-parachains-constants", "tracing-gum-proc-macro", "westend-runtime-constants", "xcm-fee-payment-runtime-api", "xcm-procedural"] node = ["asset-test-utils", "bridge-hub-test-utils", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", "cumulus-client-consensus-proposer", "cumulus-client-consensus-relay-chain", "cumulus-client-network", "cumulus-client-parachain-inherent", "cumulus-client-pov-recovery", "cumulus-client-service", "cumulus-relay-chain-inprocess-interface", "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "cumulus-relay-chain-rpc-interface", "cumulus-test-relay-sproof-builder", "emulated-integration-tests-common", "fork-tree", "frame-benchmarking-cli", "frame-remote-externalities", "frame-support-procedural-tools", "generate-bags", "mmr-gadget", "mmr-rpc", "pallet-contracts-mock-network", "pallet-transaction-payment-rpc", "parachains-runtimes-test-utils", "polkadot-approval-distribution", "polkadot-availability-bitfield-distribution", "polkadot-availability-distribution", "polkadot-availability-recovery", "polkadot-cli", "polkadot-collator-protocol", "polkadot-dispute-distribution", "polkadot-erasure-coding", "polkadot-gossip-support", "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", "polkadot-node-core-candidate-validation", "polkadot-node-core-chain-api", "polkadot-node-core-chain-selection", "polkadot-node-core-dispute-coordinator", "polkadot-node-core-parachains-inherent", "polkadot-node-core-prospective-parachains", "polkadot-node-core-provisioner", "polkadot-node-core-pvf", "polkadot-node-core-pvf-checker", "polkadot-node-core-pvf-common", "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-rpc", "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", "sc-allocator", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-client-db", "sc-consensus", "sc-consensus-aura", "sc-consensus-babe", "sc-consensus-babe-rpc", "sc-consensus-beefy", "sc-consensus-beefy-rpc", "sc-consensus-epochs", "sc-consensus-grandpa", "sc-consensus-grandpa-rpc", "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", "sc-executor", "sc-executor-common", "sc-executor-polkavm", "sc-executor-wasmtime", "sc-informant", "sc-keystore", "sc-mixnet", "sc-network", "sc-network-common", "sc-network-gossip", "sc-network-light", "sc-network-statement", "sc-network-sync", "sc-network-transactions", "sc-network-types", "sc-offchain", "sc-proposer-metrics", "sc-rpc", "sc-rpc-api", "sc-rpc-server", "sc-rpc-spec-v2", "sc-service", "sc-state-db", "sc-statement-store", "sc-storage-monitor", "sc-sync-state-rpc", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", "snowbridge-runtime-test-common", "sp-blockchain", "sp-consensus", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-database", "sp-maybe-compressed-blob", "sp-panic-handler", "sp-rpc", "staging-chain-spec-builder", "staging-node-inspect", "staging-tracking-allocator", "std", "subkey", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-rpc-client", "substrate-state-trie-migration-rpc", "substrate-wasm-builder", "tracing-gum", "xcm-emulator", "xcm-simulator"] tuples-96 = [ "frame-support-procedural?/tuples-96", diff --git a/umbrella/src/lib.rs b/umbrella/src/lib.rs index 29710c8be189..c68109350c0f 100644 --- a/umbrella/src/lib.rs +++ b/umbrella/src/lib.rs @@ -657,6 +657,10 @@ pub use pallet_skip_feeless_payment; #[cfg(feature = "pallet-society")] pub use pallet_society; +/// FRAME stake tracker pallet. +#[cfg(feature = "pallet-stake-tracker")] +pub use pallet_stake_tracker; + /// FRAME pallet staking. #[cfg(feature = "pallet-staking")] pub use pallet_staking; @@ -673,10 +677,6 @@ pub use pallet_staking_reward_fn; #[cfg(feature = "pallet-staking-runtime-api")] pub use pallet_staking_runtime_api; -/// Keeps track of the staking target's approval stakes. -#[cfg(feature = "pallet-stake-tracker")] -pub use pallet_stake_tracker; - /// FRAME pallet migration of trie. #[cfg(feature = "pallet-state-trie-migration")] pub use pallet_state_trie_migration; From 3a07d099865feae2475ace8aef5c83dc05bd1955 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Mon, 3 Jun 2024 18:12:00 +0000 Subject: [PATCH 110/133] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=westend --target_dir=polkadot --pallet=pallet_staking --- .../westend/src/weights/pallet_staking.rs | 298 +++++++++--------- 1 file changed, 146 insertions(+), 152 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 5914b2667cb8..2b3f5a3c2d56 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_staking` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-06-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-06-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-1pho9goo-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 @@ -66,10 +66,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn bond() -> Weight { // Proof Size summary in bytes: - // Measured: `1068` + // Measured: `1101` // Estimated: `4764` - // Minimum execution time: 54_643_000 picoseconds. - Weight::from_parts(55_847_000, 0) + // Minimum execution time: 54_820_000 picoseconds. + Weight::from_parts(56_134_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(4)) @@ -88,18 +88,18 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:1 w:1) - /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn bond_extra() -> Weight { // Proof Size summary in bytes: - // Measured: `2596` + // Measured: `2629` // Estimated: `8877` - // Minimum execution time: 122_367_000 picoseconds. - Weight::from_parts(125_973_000, 0) + // Minimum execution time: 119_449_000 picoseconds. + Weight::from_parts(122_803_000, 0) .saturating_add(Weight::from_parts(0, 8877)) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) @@ -122,21 +122,17 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) /// Storage: `Staking::Validators` (r:1 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:3 w:3) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:2 w:2) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListNodes` (r:1 w:1) /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) fn unbond() -> Weight { // Proof Size summary in bytes: - // Measured: `2634` - // Estimated: `8877` - // Minimum execution time: 121_036_000 picoseconds. - Weight::from_parts(123_470_000, 0) - .saturating_add(Weight::from_parts(0, 8877)) - .saturating_add(T::DbWeight::get().reads(15)) - .saturating_add(T::DbWeight::get().writes(8)) + // Measured: `1955` + // Estimated: `4764` + // Minimum execution time: 83_155_000 picoseconds. + Weight::from_parts(85_538_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -156,17 +152,19 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) /// Storage: `NominationPools::ReversePoolIdLookup` (r:1 w:0) /// Proof: `NominationPools::ReversePoolIdLookup` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + /// Storage: `DelegatedStaking::Agents` (r:1 w:0) + /// Proof: `DelegatedStaking::Agents` (`max_values`: None, `max_size`: Some(120), added: 2595, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1342` + // Measured: `1379` // Estimated: `4764` - // Minimum execution time: 56_542_000 picoseconds. - Weight::from_parts(58_269_306, 0) + // Minimum execution time: 59_632_000 picoseconds. + Weight::from_parts(61_370_945, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_008 - .saturating_add(Weight::from_parts(56_385, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(9)) + // Standard Error: 939 + .saturating_add(Weight::from_parts(64_163, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(10)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -206,13 +204,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_kill(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2753 + s * (4 ±0)` + // Measured: `2786 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 123_405_000 picoseconds. - Weight::from_parts(135_753_362, 0) + // Minimum execution time: 125_060_000 picoseconds. + Weight::from_parts(137_232_931, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 5_266 - .saturating_add(Weight::from_parts(1_333_676, 0).saturating_mul(s.into())) + // Standard Error: 4_487 + .saturating_add(Weight::from_parts(1_363_542, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(17)) .saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -248,10 +246,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn validate() -> Weight { // Proof Size summary in bytes: - // Measured: `1536` + // Measured: `1569` // Estimated: `4556` - // Minimum execution time: 73_988_000 picoseconds. - Weight::from_parts(76_337_000, 0) + // Minimum execution time: 71_655_000 picoseconds. + Weight::from_parts(74_791_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().writes(9)) @@ -271,13 +269,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3558 + k * (747 ±0)` + // Measured: `3591 + k * (747 ±0)` // Estimated: `33341 + k * (3566 ±0)` - // Minimum execution time: 95_021_000 picoseconds. - Weight::from_parts(123_030_564, 0) + // Minimum execution time: 97_335_000 picoseconds. + Weight::from_parts(117_057_410, 0) .saturating_add(Weight::from_parts(0, 33341)) - // Standard Error: 35_124 - .saturating_add(Weight::from_parts(36_381_254, 0).saturating_mul(k.into())) + // Standard Error: 32_099 + .saturating_add(Weight::from_parts(36_826_274, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(17)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(15)) @@ -313,13 +311,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2281 + n * (348 ±0)` + // Measured: `2314 + n * (348 ±0)` // Estimated: `6248 + n * (3033 ±0)` - // Minimum execution time: 105_592_000 picoseconds. - Weight::from_parts(81_899_502, 0) + // Minimum execution time: 108_483_000 picoseconds. + Weight::from_parts(83_672_983, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 35_783 - .saturating_add(Weight::from_parts(32_338_384, 0).saturating_mul(n.into())) + // Standard Error: 38_048 + .saturating_add(Weight::from_parts(32_268_279, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(14)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(8)) @@ -348,10 +346,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill() -> Weight { // Proof Size summary in bytes: - // Measured: `2340` + // Measured: `2373` // Estimated: `6248` - // Minimum execution time: 88_979_000 picoseconds. - Weight::from_parts(90_225_000, 0) + // Minimum execution time: 90_227_000 picoseconds. + Weight::from_parts(94_317_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(9)) @@ -364,10 +362,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn set_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `865` + // Measured: `898` // Estimated: `4556` - // Minimum execution time: 18_741_000 picoseconds. - Weight::from_parts(19_262_000, 0) + // Minimum execution time: 18_782_000 picoseconds. + Weight::from_parts(19_664_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -380,10 +378,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Payee` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) fn update_payee() -> Weight { // Proof Size summary in bytes: - // Measured: `932` + // Measured: `965` // Estimated: `4556` - // Minimum execution time: 24_413_000 picoseconds. - Weight::from_parts(25_222_000, 0) + // Minimum execution time: 24_418_000 picoseconds. + Weight::from_parts(25_314_000, 0) .saturating_add(Weight::from_parts(0, 4556)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -394,10 +392,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) fn set_controller() -> Weight { // Proof Size summary in bytes: - // Measured: `865` + // Measured: `898` // Estimated: `8122` - // Minimum execution time: 21_348_000 picoseconds. - Weight::from_parts(22_182_000, 0) + // Minimum execution time: 22_093_000 picoseconds. + Weight::from_parts(22_653_000, 0) .saturating_add(Weight::from_parts(0, 8122)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -408,8 +406,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_730_000 picoseconds. - Weight::from_parts(1_934_000, 0) + // Minimum execution time: 1_794_000 picoseconds. + Weight::from_parts(1_915_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -419,8 +417,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_704_000 picoseconds. - Weight::from_parts(7_205_000, 0) + // Minimum execution time: 6_918_000 picoseconds. + Weight::from_parts(7_328_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -430,8 +428,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_636_000 picoseconds. - Weight::from_parts(6_955_000, 0) + // Minimum execution time: 6_896_000 picoseconds. + Weight::from_parts(7_363_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -441,8 +439,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_667_000 picoseconds. - Weight::from_parts(7_129_000, 0) + // Minimum execution time: 6_939_000 picoseconds. + Weight::from_parts(7_148_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -453,11 +451,11 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_039_000 picoseconds. - Weight::from_parts(2_276_512, 0) + // Minimum execution time: 2_011_000 picoseconds. + Weight::from_parts(2_237_009, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 75 - .saturating_add(Weight::from_parts(12_036, 0).saturating_mul(v.into())) + // Standard Error: 78 + .saturating_add(Weight::from_parts(11_871, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Staking::Ledger` (r:1502 w:1502) @@ -469,13 +467,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 751]`. fn deprecate_controller_batch(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `680 + i * (227 ±0)` + // Measured: `713 + i * (227 ±0)` // Estimated: `990 + i * (7132 ±0)` - // Minimum execution time: 4_163_000 picoseconds. - Weight::from_parts(4_245_000, 0) + // Minimum execution time: 4_165_000 picoseconds. + Weight::from_parts(4_301_000, 0) .saturating_add(Weight::from_parts(0, 990)) - // Standard Error: 37_120 - .saturating_add(Weight::from_parts(21_925_265, 0).saturating_mul(i.into())) + // Standard Error: 37_161 + .saturating_add(Weight::from_parts(21_839_803, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(i.into()))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(i.into()))) .saturating_add(Weight::from_parts(0, 7132).saturating_mul(i.into())) @@ -517,13 +515,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2753 + s * (4 ±0)` + // Measured: `2786 + s * (4 ±0)` // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 120_134_000 picoseconds. - Weight::from_parts(131_611_869, 0) + // Minimum execution time: 120_656_000 picoseconds. + Weight::from_parts(132_995_369, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 5_038 - .saturating_add(Weight::from_parts(1_335_951, 0).saturating_mul(s.into())) + // Standard Error: 4_110 + .saturating_add(Weight::from_parts(1_245_843, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(17)) .saturating_add(T::DbWeight::get().writes(16)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -534,13 +532,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `66639` - // Estimated: `70104` - // Minimum execution time: 125_461_000 picoseconds. - Weight::from_parts(927_976_913, 0) - .saturating_add(Weight::from_parts(0, 70104)) - // Standard Error: 57_690 - .saturating_add(Weight::from_parts(4_831_497, 0).saturating_mul(s.into())) + // Measured: `66672` + // Estimated: `70137` + // Minimum execution time: 130_000_000 picoseconds. + Weight::from_parts(1_192_933_047, 0) + .saturating_add(Weight::from_parts(0, 70137)) + // Standard Error: 76_645 + .saturating_add(Weight::from_parts(6_458_788, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -582,24 +580,20 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `TargetList::ListBags` (r:8 w:8) /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:65 w:65) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:3 w:3) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) /// The range of component `n` is `[0, 64]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `8999 + n * (645 ±0)` - // Estimated: `17769 + n * (3774 ±3)` - // Minimum execution time: 210_946_000 picoseconds. - Weight::from_parts(255_089_468, 0) + // Measured: `8725 + n * (482 ±0)` + // Estimated: `17769 + n * (3774 ±0)` + // Minimum execution time: 184_524_000 picoseconds. + Weight::from_parts(244_791_126, 0) .saturating_add(Weight::from_parts(0, 17769)) - // Standard Error: 45_994 - .saturating_add(Weight::from_parts(89_944_022, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().reads((10_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(15)) - .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) + // Standard Error: 46_100 + .saturating_add(Weight::from_parts(62_744_799, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(25)) + .saturating_add(T::DbWeight::get().reads((9_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(12)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n.into()))) .saturating_add(Weight::from_parts(0, 3774).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) @@ -616,22 +610,22 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) /// Storage: `Staking::Nominators` (r:1 w:0) /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListNodes` (r:3 w:3) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) /// Storage: `VoterList::ListBags` (r:2 w:2) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) - /// Storage: `TargetList::ListNodes` (r:1 w:1) - /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2597 + l * (5 ±0)` + // Measured: `2630 + l * (5 ±0)` // Estimated: `8877` - // Minimum execution time: 119_360_000 picoseconds. - Weight::from_parts(123_258_796, 0) + // Minimum execution time: 114_260_000 picoseconds. + Weight::from_parts(118_334_795, 0) .saturating_add(Weight::from_parts(0, 8877)) - // Standard Error: 4_980 - .saturating_add(Weight::from_parts(83_927, 0).saturating_mul(l.into())) + // Standard Error: 5_407 + .saturating_add(Weight::from_parts(92_391, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -670,13 +664,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `2753 + s * (4 ±0)` - // Estimated: `6248 + s * (4 ±0)` - // Minimum execution time: 134_590_000 picoseconds. - Weight::from_parts(137_403_871, 0) - .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 4_133 - .saturating_add(Weight::from_parts(1_322_316, 0).saturating_mul(s.into())) + // Measured: `2786 + s * (4 ±0)` + // Estimated: `6251 + s * (4 ±0)` + // Minimum execution time: 136_630_000 picoseconds. + Weight::from_parts(139_624_083, 0) + .saturating_add(Weight::from_parts(0, 6251)) + // Standard Error: 4_377 + .saturating_add(Weight::from_parts(1_270_564, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(16)) .saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) @@ -726,13 +720,13 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0 + n * (716 ±0) + v * (3772 ±0)` // Estimated: `516555 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 869_142_000 picoseconds. - Weight::from_parts(874_703_000, 0) + // Minimum execution time: 861_594_000 picoseconds. + Weight::from_parts(870_075_000, 0) .saturating_add(Weight::from_parts(0, 516555)) - // Standard Error: 1_916_556 - .saturating_add(Weight::from_parts(60_523_432, 0).saturating_mul(v.into())) - // Standard Error: 190_974 - .saturating_add(Weight::from_parts(18_981_553, 0).saturating_mul(n.into())) + // Standard Error: 2_000_637 + .saturating_add(Weight::from_parts(64_775_296, 0).saturating_mul(v.into())) + // Standard Error: 199_352 + .saturating_add(Weight::from_parts(19_111_894, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(388)) .saturating_add(T::DbWeight::get().reads((6_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -761,15 +755,15 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `n` is `[500, 1000]`. fn get_npos_voters(v: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `3142 + n * (907 ±0) + v * (391 ±0)` + // Measured: `3175 + n * (907 ±0) + v * (391 ±0)` // Estimated: `456136 + n * (3566 ±0) + v * (3566 ±0)` - // Minimum execution time: 36_931_542_000 picoseconds. - Weight::from_parts(37_274_119_000, 0) + // Minimum execution time: 37_093_286_000 picoseconds. + Weight::from_parts(37_508_552_000, 0) .saturating_add(Weight::from_parts(0, 456136)) - // Standard Error: 377_146 - .saturating_add(Weight::from_parts(3_948_980, 0).saturating_mul(v.into())) - // Standard Error: 377_146 - .saturating_add(Weight::from_parts(4_835_554, 0).saturating_mul(n.into())) + // Standard Error: 410_759 + .saturating_add(Weight::from_parts(5_517_425, 0).saturating_mul(v.into())) + // Standard Error: 410_759 + .saturating_add(Weight::from_parts(4_236_228, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(179)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(n.into()))) @@ -792,13 +786,13 @@ impl pallet_staking::WeightInfo for WeightInfo { /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `58105 + v * (323 ±0)` + // Measured: `58138 + v * (323 ±0)` // Estimated: `516555 + v * (3033 ±0)` - // Minimum execution time: 9_187_779_000 picoseconds. - Weight::from_parts(9_238_084_000, 0) + // Minimum execution time: 9_387_999_000 picoseconds. + Weight::from_parts(9_449_117_000, 0) .saturating_add(Weight::from_parts(0, 516555)) - // Standard Error: 111_859 - .saturating_add(Weight::from_parts(7_084_998, 0).saturating_mul(v.into())) + // Standard Error: 115_623 + .saturating_add(Weight::from_parts(7_439_858, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(206)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(v.into()))) .saturating_add(Weight::from_parts(0, 3033).saturating_mul(v.into())) @@ -821,8 +815,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_607_000 picoseconds. - Weight::from_parts(3_819_000, 0) + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(3_844_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -844,8 +838,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_221_000 picoseconds. - Weight::from_parts(3_406_000, 0) + // Minimum execution time: 3_261_000 picoseconds. + Weight::from_parts(3_462_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(7)) } @@ -877,10 +871,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn chill_other() -> Weight { // Proof Size summary in bytes: - // Measured: `2455` + // Measured: `2488` // Estimated: `6248` - // Minimum execution time: 99_926_000 picoseconds. - Weight::from_parts(102_789_000, 0) + // Minimum execution time: 101_110_000 picoseconds. + Weight::from_parts(105_138_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(15)) .saturating_add(T::DbWeight::get().writes(9)) @@ -891,10 +885,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) fn force_apply_min_commission() -> Weight { // Proof Size summary in bytes: - // Measured: `658` + // Measured: `691` // Estimated: `3510` - // Minimum execution time: 11_542_000 picoseconds. - Weight::from_parts(11_866_000, 0) + // Minimum execution time: 11_460_000 picoseconds. + Weight::from_parts(11_842_000, 0) .saturating_add(Weight::from_parts(0, 3510)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -905,8 +899,8 @@ impl pallet_staking::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_860_000 picoseconds. - Weight::from_parts(1_982_000, 0) + // Minimum execution time: 1_866_000 picoseconds. + Weight::from_parts(2_002_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -928,10 +922,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) fn restore_ledger() -> Weight { // Proof Size summary in bytes: - // Measured: `1099` + // Measured: `1132` // Estimated: `4764` - // Minimum execution time: 53_417_000 picoseconds. - Weight::from_parts(54_329_000, 0) + // Minimum execution time: 53_810_000 picoseconds. + Weight::from_parts(54_953_000, 0) .saturating_add(Weight::from_parts(0, 4764)) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) @@ -956,10 +950,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn drop_dangling_nomination() -> Weight { // Proof Size summary in bytes: - // Measured: `1758` + // Measured: `1791` // Estimated: `8631` - // Minimum execution time: 84_706_000 picoseconds. - Weight::from_parts(86_977_000, 0) + // Minimum execution time: 86_529_000 picoseconds. + Weight::from_parts(89_155_000, 0) .saturating_add(Weight::from_parts(0, 8631)) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(4)) @@ -980,10 +974,10 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn v13_mmb_step() -> Weight { // Proof Size summary in bytes: - // Measured: `167489` + // Measured: `167522` // Estimated: `2645990` - // Minimum execution time: 10_465_670_000 picoseconds. - Weight::from_parts(10_570_173_000, 0) + // Minimum execution time: 10_525_342_000 picoseconds. + Weight::from_parts(10_686_750_000, 0) .saturating_add(Weight::from_parts(0, 2645990)) .saturating_add(T::DbWeight::get().reads(2199)) .saturating_add(T::DbWeight::get().writes(83)) From 1445118ca20e46275486055709e476a4b1e9d75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 13:42:40 +0200 Subject: [PATCH 111/133] docs pass --- .../src/migrations/v13_stake_tracker/mod.rs | 3 +- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/pallet/mod.rs | 4 +- .../frame/staking/stake-tracker/src/lib.rs | 62 +++++++++---------- 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 097e8f4a468f..c67486dbcdf8 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -75,8 +75,7 @@ impl Default for Processing { /// /// When migrating a nominator, we need to ensure that the nominator is not nominating duplicate /// targets. In addition, this migration also "cleans" the nominations by dropping all nominations -/// of targets that are not active validators. This logic is implemented by -/// [`MigrationV13::clean_nominations`]. In sum, the followinf invariants hold true after +/// of targets that are not active validators. In sum, the following invariants hold true after /// processing each nominator: /// /// 1. A nominator has no duplicate nominations; diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index ef3768131193..998607bc3801 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -444,7 +444,7 @@ impl Pallet { return Err(Error::::NotDanglingTarget.into()); } - ::nominate(nominator, nominations_after.clone())?; // TODO remove clone? + ::nominate(nominator, nominations_after.clone())?; Ok(BoundedVec::truncate_from(nominations_after)) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 401829472985..210324259048 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -2113,11 +2113,9 @@ pub mod pallet { /// for the "dangling" target needs to remain in the target list. This extrinsic allows /// nominations of dangling targets to be removed. /// - /// A danling nomination may be removed IFF: + /// A dangling nomination may be removed IFF: /// * The `target` is unbonded and it exists in the target list. /// * The `voter` is nominating `target`. - /// - /// Emits [`Event::DanglingNominationDropped`]. #[pallet::call_index(30)] #[pallet::weight(T::WeightInfo::drop_dangling_nomination())] pub fn drop_dangling_nomination( diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 176a0116f52a..3a8f05b2a116 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -24,8 +24,8 @@ //! //! The stake-tracker pallet listens to staking events through implementing the [`OnStakingUpdate`] //! trait. Based on the emitted events, the goal of this pallet is to maintain a **strictly** -//! sorted list of targets by approval voting. This pallet may also update a voter list, based on -//! the configurations. +//! sorted list of targets by approval voting. This pallet may also update a voter list and their +//! scores, based on the [`crate::VoterUpdateMode`] configuration. //! //! For the voter list, the [`crate::VoterUpdateMode`] defines the type of sortition of the list, //! namely: @@ -33,16 +33,13 @@ //! - [`crate::VoterUpdateMode::Lazy`]: will skip the score update in the voter list. //! - [`crate::VoterUpdateMode::Strict`]: will ensure that the score updates are kept sorted //! for the corresponding list. In this case, the [`Config::VoterList`] is *strictly* -//! sorted* by [`SortedListProvider::Score`] (note: from the time the sorting mode is strict). +//! sorted by [`SortedListProvider::Score`] (note: from the time the sorting mode is strict). //! //! Note that insertions and removals of voter nodes will be executed regardless of the sorting //! mode. //! //! ## Goals //! -//! Note: these goals are assuming the both target list and sorted lists have -//! [`crate::VoterUpdateMode::Strict`] set. -//! //! The [`OnStakingUpdate`] implementation (in strict mode) aims to achieve the following goals: //! //! * The [`Config::TargetList`] keeps a sorted list of validators, *strictly* sorted by approvals @@ -62,15 +59,11 @@ //! //! ## Staker status and list invariants //! -//! Note: these goals are assuming the both target list and sorted lists have -//! [`crate::VoterUpdateMode::Strict`] set. -//! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the //! voter list's score. In addition, if the `VoterList` is in strict mode, the voters' scores are up -//! to date with the current stake returned by [`T::Staking::stake`]. +//! to date with the current stake returned by [`sp_staking::StakingInterface`]. //! * A [`sp_staking::StakerStatus::Validator`] is part of both voter and target list. In addition, -//! if the `TargetList` is in strict mode, its -//! approvals score (nominations + self-stake) is kept up to date as the target list's score. +//! its approvals score (nominations + self-stake) is kept up to date as the target list's score. //! * A [`sp_staking::StakerStatus::Idle`] may have a target list's score while other stakers //! nominate the idle validator. //! * A "dangling" target, which is not an active staker anymore (i.e. not bonded), may still have @@ -79,11 +72,18 @@ //! be removed onced all the voters stop nominating the unbonded account (i.e. the target's score //! drops to 0). //! -//! ## Event emitter ordering and staking ledger state updates +//! ## Expectations +//! +//! For the goals and invariants to be respected, this pallet expects the following: //! -//! It is important to ensure that the events are emitted from staking (i.e. the calls into +//! - **Event emitting order**: It is important to ensure that the events are emitted from staking +//! (i.e. the calls into //! [`OnStakingUpdate`]) *after* the staking ledger has been updated by the caller, since the new //! state will be fetched and used to update the sorted lists accordingly. +//! - **Deduplicate nominations**: The nominations should be deduplicate. This pallet handles +//! nominations of voters from the underlying staking system. The nominations may be retrieved +//! through the [`sp_staking::StakingInterface`] and/or through the [`sp_staking::OnStakingUpdate`] +//! methods. This pallet expects that there are no duplicate nominations for each voter. #![cfg_attr(not(feature = "std"), no_std)] @@ -190,6 +190,8 @@ pub mod pallet { stake: Stake>, nominations: Vec, ) { + debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + let voter_weight = Self::to_vote(stake.active); // if voter list is in strict sorting mode, update the voter score too. @@ -205,11 +207,6 @@ pub mod pallet { voter_weight.into(), ); - // note: this dedup can be removed once the staking pallet ensures no duplicate - // nominations are allowed . - // TODO: replace the dedup by a debug_assert once #4419 is resolved. - let nominations = Self::ensure_dedup(nominations); - // updates vote weight of nominated targets accordingly. Note: this will // update the score of up to `T::MaxNominations` validators. for target in nominations.into_iter() { @@ -298,17 +295,16 @@ pub mod pallet { Self::to_vote(active) } - /// Returns a dedup list of accounts. + /// Returns whether a nomination vec has duplicate targets. /// - /// Note: this dedup can be removed once (and if) the staking pallet ensures no duplicate - /// nominations are allowed . - /// - /// TODO: replace this helper method by a debug_assert if #4419 ever prevents the nomination - /// of duplicated target. - pub fn ensure_dedup(mut v: Vec) -> Vec { + /// Used for debug assertions only, since this pallet expects the nominations to be + /// deduplicated. + pub fn has_duplicate_nominations(mut v: Vec) -> bool { use sp_std::collections::btree_set::BTreeSet; + let size_before = v.len(); + let dedup = v.drain(..).collect::>().into_iter().collect::>(); - v.drain(..).collect::>().into_iter().collect::>() + size_before != dedup.len() } } } @@ -415,8 +411,9 @@ impl OnStakingUpdate> for Pallet { /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is /// called. fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { + debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + let nominator_vote = Self::vote_of(who); - let nominations = Self::ensure_dedup(nominations); // the new voter node will be added even if the voter is in lazy mode. In lazy mode, we // ensure that the nodes exist in the voter list, even though they may not have the updated @@ -453,8 +450,9 @@ impl OnStakingUpdate> for Pallet { /// Note: the number of nodes that are updated is bounded by the maximum number of /// nominators, which is defined in the staking pallet. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { + debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + let nominator_vote = Self::vote_of(who); - let nominations = Self::ensure_dedup(nominations); // updates the nominated target's score. for t in nominations.iter() { @@ -477,10 +475,10 @@ impl OnStakingUpdate> for Pallet { prev_nominations: Vec, nominations: Vec, ) { - let nominator_vote = Self::vote_of(who); + debug_assert!(!Self::has_duplicate_nominations(prev_nominations.clone())); + debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); - let nominations = Self::ensure_dedup(nominations); - let prev_nominations = Self::ensure_dedup(prev_nominations); + let nominator_vote = Self::vote_of(who); // new nominations. for target in nominations.iter() { From e785621a94fc712bcf1e95ea9c8e9ad1d09d4f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 14:03:44 +0200 Subject: [PATCH 112/133] nit: fix umbrella cargo lint --- umbrella/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 7fb0e44c4c74..8cf0e58762e8 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -1217,6 +1217,11 @@ path = "../substrate/frame/society" default-features = false optional = true +[dependencies.pallet-stake-tracker] +path = "../substrate/frame/staking/stake-tracker" +default-features = false +optional = true + [dependencies.pallet-staking] path = "../substrate/frame/staking" default-features = false @@ -1237,11 +1242,6 @@ path = "../substrate/frame/staking/runtime-api" default-features = false optional = true -[dependencies.pallet-stake-tracker] -path = "../substrate/frame/staking/stake-tracker" -default-features = false -optional = true - [dependencies.pallet-state-trie-migration] path = "../substrate/frame/state-trie-migration" default-features = false From 8c685d76c4bec1a74f4a0f720a2d100aac189fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 14:50:46 +0200 Subject: [PATCH 113/133] fixes nomination pools benchmarks (validators must exist) --- .../benchmarking/src/inner.rs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/inner.rs b/substrate/frame/nomination-pools/benchmarking/src/inner.rs index b8c978945e9e..5ffce108a667 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/inner.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/inner.rs @@ -109,6 +109,15 @@ fn create_pool_account( (pool_creator, pool_account) } +// Set an account as validator. +fn add_targets(targets: Vec) { + use frame_election_provider_support::ElectionDataProvider; + + for t in targets.into_iter() { + pallet_staking::Pallet::::add_target(t); + } +} + fn migrate_to_transfer_stake(pool_id: PoolId) { if T::StakeAdapter::strategy_type() == StakeStrategyType::Transfer { // should already be in the correct strategy @@ -185,19 +194,15 @@ impl ListScenario { let (pool_creator1, pool_origin1) = create_pool_account::(USER_SEED + 1, origin_weight, Some(Perbill::from_percent(50))); - T::StakeAdapter::nominate( - Pool::from(pool_origin1.clone()), - // NOTE: these don't really need to be validators. - vec![account("random_validator", 0, USER_SEED)], - )?; + let target: T::AccountId = account("random_validator", 0, USER_SEED); + add_targets::(vec![target.clone()]); + + T::StakeAdapter::nominate(Pool::from(pool_origin1.clone()), vec![target.clone()])?; let (_, pool_origin2) = create_pool_account::(USER_SEED + 2, origin_weight, Some(Perbill::from_percent(50))); - T::StakeAdapter::nominate( - Pool::from(pool_origin2.clone()), - vec![account("random_validator", 0, USER_SEED)].clone(), - )?; + T::StakeAdapter::nominate(Pool::from(pool_origin2.clone()), vec![target.clone()])?; // Find a destination weight that will trigger the worst case scenario let dest_weight_as_vote = ::VoterList::score_update_worst_case( @@ -212,10 +217,7 @@ impl ListScenario { let (_, pool_dest1) = create_pool_account::(USER_SEED + 3, dest_weight, Some(Perbill::from_percent(50))); - T::StakeAdapter::nominate( - Pool::from(pool_dest1.clone()), - vec![account("random_validator", 0, USER_SEED)], - )?; + T::StakeAdapter::nominate(Pool::from(pool_dest1.clone()), vec![target.clone()])?; let weight_of = pallet_staking::Pallet::::weight_of_fn(); assert_eq!(vote_to_balance::(weight_of(&pool_origin1)).unwrap(), origin_weight); @@ -613,12 +615,14 @@ frame_benchmarking::benchmarks! { let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond, None); - // Create some accounts to nominate. For the sake of benchmarking they don't need to be - // actual validators + // Create some accounts to nominate. let validators: Vec<_> = (0..n) .map(|i| account("stash", USER_SEED, i)) .collect(); + // Ensure the nominations are all active targets. + add_targets::(validators.clone()); + whitelist_account!(depositor); }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) verify { @@ -726,6 +730,9 @@ frame_benchmarking::benchmarks! { .map(|i| account("stash", USER_SEED, i)) .collect(); + // Ensure the nominations are all active targets. + add_targets::(validators.clone()); + assert_ok!(T::StakeAdapter::nominate(Pool::from(pool_account.clone()), validators)); assert!(T::StakeAdapter::nominations(Pool::from(pool_account.clone())).is_some()); From c34ede149fc2eb55e72c86b61571ef0d6f492d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 16:00:21 +0200 Subject: [PATCH 114/133] adds try-state checks to ensure no duplicate targets in nomination --- prdoc/pr_1933.prdoc | 3 +- substrate/frame/staking/src/pallet/impls.rs | 32 +++++++++++++++++---- substrate/frame/staking/src/tests.rs | 29 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/prdoc/pr_1933.prdoc b/prdoc/pr_1933.prdoc index 3dbfee9a6a40..25a461a24432 100644 --- a/prdoc/pr_1933.prdoc +++ b/prdoc/pr_1933.prdoc @@ -4,7 +4,7 @@ doc: - audience: Runtime Dev description: | The (newly added) `stake-tracker` pallet implements the `OnStakingUpdate` trait to listen to - staking events and multiplexes those events to one or multiple types (e.g. pallets). The + staking events and multiplex those events to one or multiple types (e.g. pallets). The `stake-tracker` pallet is used as a degree of indirection to maintain an *always-sorted* target and a semi-sorted voter list for staking (implemented by the bags list pallet). Other notable changes in this PR are: @@ -18,4 +18,5 @@ doc: crates: - name: pallet-staking + bump: minor - name: pallet-stake-tracker diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 998607bc3801..e11339025715 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2364,7 +2364,10 @@ impl Pallet { /// Invariants: /// * Checks that each nominator has its entire stake correctly distributed. + /// * Nominations do not have duplicate targets. fn check_nominators() -> Result<(), TryRuntimeError> { + use sp_std::collections::btree_set::BTreeSet; + // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. let era = Self::active_era().unwrap().index; @@ -2376,15 +2379,34 @@ impl Pallet { .collect::>(); >::iter() - .filter_map( - |(nominator, nomination)| { + // fails if a nomination vec has duplicate targets. + .map(|nomination| -> Result<(T::AccountId, Nominations), TryRuntimeError> { + let targets = nomination.clone().1.targets; + + let count_before = targets.len(); + let dedup_noms: Vec = targets + .clone() + .drain(..) + .collect::>() + .into_iter() + .collect::>(); + + ensure!( + count_before == dedup_noms.len(), + "A nominator has duplicate nominations; unexpected." + ); + + Ok(nomination) + }) + .filter_map(|n| match n { + Ok((nominator, nomination)) => if nomination.submitted_in < era { Some(nominator) } else { None - } - }, - ) + }, + Err(_) => None, + }) .map(|nominator| -> Result<(), TryRuntimeError> { // must be bonded. Self::ensure_is_stash(&nominator)?; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 0226600b2a8f..1e9ed7f57e6e 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -748,6 +748,35 @@ fn nominating_and_rewards_should_work() { }); } +#[test] +fn nominate_filters_duplicate_targets() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Staking::status(&101).unwrap(), StakerStatus::Nominator(vec![11, 21])); + + // re-nominate with duplicates, which are filtered out. + assert_ok!(Staking::nominate(RuntimeOrigin::signed(101), vec![11, 11, 11, 21, 21, 21])); + assert_eq!(Staking::status(&101).unwrap(), StakerStatus::Nominator(vec![11, 21])); + }) +} + +#[test] +#[should_panic = "called `Result::unwrap()` on an `Err` value: Other(\"nominator has duplicate nominations, unexpected.\")"] +fn nominate_duplicate_targets_try_state_fails() { + ExtBuilder::default().build_and_execute(|| { + let nominations = Nominators::::get(&101).unwrap(); + assert_eq!(nominations.targets, vec![11, 21]); + + let dup_noms = Nominations { + targets: bounded_vec![11, 11, 21], + submitted_in: nominations.submitted_in, + suppressed: nominations.suppressed, + }; + Nominators::::insert(&101, dup_noms); + + assert_eq!(Staking::status(&101).unwrap(), StakerStatus::Nominator(vec![11, 11, 21])); + }); +} + #[test] fn nominators_also_get_slashed_pro_rata() { ExtBuilder::default() From 303b4be49aa88a647202afed2d522960aad26882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 22:12:18 +0200 Subject: [PATCH 115/133] fixes tests and mocks in other pallets --- Cargo.lock | 2 ++ substrate/frame/delegated-staking/src/mock.rs | 10 +++++++ .../test-delegate-stake/Cargo.toml | 1 + .../test-delegate-stake/src/lib.rs | 3 -- .../test-delegate-stake/src/mock.rs | 28 +++++++++++++++++-- .../test-transfer-stake/Cargo.toml | 1 + .../test-transfer-stake/src/mock.rs | 28 +++++++++++++++++-- substrate/frame/staking/src/pallet/impls.rs | 5 +++- 8 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72314e50173c..470e4820f7c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10911,6 +10911,7 @@ dependencies = [ "pallet-balances", "pallet-delegated-staking", "pallet-nomination-pools", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", @@ -10935,6 +10936,7 @@ dependencies = [ "pallet-bags-list", "pallet-balances", "pallet-nomination-pools", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index c1875055f2fe..da2663c0ba7f 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -208,6 +208,11 @@ impl ExtBuilder { let _ = pallet_balances::GenesisConfig:: { balances: vec![ + (18, 200), + (19, 200), + (20, 200), + (21, 200), + (22, 200), (GENESIS_VALIDATOR, 10000), (GENESIS_NOMINATOR_ONE, 1000), (GENESIS_NOMINATOR_TWO, 2000), @@ -216,6 +221,11 @@ impl ExtBuilder { .assimilate_storage(&mut storage); let stakers = vec![ + (18, 18, 100, sp_staking::StakerStatus::Validator), + (19, 19, 100, sp_staking::StakerStatus::Validator), + (20, 20, 100, sp_staking::StakerStatus::Validator), + (21, 21, 100, sp_staking::StakerStatus::Validator), + (22, 22, 100, sp_staking::StakerStatus::Validator), ( GENESIS_VALIDATOR, GENESIS_VALIDATOR, diff --git a/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml index ea8eb2069693..cccaa1d78561 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml +++ b/substrate/frame/nomination-pools/test-delegate-stake/Cargo.toml @@ -32,6 +32,7 @@ frame-election-provider-support = { path = "../../election-provider-support" } pallet-timestamp = { path = "../../timestamp" } pallet-balances = { path = "../../balances" } pallet-staking = { path = "../../staking" } +pallet-stake-tracker = { path = "../../staking/stake-tracker" } pallet-delegated-staking = { path = "../../delegated-staking" } pallet-bags-list = { path = "../../bags-list" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs index 51f6470f90d0..7bdeefff1896 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/lib.rs @@ -920,9 +920,6 @@ fn pool_migration_e2e() { assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - // have the pool nominate. - assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - assert_eq!( staking_events_since_last_call(), vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 501823263598..98bbd0e6d93f 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -139,12 +139,24 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; - type EventListeners = (Pools, DelegatedStaking); + type EventListeners = (StakeTracker, Pools, DelegatedStaking); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } +parameter_types! { + pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; +} + +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; + type VoterUpdateMode = VoterUpdateMode; +} + parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } @@ -318,6 +330,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, Staking: pallet_staking, VoterList: pallet_bags_list::, + StakeTracker: pallet_stake_tracker, Pools: pallet_nomination_pools, DelegatedStaking: pallet_delegated_staking, } @@ -338,7 +351,18 @@ pub fn new_test_ext() -> sp_io::TestExternalities { .unwrap(); let _ = pallet_balances::GenesisConfig:: { - balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], + balances: vec![(1, 200), (2, 200), (3, 200), (10, 100), (20, 100), (21, 100), (22, 100)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let _ = pallet_staking::GenesisConfig:: { + stakers: vec![ + (1, 1, 100, pallet_staking::StakerStatus::Validator), + (2, 2, 100, pallet_staking::StakerStatus::Validator), + (3, 3, 100, pallet_staking::StakerStatus::Validator), + ], + ..Default::default() } .assimilate_storage(&mut storage) .unwrap(); diff --git a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml index 5f9bc9af3a21..73c10054f63d 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml +++ b/substrate/frame/nomination-pools/test-transfer-stake/Cargo.toml @@ -32,6 +32,7 @@ frame-election-provider-support = { path = "../../election-provider-support" } pallet-timestamp = { path = "../../timestamp" } pallet-balances = { path = "../../balances" } pallet-staking = { path = "../../staking" } +pallet-stake-tracker = { path = "../../staking/stake-tracker" } pallet-bags-list = { path = "../../bags-list" } pallet-staking-reward-curve = { path = "../../staking/reward-curve" } pallet-nomination-pools = { path = ".." } diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index 0970570453b4..fd14fb7dc374 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -134,12 +134,24 @@ impl pallet_staking::Config for Runtime { type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = ConstU32<100>; type HistoryDepth = ConstU32<84>; - type EventListeners = Pools; + type EventListeners = (StakeTracker, Pools); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } +parameter_types! { + pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; +} + +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; + type VoterUpdateMode = VoterUpdateMode; +} + parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } @@ -198,6 +210,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, Staking: pallet_staking, VoterList: pallet_bags_list::, + StakeTracker: pallet_stake_tracker, Pools: pallet_nomination_pools, } ); @@ -217,7 +230,18 @@ pub fn new_test_ext() -> sp_io::TestExternalities { .unwrap(); let _ = pallet_balances::GenesisConfig:: { - balances: vec![(10, 100), (20, 100), (21, 100), (22, 100)], + balances: vec![(1, 200), (2, 200), (3, 200), (10, 100), (20, 100), (21, 100), (22, 100)], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let _ = pallet_staking::GenesisConfig:: { + stakers: vec![ + (1, 1, 100, pallet_staking::StakerStatus::Validator), + (2, 2, 100, pallet_staking::StakerStatus::Validator), + (3, 3, 100, pallet_staking::StakerStatus::Validator), + ], + ..Default::default() } .assimilate_storage(&mut storage) .unwrap(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index e11339025715..5a22c8111ce5 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1182,11 +1182,11 @@ impl Pallet { }, } - #[cfg(not(test))] debug_assert_eq!( Nominators::::count() + Validators::::count(), T::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .filter(|v| !Self::status(&v).is_err()) .count() as u32, ); } @@ -1218,6 +1218,7 @@ impl Pallet { Nominators::::count() + Validators::::count(), T::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .filter(|v| !Self::status(&v).is_err()) .count() as u32, ); @@ -1245,6 +1246,7 @@ impl Pallet { Nominators::::count() + Validators::::count(), T::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .filter(|v| !Self::status(&v).is_err()) .count() as u32, ); } @@ -1279,6 +1281,7 @@ impl Pallet { Nominators::::count() + Validators::::count(), T::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) + .filter(|v| !Self::status(&v).is_err()) .count() as u32, ); From cc16579760b4e81dc2bbde5d8cde4dc5a68d88c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 5 Jun 2024 23:01:05 +0200 Subject: [PATCH 116/133] semver nits --- prdoc/pr_1933.prdoc | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/prdoc/pr_1933.prdoc b/prdoc/pr_1933.prdoc index 25a461a24432..a43a3a090f9c 100644 --- a/prdoc/pr_1933.prdoc +++ b/prdoc/pr_1933.prdoc @@ -3,16 +3,16 @@ title: Adds `stake-tracker` pallet and integrates it with the staking pallet doc: - audience: Runtime Dev description: | - The (newly added) `stake-tracker` pallet implements the `OnStakingUpdate` trait to listen to - staking events and multiplex those events to one or multiple types (e.g. pallets). The - `stake-tracker` pallet is used as a degree of indirection to maintain an *always-sorted* - target and a semi-sorted voter list for staking (implemented by the bags list pallet). + Adds the `stake-tracker` pallet which ensures that the staking system keeps an up-to date + list of targets, *strictly-sorted* by the target's approvals stakes. The `stake-tracker` + pallet implements the `OnStakingUpdate` trait to listen to staking events and handle those + events so that the target list remains strictly-sorted and up-to date. Other notable changes in this PR are: * Changes to assumptions of chilled and removed stakers: the target list keeps track of validators that have been chilled/removed from the system, insofar as there are nominators nominating them; - * Changes to staking `Call::nominate`: New nominations can only be performed on active or - chilling validators; + * Changes to staking `Call::nominate`: new nominations can only be performed on active + validators or idle stakers; * Changes to `OnStakingUpdate` trait: new methods for signaling chilling of stakers (`on_idle`) and refactors trait API for safety of use. @@ -20,3 +20,20 @@ crates: - name: pallet-staking bump: minor - name: pallet-stake-tracker + bump: major + - name: sp-staking + bump: major + - name: frame-election-provider-support + bump: none + - name: polkadot-sdk + bump: minor + - pallet-fast-unstake + bump: none + - pallet-bags-list + bump: minor + - westend-runtime + bump: minor + - pallet-delegated-staking + bump: none + - pallet-nomination-pools-benchmarking + bump: none From fc39f8e936f965a1fca4411ca883d9e5d7a147b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 6 Jun 2024 07:24:09 +0200 Subject: [PATCH 117/133] all try-state checks pass for ext pallets; prdoc nits --- Cargo.lock | 2 ++ prdoc/pr_1933.prdoc | 12 +++---- substrate/frame/delegated-staking/Cargo.toml | 8 +++++ substrate/frame/delegated-staking/src/mock.rs | 36 ++++++++++++++++--- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e2c36240984..d31734c04999 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10210,8 +10210,10 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", + "pallet-bags-list", "pallet-balances", "pallet-nomination-pools", + "pallet-stake-tracker", "pallet-staking", "pallet-staking-reward-curve", "pallet-timestamp", diff --git a/prdoc/pr_1933.prdoc b/prdoc/pr_1933.prdoc index a43a3a090f9c..9ba5762aa0bb 100644 --- a/prdoc/pr_1933.prdoc +++ b/prdoc/pr_1933.prdoc @@ -27,13 +27,13 @@ crates: bump: none - name: polkadot-sdk bump: minor - - pallet-fast-unstake + - name: pallet-fast-unstake bump: none - - pallet-bags-list + - name: pallet-bags-list bump: minor - - westend-runtime + - name: westend-runtime bump: minor - - pallet-delegated-staking - bump: none - - pallet-nomination-pools-benchmarking + - name: pallet-delegated-staking bump: none + - name: pallet-nomination-pools-benchmarking + bump: minor diff --git a/substrate/frame/delegated-staking/Cargo.toml b/substrate/frame/delegated-staking/Cargo.toml index 3b122dc2e26c..5b95d2c15aab 100644 --- a/substrate/frame/delegated-staking/Cargo.toml +++ b/substrate/frame/delegated-staking/Cargo.toml @@ -30,6 +30,8 @@ pallet-nomination-pools = { path = "../nomination-pools" } pallet-balances = { path = "../balances" } pallet-timestamp = { path = "../timestamp" } pallet-staking-reward-curve = { path = "../staking/reward-curve" } +pallet-stake-tracker = { path = "../staking/stake-tracker" } +pallet-bags-list = { path = "../bags-list", default-features = false, features = ["try-runtime"] } frame-election-provider-support = { path = "../election-provider-support", default-features = false } [features] @@ -39,8 +41,10 @@ std = [ "frame-election-provider-support/std", "frame-support/std", "frame-system/std", + "pallet-bags-list/std", "pallet-balances/std", "pallet-nomination-pools/std", + "pallet-stake-tracker/std", "pallet-staking/std", "pallet-timestamp/std", "scale-info/std", @@ -54,8 +58,10 @@ runtime-benchmarks = [ "frame-election-provider-support/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-nomination-pools/runtime-benchmarks", + "pallet-stake-tracker/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", @@ -65,8 +71,10 @@ try-runtime = [ "frame-election-provider-support/try-runtime", "frame-support/try-runtime", "frame-system/try-runtime", + "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", "pallet-nomination-pools/try-runtime", + "pallet-stake-tracker/try-runtime", "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", "sp-runtime/try-runtime", diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index da2663c0ba7f..df16ad104b37 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -127,16 +127,42 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; - type TargetList = pallet_staking::UseValidatorsMap; + type TargetList = TargetBagsList; type NominationsQuota = pallet_staking::FixedNominationsQuota<16>; type MaxUnlockingChunks = ConstU32<10>; type MaxControllersInDeprecationBatch = ConstU32<100>; - type EventListeners = (Pools, DelegatedStaking); + type EventListeners = (StakeTracker, Pools, DelegatedStaking); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; } +const TARGET_THRESHOLDS: [Balance; 9] = [100, 200, 300, 400, 500, 600, 1_000, 2_000, 10_000]; +parameter_types! { + pub static TargetBagThresholds: &'static [Balance] = &TARGET_THRESHOLDS; +} + +type TargetBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = pallet_bags_list::Pallet; + type BagThresholds = TargetBagThresholds; + type Score = Balance; +} + +parameter_types! { + pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; +} + +impl pallet_stake_tracker::Config for Runtime { + type Currency = Balances; + type Staking = Staking; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = TargetBagsList; + type VoterUpdateMode = VoterUpdateMode; +} + parameter_types! { pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); pub const SlashRewardFraction: Perbill = Perbill::from_percent(10); @@ -192,6 +218,8 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp, Balances: pallet_balances, Staking: pallet_staking, + TargetBagsList: pallet_bags_list::, + StakeTracker: pallet_stake_tracker, Pools: pallet_nomination_pools, DelegatedStaking: delegated_staking, } @@ -236,13 +264,13 @@ impl ExtBuilder { GENESIS_NOMINATOR_ONE, GENESIS_NOMINATOR_ONE, 100, - sp_staking::StakerStatus::::Nominator(vec![1]), + sp_staking::StakerStatus::::Nominator(vec![GENESIS_VALIDATOR]), ), ( GENESIS_NOMINATOR_TWO, GENESIS_NOMINATOR_TWO, 200, - sp_staking::StakerStatus::::Nominator(vec![1]), + sp_staking::StakerStatus::::Nominator(vec![GENESIS_VALIDATOR]), ), ]; From f2613deb91e17d5782d18c3a7ab364009b701536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 6 Jun 2024 07:47:58 +0200 Subject: [PATCH 118/133] nit --- substrate/frame/staking/src/ledger.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/ledger.rs b/substrate/frame/staking/src/ledger.rs index 8c21d4918a32..6940ebe1474d 100644 --- a/substrate/frame/staking/src/ledger.rs +++ b/substrate/frame/staking/src/ledger.rs @@ -193,10 +193,7 @@ impl StakingLedger { return Err(Error::::NotStash) } - let controller = &self.controller().ok_or_else(|| { - defensive!("update called on a ledger that was not contructed via `StakingLedger` impl. unexpected."); - Error::::NotController - })?; + let controller = &self.controller().ok_or(Error::::BadState)?; // previous stake is the current stake in storage. let prev_stake = Ledger::::get(&controller).map(|ledger| ledger.stake()); From 8caac456e4f7a5bda9ba76186116eb8c4394f1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 6 Jun 2024 15:16:00 +0200 Subject: [PATCH 119/133] on_add_validator without option --- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 2 +- substrate/frame/staking/src/tests.rs | 6 +++--- substrate/frame/staking/stake-tracker/src/lib.rs | 4 ++-- substrate/frame/staking/stake-tracker/src/mock.rs | 2 +- substrate/frame/staking/stake-tracker/src/tests.rs | 2 +- substrate/primitives/staking/src/lib.rs | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 50249c692ab5..23dc6a13b815 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -320,7 +320,7 @@ impl OnStakingUpdate for EventTracker { v.push(OnStakingUpdateEvent::NominatorRemove { who: *who, nominations }); }) } - fn on_validator_add(who: &AccountId, self_stake: Option>) { + fn on_validator_add(who: &AccountId, self_stake: Stake) { EventsEmitted::mutate(|v| { v.push(OnStakingUpdateEvent::ValidatorAdd { who: *who, self_stake }); }) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5a22c8111ce5..f397673872ac 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1237,7 +1237,7 @@ impl Pallet { let self_stake = Self::stake(who); T::EventListeners::on_validator_add( who, - Some(self_stake.defensive_unwrap_or_default().into()), + self_stake.defensive_unwrap_or_default().into(), ); }; Validators::::insert(who, prefs); diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 1e9ed7f57e6e..f1ef4acc6088 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7406,9 +7406,9 @@ mod on_staking_update_events { bond_validator(12, 100); ensure_on_staking_updates_emitted(vec![ StakeUpdate { who: 11, prev_stake: None, stake: Stake { total: 100, active: 100 } }, - ValidatorAdd { who: 11, self_stake: Some(Stake { total: 100, active: 100 }) }, + ValidatorAdd { who: 11, self_stake: Stake { total: 100, active: 100 } }, StakeUpdate { who: 12, prev_stake: None, stake: Stake { total: 100, active: 100 } }, - ValidatorAdd { who: 12, self_stake: Some(Stake { total: 100, active: 100 }) }, + ValidatorAdd { who: 12, self_stake: Stake { total: 100, active: 100 } }, ]); // bond staker 21. @@ -7482,7 +7482,7 @@ mod on_staking_update_events { bond_validator(42, 100); ensure_on_staking_updates_emitted(vec![ StakeUpdate { who: 42, prev_stake: None, stake: Stake { total: 100, active: 100 } }, - ValidatorAdd { who: 42, self_stake: Some(Stake { total: 100, active: 100 }) }, + ValidatorAdd { who: 42, self_stake: Stake { total: 100, active: 100 } }, ]); // 42 bonds 50 extra. diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 3a8f05b2a116..5c7c8ac50791 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -339,8 +339,8 @@ impl OnStakingUpdate> for Pallet { // /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this /// method. - fn on_validator_add(who: &T::AccountId, self_stake: Option>>) { - let self_stake = Self::to_vote(self_stake.unwrap_or_default().active).into(); + fn on_validator_add(who: &T::AccountId, self_stake: Stake>) { + let self_stake = Self::to_vote(self_stake.active).into(); match T::TargetList::on_insert(who.clone(), self_stake) { Ok(_) => (), diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index f4270a55ce9a..1aa272803a82 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -377,7 +377,7 @@ pub(crate) fn add_validator(who: AccountId, self_stake: Balance) { v.insert(who, (stake, vec![])); }); - >::on_validator_add(&who, Some(stake)); + >::on_validator_add(&who, stake); } pub(crate) fn update_stake(who: AccountId, new: Balance, prev_stake: Option>) { diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 53e204f49abc..0f394e9120ba 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -357,7 +357,7 @@ fn on_validator_add_already_exists_works() { // noop >::on_validator_add( &10, - Some(Stake { total: 300, active: 300 }), + Stake { total: 300, active: 300 }, ); assert!(TargetBagsList::contains(&10)); assert_eq!(TargetBagsList::count(), 2); diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index e7bb03bb6eec..8328dd664633 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -153,7 +153,7 @@ pub trait OnStakingUpdate { /// Fired when someone sets their intention to validate. /// /// Note validator preference changes are not communicated, but could be added if needed. - fn on_validator_add(_who: &AccountId, _self_stake: Option>) {} + fn on_validator_add(_who: &AccountId, _self_stake: Stake) {} /// Fired when an existing validator updates their preferences. /// @@ -223,7 +223,7 @@ pub enum OnStakingUpdateEvent { }, ValidatorAdd { who: AccountId, - self_stake: Option>, + self_stake: Stake, }, ValidatorUpdate { who: AccountId, From b44a4e507f3ebabee65d6f19e532d19a8f1afd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 6 Jun 2024 18:29:42 +0200 Subject: [PATCH 120/133] doc improvements; drop dangling target fix; more tests --- substrate/frame/staking/src/pallet/impls.rs | 33 +++++--- substrate/frame/staking/src/pallet/mod.rs | 9 ++- substrate/frame/staking/src/tests.rs | 34 ++++++++ .../frame/staking/stake-tracker/src/lib.rs | 80 ++++++++++--------- 4 files changed, 108 insertions(+), 48 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index f397673872ac..c3d947fea693 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -414,7 +414,8 @@ impl Pallet { /// Removes dangling nominations from a nominator. /// /// If `maybe_target` is `None`, search for *all* dangling nominations and drop them. Otherwise - /// drop only one dangling target. + /// drop only one dangling target. If the new set of nominations without the dangling targets + /// is empry, the `nominator` is chilled. /// /// IMPORTANT NOTE: if `maybe_target` is set, it is assumed that the target is indeed dangling. /// No further checks are performed in this method. @@ -422,29 +423,41 @@ impl Pallet { nominator: &T::AccountId, target: Option<&T::AccountId>, ) -> Result>, DispatchError> { - let nominations_after = match (target, Self::status(&nominator)) { + let (size_before, nominations_after) = match (target, Self::status(&nominator)) { (None, Ok(StakerStatus::Nominator(nominations))) => { // target not set, filter out all non-validator nominations. - nominations - .into_iter() - .filter(|n| Self::status(n) == Ok(StakerStatus::Validator)) - .collect::>() + ( + nominations.len(), + nominations + .into_iter() + .filter(|n| Self::status(n) == Ok(StakerStatus::Validator)) + .collect::>(), + ) }, (Some(target), Ok(StakerStatus::Nominator(nominations))) => { debug_assert!(Self::status(&target).is_err() && T::TargetList::contains(&target),); - nominations.iter().cloned().filter(|n| n != target).collect::>() + ( + nominations.len(), + nominations.iter().cloned().filter(|n| n != target).collect::>(), + ) }, // not a nominator, return earlier. (_, _) => return Err(Error::::NotNominator.into()), }; - // no dangling nominations, return earlier. - if nominations_after.len().is_zero() { + // no dangling targets after all. + if nominations_after.len() == size_before { return Err(Error::::NotDanglingTarget.into()); } - ::nominate(nominator, nominations_after.clone())?; + if nominations_after.len().is_zero() { + // no valid nominations left, chill nominator. + ::chill(nominator)?; + } else { + // update the nominations without the dangling(s) nominations. + ::nominate(nominator, nominations_after.clone())?; + } Ok(BoundedVec::truncate_from(nominations_after)) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 210324259048..b7f193be7fdd 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1184,7 +1184,9 @@ pub mod pallet { /// Declare the desire to nominate `targets` for the origin controller. /// - /// Effects will be felt at the beginning of the next era. + /// The duplicate nominations will be implicitly removed. Only validators or idle stakers + /// are valid targets. If successful, the effects of this call will be felt at the beginning + /// of the next era. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// @@ -1218,7 +1220,7 @@ pub mod pallet { } } - ensure!(!targets.is_empty(), Error::::EmptyTargets); + // Check if maximum nominations quota is respected. ensure!( targets.len() <= T::NominationsQuota::get_quota(ledger.active) as usize, Error::::TooManyTargets @@ -1257,6 +1259,9 @@ pub mod pallet { .try_into() .map_err(|_| Error::::TooManyNominators)?; + // Ensure final target vec is not empty. + ensure!(!targets.is_empty(), Error::::EmptyTargets); + let nominations = Nominations { targets, // Initial nominations are considered submitted at era 0. See `Nominations` doc. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f1ef4acc6088..032cf6135d1a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8687,6 +8687,40 @@ mod stake_tracker { ); }) } + + #[test] + fn drop_dangling_nominations_chills_works() { + ExtBuilder::default().try_state(false).build_and_execute(|| { + // setup. + bond_validator(42, 10); + + assert_ok!(Staking::bond(RuntimeOrigin::signed(90), 500, RewardDestination::Staked)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(90), vec![42])); + + // 42 chills & unbonds completely. + assert_ok!(Staking::chill(RuntimeOrigin::signed(42))); + Ledger::::remove(42); + Bonded::::remove(42); + + // 90 is now nominating 42. + assert_ok!(Staking::status(&90), StakerStatus::Nominator(vec![42])); + // 42 is unbonded .. + assert!(Staking::status(&42).is_err()); + // .. and still part of the target list (thus dangling). + assert!(TargetBagsList::contains(&42)); + + // since 90 is *only* nominating a dangling target, it will be chilled after + // calling `drop_danlging_nomination`. + assert_ok!(Staking::drop_dangling_nomination(RuntimeOrigin::signed(1), 90, 42)); + assert_ok!(Staking::status(&90), StakerStatus::Idle); + assert!(!TargetBagsList::contains(&42)); + + assert_eq!( + *mock::staking_events().last().unwrap(), + Event::::DanglingNominationsDropped { nominator: 90, count: 1 }.into(), + ); + }) + } } mod ledger { diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 5c7c8ac50791..781793d10478 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -167,8 +167,9 @@ pub mod pallet { /// The staking interface. type Staking: StakingInterface; - /// A sorted list provider for staking voters that is kept up to date by this pallet. The - /// sorting by score depends on the sorting mode set by [`Self::VoterUpdateMode`]. + /// A sorted list provider for staking voters that is kept up to date by this pallet. + // [`Self::VoterUpdateMode`] defines whether this pallet will keep the voter list + // *strictly ordered* for every nominator stake updateor lazily ordered. type VoterList: SortedListProvider; /// A sorted list provider for staking targets that is ketp *always* sorted by the target's @@ -182,8 +183,8 @@ pub mod pallet { impl Pallet { /// Updates the stake of a voter. /// - /// It must ensure that there are no duplicate nominations to prevent over-counting the - /// stake approval. + /// NOTE: This method expects `nominations` to be deduplicated, otherwise the approvals + /// stakes of the duplicated target may become higher than expected silently. pub(crate) fn do_stake_update_voter( who: &T::AccountId, prev_stake: Option>>, @@ -247,7 +248,7 @@ pub mod pallet { // if target list does not contain target, add it and proceed. if !T::TargetList::contains(who) { T::TargetList::on_insert(who.clone(), Zero::zero()) - .expect("staker does not exist in the list as per check above; qed."); + .expect("staker does not yet exist in the list as per check above; qed."); } // update target score. @@ -298,7 +299,7 @@ pub mod pallet { /// Returns whether a nomination vec has duplicate targets. /// /// Used for debug assertions only, since this pallet expects the nominations to be - /// deduplicated. + /// deduplicated at all places. pub fn has_duplicate_nominations(mut v: Vec) -> bool { use sp_std::collections::btree_set::BTreeSet; let size_before = v.len(); @@ -334,11 +335,13 @@ impl OnStakingUpdate> for Pallet { } } - /// A validator is also considered a voter with self-vote and should also be added to + /// Triggered when a new validator is added to the system. + /// + /// Overview: If `who` is part of the target list, update its score. Otherwise, insert a new + /// node to the target list with self-stake as initial node score. + /// + /// A validator is also considered a voter with self-vote and should be added to /// [`Config::VoterList`]. - // - /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this - /// method. fn on_validator_add(who: &T::AccountId, self_stake: Stake>) { let self_stake = Self::to_vote(self_stake.active).into(); @@ -360,10 +363,12 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_add(who, vec![]) } - /// A validator has been chilled. The target node remains in the target list. + /// Triggered when a validator is chilled. /// - /// While idling, the target node is not removed from the target list but its score is - /// updated. + /// Overview: When chilled, the target node may not be removed from the target list. The + /// associated target list score is updated so that the self-stake is decreased from itself. If + /// the final target score drops to 0, the node is removed since we can guarantee that there are + /// no nominators voting for the chlled target. fn on_validator_idle(who: &T::AccountId) { let self_stake = Self::vote_of(who); Self::update_target_score(who, StakeImbalance::Negative(self_stake.into())); @@ -372,12 +377,14 @@ impl OnStakingUpdate> for Pallet { Self::on_nominator_idle(who, vec![]); } - /// A validator has been set as inactive/removed from the staking POV. + /// Triggered when a validator is set as inactive/removed by the staking system. /// - /// The target node is removed from the target list IFF its score is 0. Otherwise, its score - /// should be kept up to date as if the validator was active. + /// Overview: Updates the target list score so that `who`'s self-vote is decreased from itself. + /// The target node is removed from the target list IFF its score is 0 after update. Otherwise, + /// it means that there are "dangling" nominations to `who`, ie. there are nominators who are + /// nominating `who`. even though it is chilled/removed. fn on_validator_remove(who: &T::AccountId) { - // validator must be idle before removing completely. Perform some sanity checks too. + // validator must be idle before removing completely. match T::Staking::status(who) { Ok(StakerStatus::Idle) => (), // proceed Ok(StakerStatus::Validator) => Self::on_validator_idle(who), @@ -404,12 +411,12 @@ impl OnStakingUpdate> for Pallet { }; } - /// A nominator has been added to the system. + /// Triggered when a new nominator is added to the system. /// - /// Even in lazy mode, inserting voter list nodes on new nominator must be done. + /// Overview: Inserts a new node in the voter list with the score being `who`'s bonded stake. + /// The new node is inserted regardless of the [`Self::VoterUpdateMode`] set. /// - /// Note: it is assumed that `who`'s ledger staking state is updated *before* this method is - /// called. + /// Note: this method is also used locally when adding a new target (target is also a voter). fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); @@ -433,19 +440,18 @@ impl OnStakingUpdate> for Pallet { }; } - /// A nominator has been idle. From the `T::VotertList` PoV, chilling a nominator is the same as - /// removing it. + /// Triggered when a nominator is chilled. /// - /// Note: it is assumed that `who`'s staking ledger and `nominations` are up to date before - /// calling this method. + /// Overview: From this pallet POV, chilling a nominator is the same as removing it, since each + /// nominator only has self-stake as the voter list's node score. fn on_nominator_idle(who: &T::AccountId, nominations: Vec) { Self::on_nominator_remove(who, nominations); } - /// Fired when someone removes their intention to nominate and is completely removed from - /// the staking state. + /// Triggered when a nominator is removed (or chilled). /// - /// Even in lazy mode, removing voter list nodes on nominator remove must be done. + /// Overview: for each of `who`'s nomination targets, decrease `who`'s self-stake from their + /// score. In addition, remove `who`'s node from the voter list. /// /// Note: the number of nodes that are updated is bounded by the maximum number of /// nominators, which is defined in the staking pallet. @@ -464,12 +470,13 @@ impl OnStakingUpdate> for Pallet { ); } - /// This is called when a nominator updates their nominations. The nominator's stake remains - /// the same (updates to the nominator's stake should emit [`Self::on_stake_update`] - /// instead). However, the score of the nominated targets must be updated accordingly. + /// Triggered when a nominator updates their nominations. + /// + /// Overview: The approval scores of the the targets affected by the nomination updates must be + /// updated accordingly. /// - /// Note: it is assumed that `who`'s ledger staking state is updated *before* calling this - /// method. + /// Note that the nominator's stake remains the same (updates to the nominator's stake should + /// emit [`Self::on_stake_update`] instead). fn on_nominator_update( who: &T::AccountId, prev_nominations: Vec, @@ -494,11 +501,12 @@ impl OnStakingUpdate> for Pallet { } } - /// This is called when a staker is slashed. + /// Triggered when a staker (nominator/validator) is slashed. /// - /// From the stake-tracker POV, no direct changes should be made to the target or voter list in + /// From the stake-tracker POV, no direct updates should be made to the target or voter list in /// this event handler, since the stake updates from a slash will be indirectly performed - /// through the call to `on_stake_update`. + /// through the call to `on_stake_update` resulting from the slash performed at a higher level + /// (i.e. by staking). /// /// However, if a slash of a nominator results on its active stake becoming 0, the stake /// tracker *requests* the staking interface to chill the nominator in order to ensure that From 66f8259b36e6090e6cc8513b01c6a55011098c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 13 Jun 2024 15:00:08 +0200 Subject: [PATCH 121/133] addresses review --- .../election-provider-support/src/lib.rs | 4 +- substrate/frame/staking/src/pallet/impls.rs | 10 +++++ .../frame/staking/stake-tracker/src/lib.rs | 42 +++++++++---------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 2ce79b54ccad..91e67c353b90 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -570,9 +570,7 @@ pub trait SortedListProvider { /// /// Returns a boolean and it is only available in the context of `try-runtime` checks. #[cfg(feature = "try-runtime")] - fn in_position(_id: &AccountId) -> Result { - unimplemented!() - } + fn in_position(_id: &AccountId) -> Result; /// Check internal state of the list. Only meant for debugging. #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index c3d947fea693..a8ad52f0e970 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1808,6 +1808,11 @@ impl SortedListProvider for UseValidatorsMap { fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { unimplemented!() } + + #[cfg(feature = "try-runtime")] + fn in_position(_id: &T::AccountId) -> Result { + unimplemented!() + } } /// A simple voter list implementation that does not require any additional pallets. Note, this @@ -1883,6 +1888,11 @@ impl SortedListProvider for UseNominatorsAndValidatorsM fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { unimplemented!() } + + #[cfg(feature = "try-runtime")] + fn in_position(_id: &T::AccountId) -> Result { + unimplemented!() + } } impl StakingInterface for Pallet { diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 781793d10478..d9a997046535 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -136,7 +136,7 @@ impl StakeImbalance { pub enum VoterUpdateMode { /// All score update events will be automatically reflected in the sorted list. Strict, - /// Score update events are *not* be automatically reflected in the sorted list. Howeber, node + /// Score update events are *not* be automatically reflected in the sorted list. However, node /// insertion and removals are reflected in the list. Lazy, } @@ -191,7 +191,7 @@ pub mod pallet { stake: Stake>, nominations: Vec, ) { - debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + defensive_assert!(!Self::has_duplicate_nominations(nominations.clone())); let voter_weight = Self::to_vote(stake.active); @@ -247,8 +247,9 @@ pub mod pallet { ) { // if target list does not contain target, add it and proceed. if !T::TargetList::contains(who) { - T::TargetList::on_insert(who.clone(), Zero::zero()) - .expect("staker does not yet exist in the list as per check above; qed."); + let _ = T::TargetList::on_insert(who.clone(), Zero::zero()).defensive_proof( + "staker does not yet exist in the list as per check above; qed.", + ); } // update target score. @@ -349,8 +350,8 @@ impl OnStakingUpdate> for Pallet { Ok(_) => (), Err(_) => { // if the target already exists in the list, it means that the target is idle - // and/or is dangling. - debug_assert!( + // and/or is dangling and now it's becoming active again. + defensive_assert!( T::Staking::status(who) == Ok(StakerStatus::Idle) || T::Staking::status(who).is_err() ); @@ -360,21 +361,19 @@ impl OnStakingUpdate> for Pallet { } // a validator is also a nominator. - Self::on_nominator_add(who, vec![]) + Self::on_nominator_add(who, vec![who.clone()]) } /// Triggered when a validator is chilled. /// /// Overview: When chilled, the target node may not be removed from the target list. The - /// associated target list score is updated so that the self-stake is decreased from itself. If - /// the final target score drops to 0, the node is removed since we can guarantee that there are - /// no nominators voting for the chlled target. + /// associated target list score is updated so that the self-stake is decreased from itself. + /// + /// This method will not *try* to remove the target from the target list. That is the + /// responsability of [`OnStakingUpdate::on_validator_remove`]. fn on_validator_idle(who: &T::AccountId) { - let self_stake = Self::vote_of(who); - Self::update_target_score(who, StakeImbalance::Negative(self_stake.into())); - - // validator is a nominator too. - Self::on_nominator_idle(who, vec![]); + // validator is a validator with itself as a nomination. + Self::on_nominator_idle(who, vec![who.clone()]); } /// Triggered when a validator is set as inactive/removed by the staking system. @@ -403,7 +402,8 @@ impl OnStakingUpdate> for Pallet { // active nominations, thus we keep it in the target list with corresponding approval // stake. if score.is_zero() { - T::TargetList::on_remove(who).expect("target exists as per above; qed"); + let _ = T::TargetList::on_remove(who) + .defensive_proof("target exists as per above; qed"); } } else { // target is not part of the list. Given the contract with staking and the checks above, @@ -414,11 +414,11 @@ impl OnStakingUpdate> for Pallet { /// Triggered when a new nominator is added to the system. /// /// Overview: Inserts a new node in the voter list with the score being `who`'s bonded stake. - /// The new node is inserted regardless of the [`Self::VoterUpdateMode`] set. + /// The new node is inserted regardless of the [`crate::VoterUpdateMode`] set. /// /// Note: this method is also used locally when adding a new target (target is also a voter). fn on_nominator_add(who: &T::AccountId, nominations: Vec>) { - debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + defensive_assert!(!Self::has_duplicate_nominations(nominations.clone())); let nominator_vote = Self::vote_of(who); @@ -456,7 +456,7 @@ impl OnStakingUpdate> for Pallet { /// Note: the number of nodes that are updated is bounded by the maximum number of /// nominators, which is defined in the staking pallet. fn on_nominator_remove(who: &T::AccountId, nominations: Vec) { - debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + defensive_assert!(!Self::has_duplicate_nominations(nominations.clone())); let nominator_vote = Self::vote_of(who); @@ -482,8 +482,8 @@ impl OnStakingUpdate> for Pallet { prev_nominations: Vec, nominations: Vec, ) { - debug_assert!(!Self::has_duplicate_nominations(prev_nominations.clone())); - debug_assert!(!Self::has_duplicate_nominations(nominations.clone())); + defensive_assert!(!Self::has_duplicate_nominations(prev_nominations.clone())); + defensive_assert!(!Self::has_duplicate_nominations(nominations.clone())); let nominator_vote = Self::vote_of(who); From ea9e8385af133881d01ff194c62333a4b1db1f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 14 Jun 2024 13:11:21 +0200 Subject: [PATCH 122/133] simplifies dedup --- .../src/migrations/v13_stake_tracker/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index c67486dbcdf8..8e0a69868186 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -259,18 +259,18 @@ impl MigrationV13 { SteppedMigrationError::Failed ); - let mut raw_targets = raw_nominations.targets.into_inner(); + let raw_targets = raw_nominations.targets.into_inner(); let count_before = raw_targets.len(); - // remove duplicate nominations. - let dedup_noms: Vec = - raw_targets.drain(..).collect::>().into_iter().collect::>(); - // remove all non-validator nominations. - let targets = dedup_noms + let targets: Vec = raw_targets + // dedup nominations. + .into_iter() + .collect::>() .into_iter() + // remove all non-validator nominations. .filter(|n| Pallet::::status(n) == Ok(StakerStatus::Validator)) - .collect::>(); + .collect(); if targets.len() == 0 { // if no nominations are left, chill the nominator. From 0fda93d483094353863306e49316347188a15dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 17 Jul 2024 12:48:29 +0200 Subject: [PATCH 123/133] compilation nits after merge; addresses review comments. --- Cargo.lock | 141 ++++++++---------- .../test-staking-e2e/src/mock.rs | 3 +- .../election-provider-support/src/lib.rs | 4 +- substrate/frame/staking/src/lib.rs | 16 +- substrate/frame/staking/src/pallet/impls.rs | 12 +- substrate/frame/staking/src/pallet/mod.rs | 4 +- substrate/frame/staking/src/tests.rs | 2 +- .../frame/staking/stake-tracker/src/lib.rs | 26 +--- 8 files changed, 98 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 006944bca19f..a46c91ebee61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1108,14 +1108,14 @@ dependencies = [ "concurrent-queue", "event-listener-strategy", "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" dependencies = [ "async-task", "concurrent-queue", @@ -1207,7 +1207,7 @@ checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ "event-listener 5.3.1", "event-listener-strategy", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -1240,9 +1240,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" dependencies = [ "async-io 2.3.3", "async-lock 3.4.0", @@ -1277,7 +1277,7 @@ dependencies = [ "log", "memchr", "once_cell", - "pin-project-lite 0.2.14", + "pin-project-lite", "pin-utils", "slab", "wasm-bindgen-futures", @@ -1291,7 +1291,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -1332,7 +1332,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -1650,9 +1650,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d08263faac5cde2a4d52b513dadb80846023aade56fcd8fc99ba73ba8050e92" +checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" dependencies = [ "arrayref", "arrayvec 0.7.4", @@ -2518,13 +2518,12 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9711f33475c22aab363b05564a17d7b789bf3dfec5ebabb586adee56f0e271b5" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] @@ -5357,7 +5356,7 @@ checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -5368,7 +5367,7 @@ checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -5378,7 +5377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ "event-listener 5.3.1", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -6257,7 +6256,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite", "waker-fn", ] @@ -6271,7 +6270,7 @@ dependencies = [ "futures-core", "futures-io", "parking", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -6326,7 +6325,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.14", + "pin-project-lite", "pin-utils", "slab", ] @@ -6806,7 +6805,7 @@ checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http 0.2.12", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -6829,7 +6828,7 @@ dependencies = [ "futures-util", "http 1.1.0", "http-body 1.0.1", - "pin-project-lite 0.2.14", + "pin-project-lite", ] [[package]] @@ -6866,7 +6865,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.14", + "pin-project-lite", "socket2 0.5.7", "tokio", "tower-service", @@ -6889,7 +6888,7 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.14", + "pin-project-lite", "smallvec", "tokio", "want", @@ -6941,7 +6940,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "hyper 1.4.1", - "pin-project-lite 0.2.14", + "pin-project-lite", "socket2 0.5.7", "tokio", "tower", @@ -8135,9 +8134,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3facf0691bab65f571bc97c6c65ffa836248ca631d631b7691ac91deb7fceb5f" +checksum = "004ee9c4a4631435169aee6aad2f62e3984dc031c43b6d29731e8e82a016c538" dependencies = [ "either", "futures", @@ -8146,9 +8145,10 @@ dependencies = [ "libp2p-identity", "log", "parking_lot 0.12.3", - "quicksink", + "pin-project-lite", "rw-stream-sink", - "soketto 0.7.1", + "soketto 0.8.0", + "thiserror", "url", "webpki-roots 0.25.4", ] @@ -12455,7 +12455,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -12862,12 +12862,6 @@ dependencies = [ "syn 2.0.71", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.14" @@ -15286,7 +15280,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.14", + "pin-project-lite", "windows-sys 0.48.0", ] @@ -15299,7 +15293,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi 0.4.0", - "pin-project-lite 0.2.14", + "pin-project-lite", "rustix 0.38.34", "tracing", "windows-sys 0.52.0", @@ -15866,17 +15860,6 @@ dependencies = [ "rand", ] -[[package]] -name = "quicksink" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" -dependencies = [ - "futures-core", - "futures-sink", - "pin-project-lite 0.1.12", -] - [[package]] name = "quinn" version = "0.9.4" @@ -15884,7 +15867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" dependencies = [ "bytes", - "pin-project-lite 0.2.14", + "pin-project-lite", "quinn-proto 0.9.6", "quinn-udp 0.3.2", "rustc-hash", @@ -15903,7 +15886,7 @@ checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", "futures-io", - "pin-project-lite 0.2.14", + "pin-project-lite", "quinn-proto 0.10.6", "quinn-udp 0.4.1", "rustc-hash", @@ -16058,9 +16041,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.0.2" +version = "11.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" +checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" dependencies = [ "bitflags 2.6.0", ] @@ -16143,9 +16126,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags 2.6.0", ] @@ -16371,7 +16354,7 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project-lite 0.2.14", + "pin-project-lite", "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", @@ -20283,7 +20266,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -20343,7 +20326,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "proc-macro2 1.0.86", "quote 1.0.36", @@ -20362,7 +20345,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.25.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "environmental", "parity-scale-codec", @@ -20595,7 +20578,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -20626,7 +20609,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "Inflector", "expander", @@ -20753,7 +20736,7 @@ version = "14.0.0" [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" [[package]] name = "sp-storage" @@ -20769,7 +20752,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "19.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "impl-serde", "parity-scale-codec", @@ -20814,7 +20797,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "parity-scale-codec", "tracing", @@ -20911,7 +20894,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#4aa29a41cf731b8181f03168240e8dedb2adfa7a" +source = "git+https://github.com/paritytech/polkadot-sdk#739951991f14279a7dc05d42c29ccf57d3740a4c" dependencies = [ "impl-trait-for-tuples", "log", @@ -22264,9 +22247,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.0" +version = "1.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" dependencies = [ "backtrace", "bytes", @@ -22274,7 +22257,7 @@ dependencies = [ "mio", "num_cpus", "parking_lot 0.12.3", - "pin-project-lite 0.2.14", + "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", @@ -22331,7 +22314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", - "pin-project-lite 0.2.14", + "pin-project-lite", "tokio", "tokio-util", ] @@ -22374,7 +22357,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.14", + "pin-project-lite", "tokio", ] @@ -22452,7 +22435,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project", - "pin-project-lite 0.2.14", + "pin-project-lite", "tokio", "tower-layer", "tower-service", @@ -22470,7 +22453,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "pin-project-lite 0.2.14", + "pin-project-lite", "tower-layer", "tower-service", ] @@ -22494,7 +22477,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", - "pin-project-lite 0.2.14", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -23161,9 +23144,9 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.213.0" +version = "0.214.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850e4e6a56413a8f33567741a2388c8f6dafd841a939d945c7248671a8739dd8" +checksum = "ff694f02a8d7a50b6922b197ae03883fbf18cdb2ae9fbee7b6148456f5f44041" dependencies = [ "leb128", ] @@ -23519,9 +23502,9 @@ dependencies = [ [[package]] name = "wast" -version = "213.0.0" +version = "214.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd051172bc72db3567b039f710f27d6d80f358b8333088eb4c4c12dac2a4d993" +checksum = "694bcdb24c49c8709bd8713768b71301a11e823923eee355d530f1d8d0a7f8e9" dependencies = [ "bumpalo", "leb128", @@ -23532,9 +23515,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.213.0" +version = "1.214.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be77619385eca699d204399d2ffc9b1dfda1df3320266773d2d664ecb06cf3e" +checksum = "347249eb56773fa728df2656cfe3a8c19437ded61a922a0b5e0839d9790e278e" dependencies = [ "wast", ] diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index 0aa02998ae3f..0162d966e65f 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -107,6 +107,7 @@ parameter_types! { #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Runtime { + type Balance = Balance; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type MaxFreezes = VariantCountOf; @@ -251,7 +252,7 @@ impl pallet_bags_list::Config for Runtime { type WeightInfo = (); type ScoreProvider = pallet_bags_list::Pallet; type BagThresholds = TargetBagThresholds; - type Score = u128; + type Score = Balance; } parameter_types! { diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 91e67c353b90..2ce79b54ccad 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -570,7 +570,9 @@ pub trait SortedListProvider { /// /// Returns a boolean and it is only available in the context of `try-runtime` checks. #[cfg(feature = "try-runtime")] - fn in_position(_id: &AccountId) -> Result; + fn in_position(_id: &AccountId) -> Result { + unimplemented!() + } /// Check internal state of the list. Only meant for debugging. #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index ac24e744c544..31a9db07f87a 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -322,7 +322,7 @@ use sp_runtime::{ use sp_staking::{ offence::{Offence, OffenceError, ReportOffence}, EraIndex, ExposurePage, OnStakingUpdate, Page, PagedExposureMetadata, SessionIndex, - StakingAccount, + StakingAccount, StakingInterface, }; pub use sp_staking::{Exposure, IndividualExposure, StakerStatus}; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; @@ -585,6 +585,9 @@ impl StakingLedger { /// /// `slash_era` is the era in which the slash (which is being enacted now) actually happened. /// + /// If a slashed staker is a nominator and drops its stake to zero after slash, the staker is + /// chilled to ensure that their nominations are dropped in the stake tracker. + /// /// This calls `Config::OnStakingUpdate::on_slash` with information as to how the slash was /// applied. pub fn slash( @@ -703,6 +706,17 @@ impl StakingLedger { let final_slashed_amount = pre_slash_total.saturating_sub(self.total); + // If the slashed stash is a nominator and it's active stake is zero after the slash is + // applied, chill the staker. this is important in order to ensure that nominations are + // dropped in the stake-tracker. This way, we ensure that in the event of a validator and + // all its nominators are 100% slashed, the target can be reaped/killed without leaving + // nominations behind. + if let (true, Ok(StakerStatus::Nominator(_))) = + (self.active.is_zero(), Pallet::::status(&self.stash)) + { + Pallet::::chill_stash(&self.stash); + }; + T::EventListeners::on_slash( &self.stash, self.active, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a09c97321574..34eeefc8fcc6 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1806,7 +1806,8 @@ impl SortedListProvider for UseValidatorsMap { #[cfg(feature = "try-runtime")] fn in_position(_id: &T::AccountId) -> Result { - unimplemented!() + // No sorting provided by this impl, thus the account is always in position. + Ok(true) } #[cfg(feature = "runtime-benchmarks")] @@ -1886,7 +1887,8 @@ impl SortedListProvider for UseNominatorsAndValidatorsM #[cfg(feature = "try-runtime")] fn in_position(_id: &T::AccountId) -> Result { - unimplemented!() + // No sorting provided by this impl, thus the account is always in position. + Ok(true) } #[cfg(feature = "runtime-benchmarks")] @@ -2233,13 +2235,15 @@ impl Pallet { ensure!( ::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) - .count() as u32 == Nominators::::count() + Validators::::count(), + .count() as u32 == + Nominators::::count() + Validators::::count(), "wrong external count (VoterList.count != Nominators.count + Validators.count)" ); ensure!( ::TargetList::iter() .filter(|t| Self::status(&t) == Ok(StakerStatus::Validator)) - .count() as u32 == Validators::::count(), + .count() as u32 == + Validators::::count(), "wrong external count (TargetList.count != Validators.count)" ); ensure!( diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 25bd36bbc8f2..8565975ad176 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1248,8 +1248,8 @@ pub mod pallet { /// Declare the desire to nominate `targets` for the origin controller. /// /// The duplicate nominations will be implicitly removed. Only validators or idle stakers - /// are valid targets. If successful, the effects of this call will be felt at the beginning - /// of the next era. + /// are valid targets. If successful, the effects of this call will be felt at the + /// beginning of the next era. /// /// The dispatch origin for this call must be _Signed_ by the controller, not the stash. /// diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 26904edff52a..d78f650fd180 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -9319,7 +9319,7 @@ mod ledger_recovery { assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK assert!(Payee::::get(&333).is_some()); // OK - // however, ledger associated with its controller was killed. + // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK // side effects on 444 - ledger, bonded, payee, lock should be completely removed. diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index d9a997046535..cd4e30b713f2 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -95,7 +95,7 @@ use frame_support::{ pallet_prelude::*, traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; -use sp_runtime::traits::{Saturating, Zero}; +use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; @@ -501,38 +501,22 @@ impl OnStakingUpdate> for Pallet { } } + // no-op events. + /// Triggered when a staker (nominator/validator) is slashed. /// /// From the stake-tracker POV, no direct updates should be made to the target or voter list in /// this event handler, since the stake updates from a slash will be indirectly performed /// through the call to `on_stake_update` resulting from the slash performed at a higher level /// (i.e. by staking). - /// - /// However, if a slash of a nominator results on its active stake becoming 0, the stake - /// tracker *requests* the staking interface to chill the nominator in order to ensure that - /// their nominations are dropped. This way, we ensure that in the event of a validator and all - /// its nominators are 100% slashed, the target can be reaped/killed without leaving - /// nominations behind. fn on_slash( - stash: &T::AccountId, + _stash: &T::AccountId, _slashed_active: BalanceOf, _slashed_unlocking: &BTreeMap>, - slashed_total: BalanceOf, + _slashed_total: BalanceOf, ) { - let active_after_slash = T::Staking::stake(stash) - .defensive_unwrap_or_default() - .active - .saturating_sub(slashed_total); - - if let (true, Ok(StakerStatus::Nominator(_))) = - (active_after_slash.is_zero(), T::Staking::status(stash)) - { - let _ = T::Staking::chill(stash).defensive(); - }; } - // no-op events. - /// The score of the staker `who` is updated through the `on_stake_update` calls following the /// full unstake (ledger kill). fn on_unstake(_who: &T::AccountId) {} From 62a3e5c7b0eb82652f309a007fa85d7d304c500c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 17 Jul 2024 18:48:17 +0200 Subject: [PATCH 124/133] removes unecessary staking::status calls in stake-tracker --- .../frame/staking/stake-tracker/src/lib.rs | 22 +++++++------------ .../frame/staking/stake-tracker/src/mock.rs | 1 + .../frame/staking/stake-tracker/src/tests.rs | 10 --------- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index cd4e30b713f2..91a043ddcf82 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -382,20 +382,13 @@ impl OnStakingUpdate> for Pallet { /// The target node is removed from the target list IFF its score is 0 after update. Otherwise, /// it means that there are "dangling" nominations to `who`, ie. there are nominators who are /// nominating `who`. even though it is chilled/removed. + /// + /// Note: `who` *MUST* be either an active validator or chilled staker. fn on_validator_remove(who: &T::AccountId) { - // validator must be idle before removing completely. - match T::Staking::status(who) { - Ok(StakerStatus::Idle) => (), // proceed - Ok(StakerStatus::Validator) => Self::on_validator_idle(who), - Ok(StakerStatus::Nominator(_)) => { - defensive!("on_validator_remove called on a nominator, unexpected."); - return - }, - Err(_) => { - defensive!("on_validator_remove called on a non-existing target."); - return - }, - }; + debug_assert!( + T::Staking::status(who) == Ok(StakerStatus::Validator) || + T::Staking::status(who) == Ok(StakerStatus::Idle) + ); if let Ok(score) = T::TargetList::get_score(who) { // remove from target list IIF score is zero. If `score != 0`, the target still has @@ -430,7 +423,8 @@ impl OnStakingUpdate> for Pallet { ); // if `who` is a nominator, update the vote weight of the nominations if they exist. Note: - // this will update the score of up to `T::MaxNominations` validators. + // this will update the score of up to `T::MaxNominations` validators. Note that `who` may + // be a validator. match T::Staking::status(who).defensive() { Ok(StakerStatus::Nominator(_)) => for t in nominations { diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index 1aa272803a82..e0966c94ca9c 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -432,6 +432,7 @@ pub(crate) fn remove_staker(who: AccountId) { }); }, Ok(StakerStatus::Validator) => { + >::on_validator_idle(&who); >::on_validator_remove(&who); TestValidators::mutate(|v| v.remove(&who)); }, diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 0f394e9120ba..b53c670b0491 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -405,17 +405,7 @@ fn on_nominator_remove_defensive_works() { }) } -#[test] -#[should_panic = "Defensive failure has been triggered!: \"on_validator_remove called on a non-existing target.\""] -fn on_validator_remove_defensive_works() { - ExtBuilder::default().build_and_execute(|| { - assert!(!TargetBagsList::contains(&1)); - >::on_validator_remove(&1); - }) -} - mod staking_integration { - use super::*; #[test] From 19abad855c2d1b99a3d4115db06a74ea5b5cc34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 17 Jul 2024 19:14:05 +0200 Subject: [PATCH 125/133] merge nits: removes sp_std --- .../test-staking-e2e/src/mock.rs | 2 +- substrate/frame/staking/src/migrations/single_block.rs | 1 - .../frame/staking/src/migrations/v13_stake_tracker/mod.rs | 3 +-- substrate/frame/staking/src/pallet/impls.rs | 4 ++-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index ce268b6e5275..f71d907b5cc0 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -607,7 +607,7 @@ impl ExtBuilder { let mut ext = sp_io::TestExternalities::from(storage); - // We consider all test to start after timestamp is initialized This must be ensured by + // We consider all test to start after timestamp is initialized. This must be ensured by // having `timestamp::on_initialize` called before `staking::on_initialize`. ext.execute_with(|| { System::set_block_number(1); diff --git a/substrate/frame/staking/src/migrations/single_block.rs b/substrate/frame/staking/src/migrations/single_block.rs index 2c29440447e7..4217d797b45b 100644 --- a/substrate/frame/staking/src/migrations/single_block.rs +++ b/substrate/frame/staking/src/migrations/single_block.rs @@ -30,7 +30,6 @@ use frame_support::{ weights::Weight, }; use sp_runtime::{traits::Zero, RuntimeDebug}; -use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 8e0a69868186..b2d4386b8404 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -31,7 +31,6 @@ use frame_support::{ }; use scale_info::TypeInfo; use sp_staking::StakingInterface; -use sp_std::prelude::*; #[cfg(test)] mod tests; @@ -252,7 +251,7 @@ impl MigrationV13 { who: &T::AccountId, raw_nominations: Nominations, ) -> Result, SteppedMigrationError> { - use sp_std::collections::btree_set::BTreeSet; + use alloc::collections::btree_set::BTreeSet; ensure!( Pallet::::status(who).map(|x| x.is_nominator()).unwrap_or(false), diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 6f08a9f6a444..68f2bfec3bf6 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2396,7 +2396,7 @@ impl Pallet { /// * Checks that each nominator has its entire stake correctly distributed. /// * Nominations do not have duplicate targets. fn check_nominators() -> Result<(), TryRuntimeError> { - use sp_std::collections::btree_set::BTreeSet; + use alloc::collections::btree_set::BTreeSet; // a check per nominator to ensure their entire stake is correctly distributed. Will only // kick-in if the nomination was submitted before the current era. @@ -2522,7 +2522,7 @@ impl Pallet { /// * The number of target nodes in the target list matches the number of /// (active_validators + idle_validators + dangling_targets_score_with_score). pub fn do_try_state_approvals() -> Result<(), sp_runtime::TryRuntimeError> { - use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; + use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; let mut approvals_map: BTreeMap = BTreeMap::new(); // build map of approvals stakes from the `Nominators` storage map POV. From cb631fa66980acc55d1f756af23de4b0be4c0c88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 17 Jul 2024 23:54:20 +0200 Subject: [PATCH 126/133] fixes dependencies on mmbs without sp_std --- substrate/frame/staking/src/migrations/single_block.rs | 1 + substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/substrate/frame/staking/src/migrations/single_block.rs b/substrate/frame/staking/src/migrations/single_block.rs index 4217d797b45b..a43fa30c8c52 100644 --- a/substrate/frame/staking/src/migrations/single_block.rs +++ b/substrate/frame/staking/src/migrations/single_block.rs @@ -31,6 +31,7 @@ use frame_support::{ }; use sp_runtime::{traits::Zero, RuntimeDebug}; +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index b2d4386b8404..68715bb9f456 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -21,6 +21,7 @@ use super::PALLET_MIGRATIONS_ID; use crate::{log, weights, Config, Nominations, Nominators, Pallet, StakerStatus, Validators}; +use alloc::vec::Vec; use codec::{Decode, Encode, MaxEncodedLen}; use core::marker::PhantomData; use frame_election_provider_support::{SortedListProvider, VoteWeight}; From f591b8938c13e74d2722fdf080e0167bb6be1b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 18 Jul 2024 10:51:36 +0200 Subject: [PATCH 127/133] use crv2 in stake-tracker mock --- .../frame/staking/stake-tracker/src/mock.rs | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index e0966c94ca9c..b326ba52e697 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -30,16 +30,37 @@ pub(crate) type Balance = u64; type Block = frame_system::mocking::MockBlockU32; // Configure a mock runtime to test the pallet. -frame_support::construct_runtime!( - pub enum Test - { - System: frame_system, - Balances: pallet_balances, - VoterBagsList: pallet_bags_list::, - TargetBagsList: pallet_bags_list::, - StakeTracker: pallet_stake_tracker, - } -); +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Test; + + #[runtime::pallet_index(0)] + pub type System = frame_system::Pallet; + + #[runtime::pallet_index(1)] + pub type Balances = pallet_balances::Pallet; + + #[runtime::pallet_index(2)] + pub type StakeTracker = pallet_stake_tracker::Pallet; + + #[runtime::pallet_index(3)] + pub type VoterBagsList = pallet_bags_list::Pallet; + + #[runtime::pallet_index(4)] + pub type TargetBagsList = pallet_bags_list::Pallet; +} parameter_types! { pub static ExistentialDeposit: Balance = 1; From 8b0dec27a616dc8ab985e9aafa02920ff04f3b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 18 Jul 2024 23:32:11 +0200 Subject: [PATCH 128/133] Improves MMB docs and naming --- .../runtime/westend/src/weights/pallet_staking.rs | 2 +- substrate/frame/staking/src/benchmarking.rs | 11 +++++++---- .../staking/src/migrations/v13_stake_tracker/mod.rs | 12 +++++++----- .../src/migrations/v13_stake_tracker/tests.rs | 4 ++-- substrate/frame/staking/src/weights.rs | 6 +++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/polkadot/runtime/westend/src/weights/pallet_staking.rs b/polkadot/runtime/westend/src/weights/pallet_staking.rs index 2b3f5a3c2d56..6fe38f233a16 100644 --- a/polkadot/runtime/westend/src/weights/pallet_staking.rs +++ b/polkadot/runtime/westend/src/weights/pallet_staking.rs @@ -972,7 +972,7 @@ impl pallet_staking::WeightInfo for WeightInfo { /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn v13_mmb_step() -> Weight { + fn v13_mmb_partial_step() -> Weight { // Proof Size summary in bytes: // Measured: `167522` // Estimated: `2645990` diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 7ca803cd315f..7592576d78fd 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1158,16 +1158,19 @@ mod benchmarks { Ok(()) } - /// Multi-block step benchmark for v13 stake-tracker migration. + /// Multi-block (partial) step benchmark for v13 stake-tracker migration. /// - /// The setup benchmarks the worst case scenario of a *single-step* of the migration. A single - /// step of this MMB migration consists of migrating one nominator, i.e. fetch all the + /// The setup benchmarks the worst case scenario of a *partial-step* of the MMB migration. The + /// partial step of this MMB migration consists of migrating one nominator, i.e. fetch all the /// nominated targets of one nominator and add them to the target list. /// The worst case scenario case should consider potential rebaggings done internally by the /// sorted list provider, thus we populate the target list with 1000 validators before the /// migration. + /// + /// Note: a MMB migration step may include *several* partial steps, so each block during MMBs + /// progresses as much as possible. #[benchmark] - fn v13_mmb_step() { + fn v13_mmb_partial_step() { let mut meter = WeightMeter::new(); let n_validators = 1000; diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs index 68715bb9f456..18090e80becc 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/mod.rs @@ -96,15 +96,17 @@ impl SteppedMigration for MigrationV13 mut cursor: Option, meter: &mut frame_support::weights::WeightMeter, ) -> Result, SteppedMigrationError> { - let required = W::v13_mmb_step(); + // Worst-case scenario weight required to process one nominator or validator. + let partial_step_weight = W::v13_mmb_partial_step(); // If there's no enough weight left in the block for a migration step, return an error. - if meter.remaining().any_lt(required) { - return Err(SteppedMigrationError::InsufficientWeight { required }); + if meter.remaining().any_lt(partial_step_weight) { + return Err(SteppedMigrationError::InsufficientWeight { required: partial_step_weight }); } - // do as much progress as possible per step. - while meter.try_consume(required).is_ok() { + // Do as much progress as possible per step. As far as the meter allows, keeps processing + // the partial steps (i.e. migrating one nominator/validator). + while meter.try_consume(partial_step_weight).is_ok() { let new_cursor = match cursor { None => { // start processing first nominator. diff --git a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs index 3747c1ecdf0a..e8724c835e20 100644 --- a/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs +++ b/substrate/frame/staking/src/migrations/v13_stake_tracker/tests.rs @@ -45,7 +45,7 @@ fn mb_migration_target_list_simple_works() { // allocate 3 steps per block to do the full migration in one step. let limit = ::WeightInfo::progress_mbms_none() + pallet_migrations::Pallet::::exec_migration_max_weight() + - SubstrateWeight::::v13_mmb_step() * 3; + SubstrateWeight::::v13_mmb_partial_step() * 3; MigratorServiceWeight::set(&limit); // migrate 3 nominators. @@ -81,7 +81,7 @@ fn mb_migration_target_list_multiple_steps_works() { // allocate 1 step (i.e. 1 nominator) per block. let limit = ::WeightInfo::progress_mbms_none() + pallet_migrations::Pallet::::exec_migration_max_weight() + - SubstrateWeight::::v13_mmb_step(); + SubstrateWeight::::v13_mmb_partial_step(); MigratorServiceWeight::set(&limit); AllPalletsWithSystem::on_runtime_upgrade(); // onboard MBMs diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index b2617c57dfc3..dabfba49bdca 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -82,7 +82,7 @@ pub trait WeightInfo { fn set_min_commission() -> Weight; fn restore_ledger() -> Weight; fn drop_dangling_nomination() -> Weight; - fn v13_mmb_step() -> Weight; + fn v13_mmb_partial_step() -> Weight; } /// Weights for `pallet_staking` using the Substrate node and recommended hardware. @@ -973,7 +973,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn v13_mmb_step() -> Weight { + fn v13_mmb_partial_step() -> Weight { // Proof Size summary in bytes: // Measured: `70141` // Estimated: `477090` @@ -1871,7 +1871,7 @@ impl WeightInfo for () { /// Proof: `TargetList::ListBags` (`max_values`: None, `max_size`: Some(90), added: 2565, mode: `MaxEncodedLen`) /// Storage: `TargetList::CounterForListNodes` (r:1 w:1) /// Proof: `TargetList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - fn v13_mmb_step() -> Weight { + fn v13_mmb_partial_step() -> Weight { // Proof Size summary in bytes: // Measured: `70141` // Estimated: `477090` From a0d39626b6dcfbbfafb518f227695f2e9c8bf0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 18 Jul 2024 23:44:04 +0200 Subject: [PATCH 129/133] stake-tracker cargo toml to use workspace --- Cargo.lock | 1 - .../frame/staking/stake-tracker/Cargo.toml | 38 +++++++++---------- .../frame/staking/stake-tracker/src/lib.rs | 6 ++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc55456753b9..1acd8ff840df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11551,7 +11551,6 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index a25867bb86a3..dffdb0d037d4 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -12,30 +12,31 @@ repository = "https://github.com/paritytech/polkadot-sdk" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +codec = { features = [ + "derive", +], workspace = true } -sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } -sp-staking = { default-features = false, path = "../../../primitives/staking", features = ["serde"] } -sp-std = { default-features = false, path = "../../../primitives/std" } -sp-npos-elections = { default-features = false, path = "../../../primitives/npos-elections" } -frame-election-provider-support = { default-features = false, path = "../../election-provider-support" } -frame-support = { default-features = false, path = "../../support" } -frame-system = { default-features = false, path = "../../system" } +scale-info = { features = ["derive", "serde"], workspace = true } + +sp-runtime = { features = ["serde"], workspace = true } +sp-staking = { features = ["serde"], workspace = true } + +sp-npos-elections = { workspace = true, default-features = false } +frame-election-provider-support = { workspace = true, default-features = false } +frame-support = { workspace = true } +frame-system = { workspace = true } # Optional imports for benchmarking -frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } +frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] -sp-std = { default-features = false, path = "../../../primitives/std" } -sp-core = { default-features = false, path = "../../../primitives/core" } -sp-io = { default-features = false, path = "../../../primitives/io" } -sp-runtime = { default-features = false, path = "../../../primitives/runtime", features = ["serde"] } -sp-tracing = { default-features = false, path = "../../../primitives/tracing" } -pallet-bags-list = { default-features = false, path = "../../bags-list", features = ["try-runtime"] } -pallet-balances = { default-features = false, path = "../../balances" } -frame-benchmarking = { path = "../../benchmarking" } +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true } +sp-tracing = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = false, features = ["try-runtime"] } +pallet-balances = { workspace = true, default-features = true } +frame-benchmarking = { workspace = true, default-features = true } [features] default = ["std"] @@ -55,7 +56,6 @@ std = [ "sp-runtime/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", "sp-tracing/std", ] diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 91a043ddcf82..9d4668c2a002 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -89,6 +89,8 @@ pub use pallet::*; +extern crate alloc; + use frame_election_provider_support::SortedListProvider; use frame_support::{ defensive, @@ -99,7 +101,7 @@ use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; -use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; #[cfg(test)] pub(crate) mod mock; @@ -302,7 +304,7 @@ pub mod pallet { /// Used for debug assertions only, since this pallet expects the nominations to be /// deduplicated at all places. pub fn has_duplicate_nominations(mut v: Vec) -> bool { - use sp_std::collections::btree_set::BTreeSet; + use alloc::collections::btree_set::BTreeSet; let size_before = v.len(); let dedup = v.drain(..).collect::>().into_iter().collect::>(); From 4ddff0f33fe3d32c37bdc60795678c58a1ec592b Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Thu, 18 Jul 2024 22:08:35 +0000 Subject: [PATCH 130/133] ".git/.scripts/commands/fmt/fmt.sh" --- substrate/frame/Cargo.toml | 4 ++-- substrate/frame/staking/Cargo.toml | 6 +++--- substrate/frame/staking/src/pallet/impls.rs | 6 ++---- substrate/frame/staking/src/tests.rs | 2 +- substrate/frame/staking/stake-tracker/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/substrate/frame/Cargo.toml b/substrate/frame/Cargo.toml index 1ae33482dcf1..595fb5a19b04 100644 --- a/substrate/frame/Cargo.toml +++ b/substrate/frame/Cargo.toml @@ -67,6 +67,8 @@ pallet-examples = { workspace = true } default = ["runtime", "std"] experimental = ["frame-support/experimental"] runtime = [ + "frame-executive", + "frame-system-rpc-runtime-api", "sp-api", "sp-block-builder", "sp-consensus-aura", @@ -77,8 +79,6 @@ runtime = [ "sp-storage", "sp-transaction-pool", "sp-version", - "frame-executive", - "frame-system-rpc-runtime-api", ] std = [ "codec/std", diff --git a/substrate/frame/staking/Cargo.toml b/substrate/frame/staking/Cargo.toml index f800c61fec39..02dba8ba54de 100644 --- a/substrate/frame/staking/Cargo.toml +++ b/substrate/frame/staking/Cargo.toml @@ -63,10 +63,10 @@ std = [ "pallet-authorship/std", "pallet-bags-list/std", "pallet-balances/std", + "pallet-migrations/std", "pallet-session/std", "pallet-stake-tracker/std", "pallet-timestamp/std", - "pallet-migrations/std", "scale-info/std", "serde/std", "sp-application-crypto/std", @@ -84,9 +84,9 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-stake-tracker/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", - "pallet-migrations/runtime-benchmarks", "rand_chacha", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", @@ -98,9 +98,9 @@ try-runtime = [ "pallet-authorship/try-runtime", "pallet-bags-list/try-runtime", "pallet-balances/try-runtime", + "pallet-migrations/try-runtime", "pallet-session/try-runtime", "pallet-stake-tracker/try-runtime", "pallet-timestamp/try-runtime", - "pallet-migrations/try-runtime", "sp-runtime/try-runtime", ] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 68f2bfec3bf6..7212816d1a08 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2235,15 +2235,13 @@ impl Pallet { ensure!( ::VoterList::iter() .filter(|v| Self::status(&v) != Ok(StakerStatus::Idle)) - .count() as u32 == - Nominators::::count() + Validators::::count(), + .count() as u32 == Nominators::::count() + Validators::::count(), "wrong external count (VoterList.count != Nominators.count + Validators.count)" ); ensure!( ::TargetList::iter() .filter(|t| Self::status(&t) == Ok(StakerStatus::Validator)) - .count() as u32 == - Validators::::count(), + .count() as u32 == Validators::::count(), "wrong external count (TargetList.count != Validators.count)" ); ensure!( diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 8567d9d8babe..6243da7b8d0a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -9318,7 +9318,7 @@ mod ledger_recovery { assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK assert!(Payee::::get(&333).is_some()); // OK - // however, ledger associated with its controller was killed. + // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK // side effects on 444 - ledger, bonded, payee, lock should be completely removed. diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 9d4668c2a002..a12cd2f16d1c 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -91,6 +91,7 @@ pub use pallet::*; extern crate alloc; +use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use frame_election_provider_support::SortedListProvider; use frame_support::{ defensive, @@ -101,7 +102,6 @@ use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; -use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; #[cfg(test)] pub(crate) mod mock; From aab02ce1f23ebd05abe23a5a0b6ea540149a7914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 19 Jul 2024 22:00:38 +0200 Subject: [PATCH 131/133] nit to prevent defensives in migration --- substrate/frame/staking/stake-tracker/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 9d4668c2a002..4e2b31a735e1 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -478,7 +478,6 @@ impl OnStakingUpdate> for Pallet { prev_nominations: Vec, nominations: Vec, ) { - defensive_assert!(!Self::has_duplicate_nominations(prev_nominations.clone())); defensive_assert!(!Self::has_duplicate_nominations(nominations.clone())); let nominator_vote = Self::vote_of(who); From 933e1598294a8bfdf503097f6f046e2bbea352d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 1 Aug 2024 13:15:12 +0200 Subject: [PATCH 132/133] Adds target approvals buffering below a threshold (#5168) This PR adds target stake updates buffering to `stake-tracker`. It exposes a configuration that defines a threshold below which the target score *should not* be updated automatically in the target list. The `Config::ScoreStrictUpdateThreshold` defines said threshold. If a target stake update is below the threshold, the stake update is buffered in the `UnsettledTargetScore` storage map while the target list is not affected. Multiple approvals updates can be buffered for the same target. Calling `Call::settle` will setttle the buffered approvals tally for a given target. Setting `Config::ScoreStrictUpdateThreshold` to `None` disables the stake approvals buffering. - [x] benchmarks - [x] `try-state` checks considering the unsettled score - [x] docs --------- Co-authored-by: command-bot <> --- Cargo.lock | 1 + polkadot/runtime/westend/src/lib.rs | 5 + substrate/bin/node/runtime/src/lib.rs | 7 + substrate/frame/delegated-staking/src/mock.rs | 5 + .../test-staking-e2e/src/mock.rs | 5 + substrate/frame/nomination-pools/src/mock.rs | 4 + .../test-delegate-stake/src/mock.rs | 3 + .../test-transfer-stake/src/mock.rs | 3 + substrate/frame/staking/src/benchmarking.rs | 8 +- substrate/frame/staking/src/mock.rs | 11 + substrate/frame/staking/src/pallet/impls.rs | 20 ++ substrate/frame/staking/src/pallet/mod.rs | 13 ++ substrate/frame/staking/src/tests.rs | 40 +++- .../frame/staking/stake-tracker/Cargo.toml | 2 + .../staking/stake-tracker/src/benchmarking.rs | 53 +++++ .../frame/staking/stake-tracker/src/lib.rs | 207 ++++++++++++++++-- .../frame/staking/stake-tracker/src/mock.rs | 27 ++- .../frame/staking/stake-tracker/src/tests.rs | 160 +++++++++++++- .../staking/stake-tracker/src/weights.rs | 89 ++++++++ substrate/primitives/staking/src/lib.rs | 3 + 20 files changed, 637 insertions(+), 29 deletions(-) create mode 100644 substrate/frame/staking/stake-tracker/src/benchmarking.rs create mode 100644 substrate/frame/staking/stake-tracker/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 6fb73b528ca7..3df437818d1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11551,6 +11551,7 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", + "sp-std 14.0.0", "sp-tracing 16.0.0", ] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 4c609c095a6f..1772a39c8259 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -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 = Some(10); } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -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; } pallet_staking_reward_curve::build! { @@ -667,6 +670,8 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = TargetList; + #[cfg(any(feature = "try-runtime", test))] + type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 46df438074d1..d6aa5d5dc09c 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -697,6 +697,8 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = TargetList; + #[cfg(any(feature = "try-runtime", test))] + type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type NominationsQuota = pallet_staking::FixedNominationsQuota; type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; @@ -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 = None; } impl pallet_stake_tracker::Config for Runtime { @@ -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; } impl pallet_fast_unstake::Config for Runtime { @@ -2646,6 +2652,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_society, Society] [pallet_staking, Staking] + [pallet_stake_tracker, StakeTracker] [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index de9ff6f9f6f9..4f1aa8754c8f 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -110,6 +110,8 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = TargetBagsList; + #[cfg(any(feature = "try-runtime", test))] + type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type EventListeners = (StakeTracker, Pools, DelegatedStaking); } @@ -129,6 +131,7 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; + pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -137,6 +140,8 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = TargetBagsList; type VoterUpdateMode = VoterUpdateMode; + type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; + type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index f71d907b5cc0..d04adca7147e 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -256,6 +256,7 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Lazy; + pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -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; @@ -330,6 +333,8 @@ impl pallet_staking::Config for Runtime { type VoterList = VoterBagsList; type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = TargetBagsList; + #[cfg(any(feature = "try-runtime", test))] + type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type MaxUnlockingChunks = MaxUnlockingChunks; type EventListeners = (StakeTracker, Pools); type WeightInfo = pallet_staking::weights::SubstrateWeight; diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 6c0082073f68..4951b7532c4c 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -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) -> DispatchResult { Nominations::set(&Some(nominations)); Ok(()) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index b4f9330502be..18e57b6db197 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -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 = None; } impl pallet_stake_tracker::Config for Runtime { @@ -116,6 +117,8 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type VoterUpdateMode = VoterUpdateMode; + type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; + type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index a1129d62cdf5..dd174fa97c06 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -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 = None; } impl pallet_stake_tracker::Config for Runtime { @@ -108,6 +109,8 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type VoterUpdateMode = VoterUpdateMode; + type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; + type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 7592576d78fd..f1f1bd0c9066 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -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, @@ -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; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 17be5743ea1e..4faaf4280681 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -356,6 +356,8 @@ impl OnStakingUpdate 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 = None; } impl pallet_stake_tracker::Config for Test { @@ -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` @@ -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; type NominationsQuota = WeightedNominationsQuota<16>; type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; @@ -559,6 +565,11 @@ impl ExtBuilder { MaxWinners::set(max); self } + pub fn stake_tracker_update_threshold(self, threshold: Option) -> Self { + ScoreStrictUpdateThreshold::set(threshold); + self + } + fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 7212816d1a08..415b704a631b 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1993,6 +1993,11 @@ impl StakingInterface for Pallet { Self::nominate(RawOrigin::Signed(ctrl).into(), targets) } + fn validate(who: &Self::AccountId) -> DispatchResult { + let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; + Self::validate(RawOrigin::Signed(ctrl).into(), Default::default()) + } + fn desired_validator_count() -> u32 { ValidatorCount::::get() } @@ -2521,6 +2526,8 @@ impl Pallet { /// (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 = BTreeMap::new(); // build map of approvals stakes from the `Nominators` storage map POV. @@ -2585,6 +2592,19 @@ impl Pallet { } } + // 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. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index c83088e3e782..af76eb6a78ac 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -268,6 +268,19 @@ pub mod pallet { #[pallet::no_default] type TargetList: SortedListProvider>; + /// 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< + >::Score, + >, + )>, + >; + /// The maximum number of `unlocking` chunks a [`StakingLedger`] can /// have. Effectively determines how many unique eras a staker may be /// unbonding in. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6243da7b8d0a..c3d579340d57 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -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; @@ -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::::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 { @@ -9318,7 +9355,8 @@ mod ledger_recovery { assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK assert!(Payee::::get(&333).is_some()); // OK - // however, ledger associated with its controller was killed. + + // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK // side effects on 444 - ledger, bonded, payee, lock should be completely removed. diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index dffdb0d037d4..0da249ae99ec 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -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 } @@ -56,6 +57,7 @@ std = [ "sp-runtime/std", "sp-runtime/std", "sp-staking/std", + "sp-std/std", "sp-tracing/std", ] diff --git a/substrate/frame/staking/stake-tracker/src/benchmarking.rs b/substrate/frame/staking/stake-tracker/src/benchmarking.rs new file mode 100644 index 000000000000..4a00e1d4460a --- /dev/null +++ b/substrate/frame/staking/stake-tracker/src/benchmarking.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Stake Tracker Pallet benchmarking. + +use super::*; +use crate::{Pallet as StakeTracker, UnsettledTargetScore}; + +use frame_benchmarking::v2::*; +use frame_support::assert_ok; +use frame_system::RawOrigin; + +const SEED: u32 = 0; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn settle() { + let caller = whitelisted_caller(); + let target: T::AccountId = account("target", 0, SEED); + + assert_ok!(StakeTracker::::setup_target_with_unsettled_score(&target)); + assert!(UnsettledTargetScore::::get(&target).is_some()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), target.clone()); + + assert!(UnsettledTargetScore::::get(target).is_none()); + } + + impl_benchmark_test_suite!( + StakeTracker, + crate::mock::ExtBuilder::default().set_update_threshold(Some(50)), + crate::mock::Test, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index 48121824fb84..eabba1fbe7b7 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -18,7 +18,8 @@ //! # Stake Tracker Pallet //! //! The stake-tracker pallet is responsible to keep track of the voter's stake and target's approval -//! voting in the staking system. +//! voting in the staking system. It provides an easy way to other pallets to query the list of +//! strictly sorted targets based on their approvals. //! //! ## Overview //! @@ -57,6 +58,17 @@ //! should handle that in some way (e.g. buffering events and implementing a multi-block event //! emitter). //! +//! ## Lazy target approvals' updates +//! +//! This pallet exposes a configuration that defines a threshold below which the target score +//! *should not* be updated automatically. The `Config::ScoreStrictUpdateThreshold` defines said +//! threshold. If a target stake update is below the threshold, the stake update is buffered in +//! the `UnsettledTargetScore` storage map while the target list is not affected. Multiple +//! approvals updates can be buffered for the same target. Calling `Call::settle` will setttle the +//! buffered approvals tally for a given target. +//! +//! Setting `Config::ScoreStrictUpdateThreshold` to `None` disables the stake approvals buffering. +//! //! ## Staker status and list invariants //! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the @@ -89,48 +101,108 @@ pub use pallet::*; +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +pub mod mock; +#[cfg(test)] +mod tests; + +pub mod weights; + extern crate alloc; use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; -use frame_election_provider_support::SortedListProvider; +use frame_election_provider_support::{ExtendedBalance, SortedListProvider, VoteWeight}; use frame_support::{ defensive, pallet_prelude::*, - traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, + traits::{ + fungible::{Inspect as FnInspect, Mutate as FnMutate}, + Defensive, DefensiveSaturating, + }, }; +use frame_system::pallet_prelude::*; use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; - -#[cfg(test)] -pub(crate) mod mock; -#[cfg(test)] -mod tests; +use sp_std::ops::Add; +pub use weights::WeightInfo; /// The balance type of this pallet. pub type BalanceOf = <::Staking as StakingInterface>::Balance; /// The account ID of this pallet. pub type AccountIdOf = ::AccountId; +/// Score of a sorted list provider. +pub type ScoreOf = <::TargetList as SortedListProvider>>::Score; +/// List of current unsettled target scores. +pub type UnsettledList = Vec<(AccountIdOf, StakeImbalance)>; /// Represents a stake imbalance to be applied to a staker's score. -#[derive(Copy, Clone, Debug)] +#[derive(TypeInfo, Copy, Debug, Clone, Encode, Decode, PartialEq, MaxEncodedLen)] pub enum StakeImbalance { /// Represents the reduction of stake by `Score`. Negative(Score), /// Represents the increase of stake by `Score`. Positive(Score), + /// No stake imbalance. + Zero, +} + +impl Default for StakeImbalance { + fn default() -> Self { + Self::Positive(Zero::zero()) + } +} + +impl Add for StakeImbalance { + type Output = Self; + + fn add(self, other: Self) -> Self { + match (self, other) { + (Self::Positive(x), Self::Positive(y)) => Self::Positive(x.defensive_saturating_add(y)), + (Self::Negative(x), Self::Negative(y)) => Self::Negative(x.defensive_saturating_add(y)), + (Self::Positive(x), Self::Negative(y)) => + if x > y { + Self::Positive(x.defensive_saturating_sub(y)) + } else if x < y { + Self::Negative(y.defensive_saturating_sub(x)) + } else { + Self::Zero + }, + (Self::Negative(x), Self::Positive(y)) => + if x > y { + Self::Negative(x.defensive_saturating_sub(y)) + } else if x < y { + Self::Positive(y.defensive_saturating_sub(x)) + } else { + Self::Zero + }, + (Self::Zero, _) => other, + (_, Self::Zero) => self, + } + } } -impl StakeImbalance { - /// Constructor for a stake imbalance instance based on the previous and next score. - fn from(prev: Score, new: Score) -> Self { +impl StakeImbalance { + /// Constructor for a stake imbalance instance based on the previous and next unsigned value. + fn from(prev: V, new: V) -> Self { if prev > new { StakeImbalance::Negative(prev.defensive_saturating_sub(new)) } else { StakeImbalance::Positive(new.defensive_saturating_sub(prev)) } } + + /// Returns the unsigned value of a staking balance instance. + fn value(&self) -> V { + match self { + Self::Positive(score) | Self::Negative(score) => *score, + Self::Zero => Zero::zero(), + } + } } /// Defines the sorting mode of sorted list providers. @@ -152,7 +224,6 @@ impl VoterUpdateMode { #[frame_support::pallet] pub mod pallet { use crate::*; - use frame_election_provider_support::{ExtendedBalance, VoteWeight}; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -164,7 +235,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The stake balance. - type Currency: FnInspect>; + type Currency: FnInspect> + + FnMutate; /// The staking interface. type Staking: StakingInterface; @@ -180,9 +252,63 @@ pub mod pallet { /// The voter list update mode. type VoterUpdateMode: Get; + + /// Score threshold which defines whether the approvals should be updated on buffered. + /// + /// If the approvals score to be updated is higher than `ScoreStrictUpdateThreshold`, + /// update the target list. Otherwise, buffer the update. + type ScoreStrictUpdateThreshold: Get>; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + /// Map with unsettled score for targets. + /// + /// This map keeps track of unsettled score for targets. + #[pallet::storage] + pub type UnsettledTargetScore = + StorageMap<_, Twox64Concat, T::AccountId, StakeImbalance>>; + + #[pallet::error] + #[derive(PartialEq)] + pub enum Error { + /// Account is not a target. + NotTarget, + /// No unsettled score for a given target. + NoScoreToSettle, + } + + #[pallet::call] + impl Pallet { + /// Settles a buffered target approvals imbalance. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::settle())] + pub fn settle(origin: OriginFor, who: AccountIdOf) -> DispatchResult { + let _ = ensure_signed(origin)?; + + ensure!(T::TargetList::contains(&who), Error::::NotTarget); + ensure!(UnsettledTargetScore::::contains_key(&who), Error::::NoScoreToSettle); + + Self::do_settle(&who)?; + Ok(()) + } } impl Pallet { + /// Settles buffered score for a target, if it exists. + pub(crate) fn do_settle(who: &T::AccountId) -> Result<(), Error> { + UnsettledTargetScore::::try_mutate_exists(who, |maybe_imbalance| { + let imbalance = maybe_imbalance.ok_or(Error::::NoScoreToSettle)?; + + Self::update_target_score_unchecked(who, imbalance); + *maybe_imbalance = None; + Ok(()) + })?; + + Ok(()) + } + /// Updates the stake of a voter. /// /// NOTE: This method expects `nominations` to be deduplicated, otherwise the approvals @@ -254,7 +380,27 @@ pub mod pallet { ); } - // update target score. + // updates the target list OR buffers the score depending on whether the score + // imbalance is higher than the update threshold (if set). + if let Some(update_threshold) = T::ScoreStrictUpdateThreshold::get() { + if imbalance.value() > update_threshold { + Self::update_target_score_unchecked(who, imbalance); + } else { + // buffer the approvals update in `UnsettledTargetScore` map. + UnsettledTargetScore::::insert( + who, + UnsettledTargetScore::::get(who).unwrap_or_default().add(imbalance), + ); + } + } else { + Self::update_target_score_unchecked(who, imbalance); + } + } + + pub(crate) fn update_target_score_unchecked( + who: &T::AccountId, + imbalance: StakeImbalance, + ) { match imbalance { StakeImbalance::Positive(imbalance) => { let _ = T::TargetList::on_increase(who, imbalance).defensive_proof( @@ -280,6 +426,7 @@ pub mod pallet { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); } }, + StakeImbalance::Zero => (), // update not needed. }; } @@ -310,6 +457,33 @@ pub mod pallet { size_before != dedup.len() } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn setup_target_with_unsettled_score(target: &T::AccountId) -> DispatchResult { + // fund target account. + let mut balance = T::Currency::minimum_balance(); + for _ in 0..100 { + balance = balance + T::Currency::minimum_balance(); + } + let _ = T::Currency::set_balance(target, balance + T::Currency::minimum_balance()); + + ::bond(target, balance, target)?; + ::validate(target)?; + + UnsettledTargetScore::::insert(target, StakeImbalance::Positive(10)); + + Ok(()) + } + } +} + +/// Returns a vec with all the unsettled scores. +pub struct UnsettledTargetScores(PhantomData); +impl sp_runtime::traits::TypedGet for UnsettledTargetScores { + type Type = UnsettledList; + + fn get() -> Self::Type { + UnsettledTargetScore::::iter().collect::>() } } @@ -399,6 +573,9 @@ impl OnStakingUpdate> for Pallet { if score.is_zero() { let _ = T::TargetList::on_remove(who) .defensive_proof("target exists as per above; qed"); + + // ensure that the unsettled score list is cleaned. + let _ = UnsettledTargetScore::::take(who); } } else { // target is not part of the list. Given the contract with staking and the checks above, diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index b326ba52e697..ddbc02e3cdc2 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -31,7 +31,7 @@ type Block = frame_system::mocking::MockBlockU32; // Configure a mock runtime to test the pallet. #[frame_support::runtime] -mod runtime { +pub mod runtime { #[runtime::runtime] #[runtime::derive( RuntimeCall, @@ -98,8 +98,6 @@ const TARGET_THRESHOLDS: [u128; 9] = [100, 200, 300, 400, 500, 600, 700, 800, 90 parameter_types! { pub static VoterBagThresholds: &'static [VoteWeight] = &VOTER_THRESHOLDS; pub static TargetBagThresholds: &'static [u128] = &TARGET_THRESHOLDS; - - pub static VoterUpdateMode: crate::VoterUpdateMode = crate::VoterUpdateMode::Strict; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -120,12 +118,20 @@ impl pallet_bags_list::Config for Test { type Score = u128; } +parameter_types! { + pub static VoterUpdateMode: crate::VoterUpdateMode = crate::VoterUpdateMode::Strict; + // disables the lazy approvals update. + pub static ScoreStrictUpdateThreshold: Option = None; +} + impl pallet_stake_tracker::Config for Test { type Currency = Balances; type Staking = StakingMock; type VoterList = VoterBagsList; type TargetList = TargetBagsList; type VoterUpdateMode = VoterUpdateMode; + type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; + type WeightInfo = (); } pub struct StakingMock {} @@ -194,7 +200,7 @@ impl StakingInterface for StakingMock { } fn minimum_validator_bond() -> Self::Balance { - unreachable!(); + 1 } fn stash_by_ctrl( @@ -216,7 +222,13 @@ impl StakingInterface for StakingMock { _value: Self::Balance, _payee: &Self::AccountId, ) -> sp_runtime::DispatchResult { - unreachable!(); + Ok(()) + } + + fn validate(who: &Self::AccountId) -> DispatchResult { + add_validator(*who, 10); + + Ok(()) } fn nominate( @@ -503,6 +515,11 @@ impl ExtBuilder { self } + pub fn set_update_threshold(self, threshold: Option) -> Self { + ScoreStrictUpdateThreshold::set(threshold); + self + } + pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index b53c670b0491..975c9ec43d2e 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -17,16 +17,172 @@ #![cfg(test)] -use crate::{mock::*, StakeImbalance}; +use crate::{mock::*, Error, StakeImbalance, UnsettledTargetScores}; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; -use frame_support::assert_ok; +use frame_support::{assert_noop, assert_ok}; +use sp_runtime::traits::TypedGet; use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingInterface}; // keeping tests clean. type A = AccountId; type B = Balance; +mod stake_imbalance { + use super::*; + + #[test] + fn stake_imbalance_arithmetic_works() { + use std::ops::Add; + + // 0 + 0 = 0 + assert_eq!(StakeImbalance::::Zero.add(StakeImbalance::Zero), StakeImbalance::Zero,); + + // 1 + 0 = 1 + assert_eq!( + StakeImbalance::Positive(1).add(StakeImbalance::Zero), + StakeImbalance::Positive(1), + ); + + // -1 + 0 = -1 + assert_eq!( + StakeImbalance::Negative(1).add(StakeImbalance::Zero), + StakeImbalance::Negative(1), + ); + + // -2 + 2 = 0 + assert_eq!( + StakeImbalance::Negative(2).add(StakeImbalance::Positive(2)), + StakeImbalance::Zero, + ); + + // 1 + 2 = 3 + assert_eq!( + StakeImbalance::Positive(1).add(StakeImbalance::Positive(2)), + StakeImbalance::Positive(3) + ); + + // 1 + (-2) = -1 + assert_eq!( + StakeImbalance::Positive(1).add(StakeImbalance::Negative(2)), + StakeImbalance::Negative(1) + ); + + // -1 + 2 = 1 + assert_eq!( + StakeImbalance::Negative(1).add(StakeImbalance::Positive(2)), + StakeImbalance::Positive(1) + ); + + // -1 + (-2) = -3 + assert_eq!( + StakeImbalance::Negative(1).add(StakeImbalance::Negative(2)), + StakeImbalance::Negative(3) + ); + } + + #[test] + fn updates_below_threshold_buffer_works() { + ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { + add_validator(10, 100); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); + + // updating stake by 200 will reflect in the target list. + update_stake(10, 200, stake_of(10)); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + // unsettled stake list is empty. + assert_eq!(UnsettledTargetScores::::get(), vec![]); + + // updating stake by +5 (below thresahold) will *not* reflect in the target list and + // update the unsettled stake list. + update_stake(10, 205, stake_of(10)); + // target list was not updated. + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + // unsettled stake list has the bufferd score for target 10. + assert_eq!( + UnsettledTargetScores::::get(), + vec![(10u64, StakeImbalance::Positive(5))] + ); + + // updating the stake by -7 is still below the threshold and thus target list is not + // affected. The buffered score will be updated accordingly. + update_stake(10, 198, stake_of(10)); + // target list was not updated. + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); + // unsettled stake list has the bufferd score for target 10. + assert_eq!( + UnsettledTargetScores::::get(), + vec![(10u64, StakeImbalance::Negative(2))] + ); + + // finally, settling the buffered target score for 10 will affect the target's + // approvals. + assert_ok!(StakeTracker::do_settle(&10)); + // +5 + (-7) imbalance = (-2), thus approvals is initial approvals - 2. + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 198); + // unsettled stake list is empty again. + assert_eq!(UnsettledTargetScores::::get(), vec![]); + }) + } + + #[test] + fn settle_buffered_score_works() { + ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { + add_validator(10, 100); + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); + assert_eq!(UnsettledTargetScores::::get(), vec![]); + + // updating stake by +5 (below thresahold) will *not* reflect in the target list and + // update the unsettled stake list. + update_stake(10, 105, stake_of(10)); + // target list was not updated. + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); + // unsettled stake list has the bufferd score for target 10. + assert_eq!( + UnsettledTargetScores::::get(), + vec![(10u64, StakeImbalance::Positive(5))] + ); + + // calls `settle` extrinsic to settle the buffered score of 10. + assert_ok!(StakeTracker::settle(RuntimeOrigin::signed(1), 10)); + + // approvals were updated accordingly + assert_eq!(TargetBagsList::get_score(&10).unwrap(), 105); + // unsettled stake list is empty again. + assert_eq!(UnsettledTargetScores::::get(), vec![]); + + // calling `settle` with target account that does not have buffered score errors. + assert_noop!( + StakeTracker::settle(RuntimeOrigin::signed(1), 10), + Error::::NoScoreToSettle, + ); + }) + } + + #[test] + fn settle_buffered_score_error_works() { + ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { + assert!(!TargetBagsList::contains(&100)); + + // calling `settle` of an account that does not exist in the target list errors. + assert_noop!( + StakeTracker::settle(RuntimeOrigin::signed(1), 100), + Error::::NotTarget, + ); + + add_validator(10, 100); + assert!(TargetBagsList::contains(&10)); + assert_eq!(UnsettledTargetScores::::get(), vec![]); + + // calling `settle` with target account that does not have buffered score errors. + assert_noop!( + StakeTracker::settle(RuntimeOrigin::signed(1), 10), + Error::::NoScoreToSettle, + ); + }) + } +} + #[test] fn setup_works() { ExtBuilder::default().build_and_execute(|| { diff --git a/substrate/frame/staking/stake-tracker/src/weights.rs b/substrate/frame/staking/stake-tracker/src/weights.rs new file mode 100644 index 000000000000..86ff3397cd33 --- /dev/null +++ b/substrate/frame/staking/stake-tracker/src/weights.rs @@ -0,0 +1,89 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_staking` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-05-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// target/production/substrate-node +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_stake_tracker +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/staking/stake-tracker/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_stake_tracker`. +pub trait WeightInfo { + fn settle() -> Weight; +} + +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `StakeTracker::UnsettledScore` (r:1 w:1) + /// Proof: `StakeTracker::UnsettledScore` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn settle() -> Weight { + // Proof Size summary in bytes: + // Measured: `606` + // Estimated: `3635` + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(20_000_000, 0) + .saturating_add(Weight::from_parts(0, 3635)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `TargetList::ListNodes` (r:1 w:1) + /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) + /// Storage: `StakeTracker::UnsettledScore` (r:1 w:1) + /// Proof: `StakeTracker::UnsettledScore` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) + fn settle() -> Weight { + // Proof Size summary in bytes: + // Measured: `606` + // Estimated: `3635` + // Minimum execution time: 19_000_000 picoseconds. + Weight::from_parts(20_000_000, 0) + .saturating_add(Weight::from_parts(0, 3635)) + } +} + diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 8328dd664633..72014ecdb60b 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -324,6 +324,9 @@ pub trait StakingInterface { fn bond(who: &Self::AccountId, value: Self::Balance, payee: &Self::AccountId) -> DispatchResult; + /// Have `who` become a validator with default preferences. + fn validate(who: &Self::AccountId) -> DispatchResult; + /// Have `who` nominate `validators`. fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult; From 24c4faa3701c5e2b684dfdfdd4e704722f82a152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 5 Aug 2024 10:19:44 +0200 Subject: [PATCH 133/133] Revert "Adds target approvals buffering below a threshold" (#5235) Reverts paritytech/polkadot-sdk#5168 as per https://github.com/paritytech/polkadot-sdk/pull/5168#issuecomment-2265170923 --- Cargo.lock | 1 - polkadot/runtime/westend/src/lib.rs | 5 - substrate/bin/node/runtime/src/lib.rs | 7 - substrate/frame/delegated-staking/src/mock.rs | 5 - .../test-staking-e2e/src/mock.rs | 5 - substrate/frame/nomination-pools/src/mock.rs | 4 - .../test-delegate-stake/src/mock.rs | 3 - .../test-transfer-stake/src/mock.rs | 3 - substrate/frame/staking/src/benchmarking.rs | 8 +- substrate/frame/staking/src/mock.rs | 11 - substrate/frame/staking/src/pallet/impls.rs | 20 -- substrate/frame/staking/src/pallet/mod.rs | 13 -- substrate/frame/staking/src/tests.rs | 40 +--- .../frame/staking/stake-tracker/Cargo.toml | 2 - .../staking/stake-tracker/src/benchmarking.rs | 53 ----- .../frame/staking/stake-tracker/src/lib.rs | 207 ++---------------- .../frame/staking/stake-tracker/src/mock.rs | 27 +-- .../frame/staking/stake-tracker/src/tests.rs | 160 +------------- .../staking/stake-tracker/src/weights.rs | 89 -------- substrate/primitives/staking/src/lib.rs | 3 - 20 files changed, 29 insertions(+), 637 deletions(-) delete mode 100644 substrate/frame/staking/stake-tracker/src/benchmarking.rs delete mode 100644 substrate/frame/staking/stake-tracker/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index 3df437818d1f..6fb73b528ca7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11551,7 +11551,6 @@ dependencies = [ "sp-npos-elections", "sp-runtime", "sp-staking", - "sp-std 14.0.0", "sp-tracing 16.0.0", ] diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 1772a39c8259..4c609c095a6f 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -590,7 +590,6 @@ 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 = Some(10); } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -617,8 +616,6 @@ 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; } pallet_staking_reward_curve::build! { @@ -670,8 +667,6 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = TargetList; - #[cfg(any(feature = "try-runtime", test))] - type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d6aa5d5dc09c..46df438074d1 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -697,8 +697,6 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = TargetList; - #[cfg(any(feature = "try-runtime", test))] - type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type NominationsQuota = pallet_staking::FixedNominationsQuota; type MaxUnlockingChunks = ConstU32<32>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; @@ -711,8 +709,6 @@ 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 = None; } impl pallet_stake_tracker::Config for Runtime { @@ -721,8 +717,6 @@ 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; } impl pallet_fast_unstake::Config for Runtime { @@ -2652,7 +2646,6 @@ mod benches { [pallet_session, SessionBench::] [pallet_society, Society] [pallet_staking, Staking] - [pallet_stake_tracker, StakeTracker] [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 4f1aa8754c8f..de9ff6f9f6f9 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -110,8 +110,6 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = TargetBagsList; - #[cfg(any(feature = "try-runtime", test))] - type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type EventListeners = (StakeTracker, Pools, DelegatedStaking); } @@ -131,7 +129,6 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; - pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -140,8 +137,6 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = TargetBagsList; type VoterUpdateMode = VoterUpdateMode; - type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; - type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index d04adca7147e..f71d907b5cc0 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -256,7 +256,6 @@ impl pallet_bags_list::Config for Runtime { parameter_types! { pub static UpdateMode: VoterUpdateMode = VoterUpdateMode::Lazy; - pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -265,8 +264,6 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = VoterBagsList; type TargetList = TargetBagsList; type VoterUpdateMode = UpdateMode; - type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; - type WeightInfo = (); } pub struct BalanceToU256; @@ -333,8 +330,6 @@ impl pallet_staking::Config for Runtime { type VoterList = VoterBagsList; type NominationsQuota = pallet_staking::FixedNominationsQuota; type TargetList = TargetBagsList; - #[cfg(any(feature = "try-runtime", test))] - type TargetUnsettledApprovals = pallet_stake_tracker::UnsettledTargetScores; type MaxUnlockingChunks = MaxUnlockingChunks; type EventListeners = (StakeTracker, Pools); type WeightInfo = pallet_staking::weights::SubstrateWeight; diff --git a/substrate/frame/nomination-pools/src/mock.rs b/substrate/frame/nomination-pools/src/mock.rs index 4951b7532c4c..6c0082073f68 100644 --- a/substrate/frame/nomination-pools/src/mock.rs +++ b/substrate/frame/nomination-pools/src/mock.rs @@ -174,10 +174,6 @@ impl sp_staking::StakingInterface for StakingMock { Ok(()) } - fn validate(who: &Self::AccountId) -> sp_runtime::DispatchResult { - unimplemented!() - } - fn nominate(_: &Self::AccountId, nominations: Vec) -> DispatchResult { Nominations::set(&Some(nominations)); Ok(()) diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index 18e57b6db197..b4f9330502be 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -108,7 +108,6 @@ impl pallet_staking::Config for Runtime { parameter_types! { pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; - pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -117,8 +116,6 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type VoterUpdateMode = VoterUpdateMode; - type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; - type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index dd174fa97c06..a1129d62cdf5 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -100,7 +100,6 @@ impl pallet_staking::Config for Runtime { parameter_types! { pub static VoterUpdateMode: pallet_stake_tracker::VoterUpdateMode = pallet_stake_tracker::VoterUpdateMode::Lazy; - pub static ScoreStrictUpdateThreshold: Option = None; } impl pallet_stake_tracker::Config for Runtime { @@ -109,8 +108,6 @@ impl pallet_stake_tracker::Config for Runtime { type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; type VoterUpdateMode = VoterUpdateMode; - type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; - type WeightInfo = (); } parameter_types! { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index f1f1bd0c9066..7592576d78fd 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -22,7 +22,6 @@ 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, @@ -32,13 +31,18 @@ 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; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4faaf4280681..17be5743ea1e 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -356,8 +356,6 @@ impl OnStakingUpdate 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 = None; } impl pallet_stake_tracker::Config for Test { @@ -366,8 +364,6 @@ 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` @@ -390,8 +386,6 @@ 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; type NominationsQuota = WeightedNominationsQuota<16>; type MaxUnlockingChunks = MaxUnlockingChunks; type HistoryDepth = HistoryDepth; @@ -565,11 +559,6 @@ impl ExtBuilder { MaxWinners::set(max); self } - pub fn stake_tracker_update_threshold(self, threshold: Option) -> Self { - ScoreStrictUpdateThreshold::set(threshold); - self - } - fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 415b704a631b..7212816d1a08 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1993,11 +1993,6 @@ impl StakingInterface for Pallet { Self::nominate(RawOrigin::Signed(ctrl).into(), targets) } - fn validate(who: &Self::AccountId) -> DispatchResult { - let ctrl = Self::bonded(who).ok_or(Error::::NotStash)?; - Self::validate(RawOrigin::Signed(ctrl).into(), Default::default()) - } - fn desired_validator_count() -> u32 { ValidatorCount::::get() } @@ -2526,8 +2521,6 @@ impl Pallet { /// (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 = BTreeMap::new(); // build map of approvals stakes from the `Nominators` storage map POV. @@ -2592,19 +2585,6 @@ impl Pallet { } } - // 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. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index af76eb6a78ac..c83088e3e782 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -268,19 +268,6 @@ pub mod pallet { #[pallet::no_default] type TargetList: SortedListProvider>; - /// 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< - >::Score, - >, - )>, - >; - /// The maximum number of `unlocking` chunks a [`StakingLedger`] can /// have. Effectively determines how many unique eras a staker may be /// unbonding in. diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c3d579340d57..6243da7b8d0a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -7853,7 +7853,6 @@ 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; @@ -8721,42 +8720,6 @@ 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::::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 { @@ -9355,8 +9318,7 @@ mod ledger_recovery { assert_eq!(Balances::balance_locked(crate::STAKING_ID, &333), lock_333_before); // OK assert_eq!(Bonded::::get(&333), Some(444)); // OK assert!(Payee::::get(&333).is_some()); // OK - - // however, ledger associated with its controller was killed. + // however, ledger associated with its controller was killed. assert!(Ledger::::get(&444).is_none()); // NOK // side effects on 444 - ledger, bonded, payee, lock should be completely removed. diff --git a/substrate/frame/staking/stake-tracker/Cargo.toml b/substrate/frame/staking/stake-tracker/Cargo.toml index 0da249ae99ec..dffdb0d037d4 100644 --- a/substrate/frame/staking/stake-tracker/Cargo.toml +++ b/substrate/frame/staking/stake-tracker/Cargo.toml @@ -19,7 +19,6 @@ 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 } @@ -57,7 +56,6 @@ std = [ "sp-runtime/std", "sp-runtime/std", "sp-staking/std", - "sp-std/std", "sp-tracing/std", ] diff --git a/substrate/frame/staking/stake-tracker/src/benchmarking.rs b/substrate/frame/staking/stake-tracker/src/benchmarking.rs deleted file mode 100644 index 4a00e1d4460a..000000000000 --- a/substrate/frame/staking/stake-tracker/src/benchmarking.rs +++ /dev/null @@ -1,53 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Stake Tracker Pallet benchmarking. - -use super::*; -use crate::{Pallet as StakeTracker, UnsettledTargetScore}; - -use frame_benchmarking::v2::*; -use frame_support::assert_ok; -use frame_system::RawOrigin; - -const SEED: u32 = 0; - -#[benchmarks] -mod benchmarks { - use super::*; - - #[benchmark] - fn settle() { - let caller = whitelisted_caller(); - let target: T::AccountId = account("target", 0, SEED); - - assert_ok!(StakeTracker::::setup_target_with_unsettled_score(&target)); - assert!(UnsettledTargetScore::::get(&target).is_some()); - - #[extrinsic_call] - _(RawOrigin::Signed(caller), target.clone()); - - assert!(UnsettledTargetScore::::get(target).is_none()); - } - - impl_benchmark_test_suite!( - StakeTracker, - crate::mock::ExtBuilder::default().set_update_threshold(Some(50)), - crate::mock::Test, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/staking/stake-tracker/src/lib.rs b/substrate/frame/staking/stake-tracker/src/lib.rs index eabba1fbe7b7..48121824fb84 100644 --- a/substrate/frame/staking/stake-tracker/src/lib.rs +++ b/substrate/frame/staking/stake-tracker/src/lib.rs @@ -18,8 +18,7 @@ //! # Stake Tracker Pallet //! //! The stake-tracker pallet is responsible to keep track of the voter's stake and target's approval -//! voting in the staking system. It provides an easy way to other pallets to query the list of -//! strictly sorted targets based on their approvals. +//! voting in the staking system. //! //! ## Overview //! @@ -58,17 +57,6 @@ //! should handle that in some way (e.g. buffering events and implementing a multi-block event //! emitter). //! -//! ## Lazy target approvals' updates -//! -//! This pallet exposes a configuration that defines a threshold below which the target score -//! *should not* be updated automatically. The `Config::ScoreStrictUpdateThreshold` defines said -//! threshold. If a target stake update is below the threshold, the stake update is buffered in -//! the `UnsettledTargetScore` storage map while the target list is not affected. Multiple -//! approvals updates can be buffered for the same target. Calling `Call::settle` will setttle the -//! buffered approvals tally for a given target. -//! -//! Setting `Config::ScoreStrictUpdateThreshold` to `None` disables the stake approvals buffering. -//! //! ## Staker status and list invariants //! //! * A [`sp_staking::StakerStatus::Nominator`] is part of the voter list and its self-stake is the @@ -101,108 +89,48 @@ pub use pallet::*; -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -#[cfg(test)] -pub mod mock; -#[cfg(test)] -mod tests; - -pub mod weights; - extern crate alloc; use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; -use frame_election_provider_support::{ExtendedBalance, SortedListProvider, VoteWeight}; +use frame_election_provider_support::SortedListProvider; use frame_support::{ defensive, pallet_prelude::*, - traits::{ - fungible::{Inspect as FnInspect, Mutate as FnMutate}, - Defensive, DefensiveSaturating, - }, + traits::{fungible::Inspect as FnInspect, Defensive, DefensiveSaturating}, }; -use frame_system::pallet_prelude::*; use sp_runtime::traits::Zero; use sp_staking::{ currency_to_vote::CurrencyToVote, OnStakingUpdate, Stake, StakerStatus, StakingInterface, }; -use sp_std::ops::Add; -pub use weights::WeightInfo; + +#[cfg(test)] +pub(crate) mod mock; +#[cfg(test)] +mod tests; /// The balance type of this pallet. pub type BalanceOf = <::Staking as StakingInterface>::Balance; /// The account ID of this pallet. pub type AccountIdOf = ::AccountId; -/// Score of a sorted list provider. -pub type ScoreOf = <::TargetList as SortedListProvider>>::Score; -/// List of current unsettled target scores. -pub type UnsettledList = Vec<(AccountIdOf, StakeImbalance)>; /// Represents a stake imbalance to be applied to a staker's score. -#[derive(TypeInfo, Copy, Debug, Clone, Encode, Decode, PartialEq, MaxEncodedLen)] +#[derive(Copy, Clone, Debug)] pub enum StakeImbalance { /// Represents the reduction of stake by `Score`. Negative(Score), /// Represents the increase of stake by `Score`. Positive(Score), - /// No stake imbalance. - Zero, -} - -impl Default for StakeImbalance { - fn default() -> Self { - Self::Positive(Zero::zero()) - } -} - -impl Add for StakeImbalance { - type Output = Self; - - fn add(self, other: Self) -> Self { - match (self, other) { - (Self::Positive(x), Self::Positive(y)) => Self::Positive(x.defensive_saturating_add(y)), - (Self::Negative(x), Self::Negative(y)) => Self::Negative(x.defensive_saturating_add(y)), - (Self::Positive(x), Self::Negative(y)) => - if x > y { - Self::Positive(x.defensive_saturating_sub(y)) - } else if x < y { - Self::Negative(y.defensive_saturating_sub(x)) - } else { - Self::Zero - }, - (Self::Negative(x), Self::Positive(y)) => - if x > y { - Self::Negative(x.defensive_saturating_sub(y)) - } else if x < y { - Self::Positive(y.defensive_saturating_sub(x)) - } else { - Self::Zero - }, - (Self::Zero, _) => other, - (_, Self::Zero) => self, - } - } } -impl StakeImbalance { - /// Constructor for a stake imbalance instance based on the previous and next unsigned value. - fn from(prev: V, new: V) -> Self { +impl StakeImbalance { + /// Constructor for a stake imbalance instance based on the previous and next score. + fn from(prev: Score, new: Score) -> Self { if prev > new { StakeImbalance::Negative(prev.defensive_saturating_sub(new)) } else { StakeImbalance::Positive(new.defensive_saturating_sub(prev)) } } - - /// Returns the unsigned value of a staking balance instance. - fn value(&self) -> V { - match self { - Self::Positive(score) | Self::Negative(score) => *score, - Self::Zero => Zero::zero(), - } - } } /// Defines the sorting mode of sorted list providers. @@ -224,6 +152,7 @@ impl VoterUpdateMode { #[frame_support::pallet] pub mod pallet { use crate::*; + use frame_election_provider_support::{ExtendedBalance, VoteWeight}; /// The current storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -235,8 +164,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The stake balance. - type Currency: FnInspect> - + FnMutate; + type Currency: FnInspect>; /// The staking interface. type Staking: StakingInterface; @@ -252,63 +180,9 @@ pub mod pallet { /// The voter list update mode. type VoterUpdateMode: Get; - - /// Score threshold which defines whether the approvals should be updated on buffered. - /// - /// If the approvals score to be updated is higher than `ScoreStrictUpdateThreshold`, - /// update the target list. Otherwise, buffer the update. - type ScoreStrictUpdateThreshold: Get>; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - } - - /// Map with unsettled score for targets. - /// - /// This map keeps track of unsettled score for targets. - #[pallet::storage] - pub type UnsettledTargetScore = - StorageMap<_, Twox64Concat, T::AccountId, StakeImbalance>>; - - #[pallet::error] - #[derive(PartialEq)] - pub enum Error { - /// Account is not a target. - NotTarget, - /// No unsettled score for a given target. - NoScoreToSettle, - } - - #[pallet::call] - impl Pallet { - /// Settles a buffered target approvals imbalance. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::settle())] - pub fn settle(origin: OriginFor, who: AccountIdOf) -> DispatchResult { - let _ = ensure_signed(origin)?; - - ensure!(T::TargetList::contains(&who), Error::::NotTarget); - ensure!(UnsettledTargetScore::::contains_key(&who), Error::::NoScoreToSettle); - - Self::do_settle(&who)?; - Ok(()) - } } impl Pallet { - /// Settles buffered score for a target, if it exists. - pub(crate) fn do_settle(who: &T::AccountId) -> Result<(), Error> { - UnsettledTargetScore::::try_mutate_exists(who, |maybe_imbalance| { - let imbalance = maybe_imbalance.ok_or(Error::::NoScoreToSettle)?; - - Self::update_target_score_unchecked(who, imbalance); - *maybe_imbalance = None; - Ok(()) - })?; - - Ok(()) - } - /// Updates the stake of a voter. /// /// NOTE: This method expects `nominations` to be deduplicated, otherwise the approvals @@ -380,27 +254,7 @@ pub mod pallet { ); } - // updates the target list OR buffers the score depending on whether the score - // imbalance is higher than the update threshold (if set). - if let Some(update_threshold) = T::ScoreStrictUpdateThreshold::get() { - if imbalance.value() > update_threshold { - Self::update_target_score_unchecked(who, imbalance); - } else { - // buffer the approvals update in `UnsettledTargetScore` map. - UnsettledTargetScore::::insert( - who, - UnsettledTargetScore::::get(who).unwrap_or_default().add(imbalance), - ); - } - } else { - Self::update_target_score_unchecked(who, imbalance); - } - } - - pub(crate) fn update_target_score_unchecked( - who: &T::AccountId, - imbalance: StakeImbalance, - ) { + // update target score. match imbalance { StakeImbalance::Positive(imbalance) => { let _ = T::TargetList::on_increase(who, imbalance).defensive_proof( @@ -426,7 +280,6 @@ pub mod pallet { defensive!("unexpected: unable to fetch score from staking interface of an existent staker"); } }, - StakeImbalance::Zero => (), // update not needed. }; } @@ -457,33 +310,6 @@ pub mod pallet { size_before != dedup.len() } - - #[cfg(feature = "runtime-benchmarks")] - pub(crate) fn setup_target_with_unsettled_score(target: &T::AccountId) -> DispatchResult { - // fund target account. - let mut balance = T::Currency::minimum_balance(); - for _ in 0..100 { - balance = balance + T::Currency::minimum_balance(); - } - let _ = T::Currency::set_balance(target, balance + T::Currency::minimum_balance()); - - ::bond(target, balance, target)?; - ::validate(target)?; - - UnsettledTargetScore::::insert(target, StakeImbalance::Positive(10)); - - Ok(()) - } - } -} - -/// Returns a vec with all the unsettled scores. -pub struct UnsettledTargetScores(PhantomData); -impl sp_runtime::traits::TypedGet for UnsettledTargetScores { - type Type = UnsettledList; - - fn get() -> Self::Type { - UnsettledTargetScore::::iter().collect::>() } } @@ -573,9 +399,6 @@ impl OnStakingUpdate> for Pallet { if score.is_zero() { let _ = T::TargetList::on_remove(who) .defensive_proof("target exists as per above; qed"); - - // ensure that the unsettled score list is cleaned. - let _ = UnsettledTargetScore::::take(who); } } else { // target is not part of the list. Given the contract with staking and the checks above, diff --git a/substrate/frame/staking/stake-tracker/src/mock.rs b/substrate/frame/staking/stake-tracker/src/mock.rs index ddbc02e3cdc2..b326ba52e697 100644 --- a/substrate/frame/staking/stake-tracker/src/mock.rs +++ b/substrate/frame/staking/stake-tracker/src/mock.rs @@ -31,7 +31,7 @@ type Block = frame_system::mocking::MockBlockU32; // Configure a mock runtime to test the pallet. #[frame_support::runtime] -pub mod runtime { +mod runtime { #[runtime::runtime] #[runtime::derive( RuntimeCall, @@ -98,6 +98,8 @@ const TARGET_THRESHOLDS: [u128; 9] = [100, 200, 300, 400, 500, 600, 700, 800, 90 parameter_types! { pub static VoterBagThresholds: &'static [VoteWeight] = &VOTER_THRESHOLDS; pub static TargetBagThresholds: &'static [u128] = &TARGET_THRESHOLDS; + + pub static VoterUpdateMode: crate::VoterUpdateMode = crate::VoterUpdateMode::Strict; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -118,20 +120,12 @@ impl pallet_bags_list::Config for Test { type Score = u128; } -parameter_types! { - pub static VoterUpdateMode: crate::VoterUpdateMode = crate::VoterUpdateMode::Strict; - // disables the lazy approvals update. - pub static ScoreStrictUpdateThreshold: Option = None; -} - impl pallet_stake_tracker::Config for Test { type Currency = Balances; type Staking = StakingMock; type VoterList = VoterBagsList; type TargetList = TargetBagsList; type VoterUpdateMode = VoterUpdateMode; - type ScoreStrictUpdateThreshold = ScoreStrictUpdateThreshold; - type WeightInfo = (); } pub struct StakingMock {} @@ -200,7 +194,7 @@ impl StakingInterface for StakingMock { } fn minimum_validator_bond() -> Self::Balance { - 1 + unreachable!(); } fn stash_by_ctrl( @@ -222,13 +216,7 @@ impl StakingInterface for StakingMock { _value: Self::Balance, _payee: &Self::AccountId, ) -> sp_runtime::DispatchResult { - Ok(()) - } - - fn validate(who: &Self::AccountId) -> DispatchResult { - add_validator(*who, 10); - - Ok(()) + unreachable!(); } fn nominate( @@ -515,11 +503,6 @@ impl ExtBuilder { self } - pub fn set_update_threshold(self, threshold: Option) -> Self { - ScoreStrictUpdateThreshold::set(threshold); - self - } - pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/substrate/frame/staking/stake-tracker/src/tests.rs b/substrate/frame/staking/stake-tracker/src/tests.rs index 975c9ec43d2e..b53c670b0491 100644 --- a/substrate/frame/staking/stake-tracker/src/tests.rs +++ b/substrate/frame/staking/stake-tracker/src/tests.rs @@ -17,172 +17,16 @@ #![cfg(test)] -use crate::{mock::*, Error, StakeImbalance, UnsettledTargetScores}; +use crate::{mock::*, StakeImbalance}; use frame_election_provider_support::{ScoreProvider, SortedListProvider}; -use frame_support::{assert_noop, assert_ok}; -use sp_runtime::traits::TypedGet; +use frame_support::assert_ok; use sp_staking::{OnStakingUpdate, Stake, StakerStatus, StakingInterface}; // keeping tests clean. type A = AccountId; type B = Balance; -mod stake_imbalance { - use super::*; - - #[test] - fn stake_imbalance_arithmetic_works() { - use std::ops::Add; - - // 0 + 0 = 0 - assert_eq!(StakeImbalance::::Zero.add(StakeImbalance::Zero), StakeImbalance::Zero,); - - // 1 + 0 = 1 - assert_eq!( - StakeImbalance::Positive(1).add(StakeImbalance::Zero), - StakeImbalance::Positive(1), - ); - - // -1 + 0 = -1 - assert_eq!( - StakeImbalance::Negative(1).add(StakeImbalance::Zero), - StakeImbalance::Negative(1), - ); - - // -2 + 2 = 0 - assert_eq!( - StakeImbalance::Negative(2).add(StakeImbalance::Positive(2)), - StakeImbalance::Zero, - ); - - // 1 + 2 = 3 - assert_eq!( - StakeImbalance::Positive(1).add(StakeImbalance::Positive(2)), - StakeImbalance::Positive(3) - ); - - // 1 + (-2) = -1 - assert_eq!( - StakeImbalance::Positive(1).add(StakeImbalance::Negative(2)), - StakeImbalance::Negative(1) - ); - - // -1 + 2 = 1 - assert_eq!( - StakeImbalance::Negative(1).add(StakeImbalance::Positive(2)), - StakeImbalance::Positive(1) - ); - - // -1 + (-2) = -3 - assert_eq!( - StakeImbalance::Negative(1).add(StakeImbalance::Negative(2)), - StakeImbalance::Negative(3) - ); - } - - #[test] - fn updates_below_threshold_buffer_works() { - ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { - add_validator(10, 100); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); - - // updating stake by 200 will reflect in the target list. - update_stake(10, 200, stake_of(10)); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); - // unsettled stake list is empty. - assert_eq!(UnsettledTargetScores::::get(), vec![]); - - // updating stake by +5 (below thresahold) will *not* reflect in the target list and - // update the unsettled stake list. - update_stake(10, 205, stake_of(10)); - // target list was not updated. - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); - // unsettled stake list has the bufferd score for target 10. - assert_eq!( - UnsettledTargetScores::::get(), - vec![(10u64, StakeImbalance::Positive(5))] - ); - - // updating the stake by -7 is still below the threshold and thus target list is not - // affected. The buffered score will be updated accordingly. - update_stake(10, 198, stake_of(10)); - // target list was not updated. - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 200); - // unsettled stake list has the bufferd score for target 10. - assert_eq!( - UnsettledTargetScores::::get(), - vec![(10u64, StakeImbalance::Negative(2))] - ); - - // finally, settling the buffered target score for 10 will affect the target's - // approvals. - assert_ok!(StakeTracker::do_settle(&10)); - // +5 + (-7) imbalance = (-2), thus approvals is initial approvals - 2. - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 198); - // unsettled stake list is empty again. - assert_eq!(UnsettledTargetScores::::get(), vec![]); - }) - } - - #[test] - fn settle_buffered_score_works() { - ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { - add_validator(10, 100); - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); - assert_eq!(UnsettledTargetScores::::get(), vec![]); - - // updating stake by +5 (below thresahold) will *not* reflect in the target list and - // update the unsettled stake list. - update_stake(10, 105, stake_of(10)); - // target list was not updated. - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 100); - // unsettled stake list has the bufferd score for target 10. - assert_eq!( - UnsettledTargetScores::::get(), - vec![(10u64, StakeImbalance::Positive(5))] - ); - - // calls `settle` extrinsic to settle the buffered score of 10. - assert_ok!(StakeTracker::settle(RuntimeOrigin::signed(1), 10)); - - // approvals were updated accordingly - assert_eq!(TargetBagsList::get_score(&10).unwrap(), 105); - // unsettled stake list is empty again. - assert_eq!(UnsettledTargetScores::::get(), vec![]); - - // calling `settle` with target account that does not have buffered score errors. - assert_noop!( - StakeTracker::settle(RuntimeOrigin::signed(1), 10), - Error::::NoScoreToSettle, - ); - }) - } - - #[test] - fn settle_buffered_score_error_works() { - ExtBuilder::default().set_update_threshold(Some(10)).build_and_execute(|| { - assert!(!TargetBagsList::contains(&100)); - - // calling `settle` of an account that does not exist in the target list errors. - assert_noop!( - StakeTracker::settle(RuntimeOrigin::signed(1), 100), - Error::::NotTarget, - ); - - add_validator(10, 100); - assert!(TargetBagsList::contains(&10)); - assert_eq!(UnsettledTargetScores::::get(), vec![]); - - // calling `settle` with target account that does not have buffered score errors. - assert_noop!( - StakeTracker::settle(RuntimeOrigin::signed(1), 10), - Error::::NoScoreToSettle, - ); - }) - } -} - #[test] fn setup_works() { ExtBuilder::default().build_and_execute(|| { diff --git a/substrate/frame/staking/stake-tracker/src/weights.rs b/substrate/frame/staking/stake-tracker/src/weights.rs deleted file mode 100644 index 86ff3397cd33..000000000000 --- a/substrate/frame/staking/stake-tracker/src/weights.rs +++ /dev/null @@ -1,89 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `pallet_staking` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-05-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-unxyhko3-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// target/production/substrate-node -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_stake_tracker -// --chain=dev -// --header=./substrate/HEADER-APACHE2 -// --output=./substrate/frame/staking/stake-tracker/src/weights.rs -// --template=./substrate/.maintain/frame-weight-template.hbs - - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_stake_tracker`. -pub trait WeightInfo { - fn settle() -> Weight; -} - -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `TargetList::ListNodes` (r:1 w:1) - /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `StakeTracker::UnsettledScore` (r:1 w:1) - /// Proof: `StakeTracker::UnsettledScore` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) - fn settle() -> Weight { - // Proof Size summary in bytes: - // Measured: `606` - // Estimated: `3635` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(20_000_000, 0) - .saturating_add(Weight::from_parts(0, 3635)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `TargetList::ListNodes` (r:1 w:1) - /// Proof: `TargetList::ListNodes` (`max_values`: None, `max_size`: Some(170), added: 2645, mode: `MaxEncodedLen`) - /// Storage: `StakeTracker::UnsettledScore` (r:1 w:1) - /// Proof: `StakeTracker::UnsettledScore` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `MaxEncodedLen`) - fn settle() -> Weight { - // Proof Size summary in bytes: - // Measured: `606` - // Estimated: `3635` - // Minimum execution time: 19_000_000 picoseconds. - Weight::from_parts(20_000_000, 0) - .saturating_add(Weight::from_parts(0, 3635)) - } -} - diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 72014ecdb60b..8328dd664633 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -324,9 +324,6 @@ pub trait StakingInterface { fn bond(who: &Self::AccountId, value: Self::Balance, payee: &Self::AccountId) -> DispatchResult; - /// Have `who` become a validator with default preferences. - fn validate(who: &Self::AccountId) -> DispatchResult; - /// Have `who` nominate `validators`. fn nominate(who: &Self::AccountId, validators: Vec) -> DispatchResult;