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

Bound staking storage items #12230

Merged
merged 39 commits into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e03fdee
replace pallet level unboundedness to individual storage items
Ank4n Sep 7, 2022
9ac3c47
bound structs
Ank4n Sep 7, 2022
9321b61
bounding history depth
Ank4n Sep 8, 2022
b816866
defensive error
Ank4n Sep 9, 2022
c55de4f
use the era history depth from config
Ank4n Sep 9, 2022
8cf856b
clean up history depth from storage in v11
Ank4n Sep 9, 2022
5904724
keep the name HistoryDepth for the new configuration value
Ank4n Sep 9, 2022
477e122
use u32 for history depth in node runtime
Ank4n Sep 9, 2022
49682d9
improve doc comments
Ank4n Sep 12, 2022
5084202
add HistoryDepth to mock runtimes with pallet-staking
Ank4n Sep 12, 2022
16b80ff
rustfmt
Ank4n Sep 12, 2022
1726af2
refactor and doc improve
Ank4n Sep 12, 2022
a652db7
apply re-benchmarked weight for staking
Ank4n Sep 12, 2022
ba57f5d
pr feedback improvements
Ank4n Sep 13, 2022
36595e7
test for claimed rewards following the expected bounds
Ank4n Sep 13, 2022
95baa04
refactor test to calculate first and last reward era programmatically
Ank4n Sep 13, 2022
420133a
verify previous eras cannot be claimed
Ank4n Sep 13, 2022
f43fe8c
add migration v12
Ank4n Sep 19, 2022
fc63040
".git/.scripts/bench-bot.sh" pallet dev pallet_staking
Sep 19, 2022
a94d03b
fix compiler error
Ank4n Sep 19, 2022
0f56a7c
Merge remote-tracking branch 'origin/master' into ankan/bound-staking…
Sep 19, 2022
5e76abe
corrupting history depth does not lead to catastrophic issue
Ank4n Sep 20, 2022
3d76533
fix new line
Ank4n Sep 20, 2022
ee6d571
remove unused import
Ank4n Sep 20, 2022
2f5c9e4
fmt
Ank4n Sep 20, 2022
bc7ca47
add test to document scenario where history depth is reduced without …
Ank4n Sep 20, 2022
00b916c
fmt
Ank4n Sep 20, 2022
8db1b59
Update frame/staking/src/lib.rs
Ank4n Sep 20, 2022
c6dfcbf
Update frame/staking/src/migrations.rs
Ank4n Sep 20, 2022
121557d
doc for all storage items bounded by HistoryDepth
Ank4n Sep 20, 2022
5ae9c8c
Update frame/staking/src/pallet/mod.rs
Ank4n Sep 20, 2022
36b590d
Update frame/staking/src/tests.rs
Ank4n Sep 20, 2022
a8f0e7d
pr feedback fixes
Ank4n Sep 20, 2022
1010ed5
Update frame/staking/src/tests.rs
Ank4n Sep 20, 2022
1149e3b
Merge branch 'master' of github.com:paritytech/substrate into ankan/b…
kianenigma Sep 20, 2022
635bada
remove extra checks
kianenigma Sep 20, 2022
bc476c0
Merge branch 'master' into ankan/bound-staking-storage-trivial
Ank4n Sep 21, 2022
734fb6a
fix merge
Ank4n Sep 21, 2022
8c3ac49
fmt
Ank4n Sep 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ parameter_types! {
pub const MaxNominatorRewardedPerValidator: u32 = 256;
pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
pub OffchainRepeat: BlockNumber = 5;
pub HistoryDepth: u32 = 84;
}

pub struct StakingBenchmarkingConfig;
Expand Down Expand Up @@ -572,6 +573,7 @@ impl pallet_staking::Config for Runtime {
// This a placeholder, to be introduced in the next PR as an instance of bags-list
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = HistoryDepth;
type OnStakerSlash = NominationPools;
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
type BenchmarkingConfig = StakingBenchmarkingConfig;
Expand Down
1 change: 1 addition & 0 deletions frame/babe/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ impl pallet_staking::Config for Test {
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
1 change: 1 addition & 0 deletions frame/grandpa/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ impl pallet_staking::Config for Test {
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
1 change: 1 addition & 0 deletions frame/nomination-pools/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ impl pallet_staking::Config for Runtime {
type VoterList = VoterList;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type OnStakerSlash = Pools;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
1 change: 1 addition & 0 deletions frame/nomination-pools/test-staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ impl pallet_staking::Config for Runtime {
type VoterList = VoterList;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type OnStakerSlash = Pools;
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
1 change: 1 addition & 0 deletions frame/offences/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ impl pallet_staking::Config for Test {
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type OnStakerSlash = ();
type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
1 change: 1 addition & 0 deletions frame/session/benchmarking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl pallet_staking::Config for Test {
type ElectionProvider = onchain::UnboundedExecution<OnChainSeqPhragmen>;
type GenesisElectionProvider = Self::ElectionProvider;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = ConstU32<84>;
type VoterList = pallet_staking::UseNominatorsAndValidatorsMap<Self>;
type TargetList = pallet_staking::UseValidatorsMap<Self>;
type OnStakerSlash = ();
Expand Down
21 changes: 1 addition & 20 deletions frame/staking/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,25 +660,6 @@ benchmarks! {
assert!(original_bonded < new_bonded);
}

set_history_depth {
let e in 1 .. 100;
HistoryDepth::<T>::put(e);
CurrentEra::<T>::put(e);
let dummy = || -> T::AccountId { codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() };
for i in 0 .. e {
<ErasStakers<T>>::insert(i, dummy(), Exposure::<T::AccountId, BalanceOf<T>>::default());
<ErasStakersClipped<T>>::insert(i, dummy(), Exposure::<T::AccountId, BalanceOf<T>>::default());
<ErasValidatorPrefs<T>>::insert(i, dummy(), ValidatorPrefs::default());
<ErasValidatorReward<T>>::insert(i, BalanceOf::<T>::one());
<ErasRewardPoints<T>>::insert(i, EraRewardPoints::<T::AccountId>::default());
<ErasTotalStake<T>>::insert(i, BalanceOf::<T>::one());
ErasStartSessionIndex::<T>::insert(i, i);
}
}: _(RawOrigin::Root, EraIndex::zero(), u32::MAX)
verify {
assert_eq!(HistoryDepth::<T>::get(), 0);
}

reap_stash {
let s in 1 .. MAX_SPANS;
// clean up any existing state.
Expand All @@ -698,7 +679,7 @@ benchmarks! {
active: T::Currency::minimum_balance() - One::one(),
total: T::Currency::minimum_balance() - One::one(),
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
};
Ledger::<T>::insert(&controller, l);

Expand Down
38 changes: 25 additions & 13 deletions frame/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,12 @@ pub mod weights;

mod pallet;

use codec::{Decode, Encode, HasCompact};
use codec::{Decode, Encode, HasCompact, MaxEncodedLen};
use frame_support::{
parameter_types,
traits::{Currency, Defensive, Get},
weights::Weight,
BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound,
};
use scale_info::TypeInfo;
use sp_runtime::{
Expand Down Expand Up @@ -354,7 +354,7 @@ parameter_types! {
}

/// Information regarding the active era (era in used in session).
#[derive(Encode, Decode, RuntimeDebug, TypeInfo)]
#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct ActiveEraInfo {
/// Index of era.
pub index: EraIndex,
Expand Down Expand Up @@ -395,7 +395,7 @@ pub enum StakerStatus<AccountId> {
}

/// A destination account for payment.
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub enum RewardDestination<AccountId> {
/// Pay into the stash account, increasing the amount at stake accordingly.
Staked,
Expand All @@ -416,7 +416,7 @@ impl<AccountId> Default for RewardDestination<AccountId> {
}

/// Preference of what happens regarding validation.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)]
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)]
pub struct ValidatorPrefs {
/// Reward that validator takes up-front; only the rest is split between themselves and
/// nominators.
Expand All @@ -429,8 +429,8 @@ pub struct ValidatorPrefs {
}

/// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
pub struct UnlockChunk<Balance: HasCompact> {
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
pub struct UnlockChunk<Balance: HasCompact + MaxEncodedLen> {
/// Amount of funds to be unlocked.
#[codec(compact)]
value: Balance,
Expand All @@ -440,7 +440,16 @@ pub struct UnlockChunk<Balance: HasCompact> {
}

/// The ledger of a (bonded) stash.
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)]
#[derive(
PartialEqNoBound,
EqNoBound,
CloneNoBound,
Encode,
Decode,
RuntimeDebugNoBound,
TypeInfo,
MaxEncodedLen,
)]
#[scale_info(skip_type_params(T))]
pub struct StakingLedger<T: Config> {
/// The stash account whose balance is actually locked and at stake.
Expand All @@ -459,7 +468,7 @@ pub struct StakingLedger<T: Config> {
pub unlocking: BoundedVec<UnlockChunk<BalanceOf<T>>, MaxUnlockingChunks>,
/// List of eras for which the stakers behind a validator have claimed rewards. Only updated
/// for validators.
pub claimed_rewards: Vec<EraIndex>,
pub claimed_rewards: BoundedVec<EraIndex, T::HistoryDepth>,
}

impl<T: Config> StakingLedger<T> {
Expand All @@ -470,7 +479,7 @@ impl<T: Config> StakingLedger<T> {
total: Zero::zero(),
active: Zero::zero(),
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
}
}

Expand Down Expand Up @@ -676,7 +685,9 @@ impl<T: Config> StakingLedger<T> {
}

/// A record of the nominations made by a specific account.
#[derive(PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)]
#[derive(
PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen,
)]
#[codec(mel_bound())]
#[scale_info(skip_type_params(T))]
pub struct Nominations<T: Config> {
Expand Down Expand Up @@ -850,7 +861,7 @@ impl<Balance: AtLeast32BitUnsigned + Clone, T: Get<&'static PiecewiseLinear<'sta
}

/// Mode of era-forcing.
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)]
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum Forcing {
/// Not forcing anything - just let whatever happen.
Expand All @@ -874,7 +885,7 @@ impl Default for Forcing {
// A value placed in storage that represents the current version of the Staking storage. This value
// is used by the `on_runtime_upgrade` logic to determine whether we run storage migration logic.
// This should match directly with the semantic versions of the Rust crate.
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)]
#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)]
enum Releases {
V1_0_0Ancient,
V2_0_0,
Expand All @@ -887,6 +898,7 @@ enum Releases {
V9_0_0, // inject validators into `VoterList` as well.
V10_0_0, // remove `EarliestUnappliedSlash`.
V11_0_0, // Move pallet storage prefix, e.g. BagsList -> VoterBagsList
V12_0_0, // remove `HistoryDepth`
Ank4n marked this conversation as resolved.
Show resolved Hide resolved
}

impl Default for Releases {
Expand Down
53 changes: 53 additions & 0 deletions frame/staking/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,59 @@ use super::*;
use frame_election_provider_support::SortedListProvider;
use frame_support::traits::OnRuntimeUpgrade;

pub mod v12 {
use super::*;
use frame_support::{pallet_prelude::ValueQuery, storage_alias};

#[storage_alias]
type HistoryDepth<T: Config> = StorageValue<Pallet<T>, u32, ValueQuery>;

/// Clean up `HistoryDepth` from storage
///
/// We will be depending on the configurable value of `HistoryDepth` post
/// this release.
Ank4n marked this conversation as resolved.
Show resolved Hide resolved
pub struct MigrateToV12<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for MigrateToV12<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<(), &'static str> {
use frame_support::traits::OnRuntimeUpgradeHelpersExt;
frame_support::ensure!(
StorageVersion::<T>::get() == Releases::V11_0_0,
"Expected v11 before upgrading to v12"
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For testing purposes, we might need to remove this.


frame_support::ensure!(
T::HistoryDepth::get() == HistoryDepth::<T>::get(),
"Provided value of HistoryDepth should be same as the existing storage value"
);

Ok(())
}

fn on_runtime_upgrade() -> frame_support::weights::Weight {
if StorageVersion::<T>::get() == Releases::V11_0_0 {
HistoryDepth::<T>::kill();
StorageVersion::<T>::put(Releases::V12_0_0);

log!(info, "v12 applied successfully");
T::DbWeight::get().reads_writes(1, 2)
} else {
log!(warn, "Skipping v12, should be removed");
T::DbWeight::get().reads(1)
}
}

#[cfg(feature = "try-runtime")]
fn post_upgrade() -> Result<(), &'static str> {
frame_support::ensure!(
StorageVersion::<T>::get() == crate::Releases::V12_0_0,
"v12 not applied"
);
Ok(())
}
}
}

pub mod v11 {
use super::*;
use frame_support::{
Expand Down
2 changes: 2 additions & 0 deletions frame/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] =
parameter_types! {
pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS;
pub static MaxNominations: u32 = 16;
pub static HistoryDepth: u32 = 80;
pub static RewardOnUnbalanceWasCalled: bool = false;
pub static LedgerSlashPerEra: (BalanceOf<Test>, BTreeMap<EraIndex, BalanceOf<Test>>) = (Zero::zero(), BTreeMap::new());
}
Expand Down Expand Up @@ -301,6 +302,7 @@ impl crate::pallet::pallet::Config for Test {
type VoterList = VoterBagsList;
type TargetList = UseValidatorsMap<Self>;
type MaxUnlockingChunks = ConstU32<32>;
type HistoryDepth = HistoryDepth;
type OnStakerSlash = OnStakerSlashMock<Test>;
type BenchmarkingConfig = TestBenchmarkingConfig;
type WeightInfo = ();
Expand Down
25 changes: 16 additions & 9 deletions frame/staking/src/pallet/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use frame_support::{
dispatch::WithPostDispatchInfo,
pallet_prelude::*,
traits::{
Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance,
LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons,
Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get,
Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons,
},
weights::Weight,
};
Expand Down Expand Up @@ -101,7 +101,7 @@ impl<T: Config> Pallet<T> {
Error::<T>::InvalidEraToReward
.with_weight(T::WeightInfo::payout_stakers_alive_staked(0))
})?;
let history_depth = Self::history_depth();
let history_depth = T::HistoryDepth::get();
ensure!(
era <= current_era && era >= current_era.saturating_sub(history_depth),
Error::<T>::InvalidEraToReward
Expand All @@ -123,11 +123,18 @@ impl<T: Config> Pallet<T> {
ledger
.claimed_rewards
.retain(|&x| x >= current_era.saturating_sub(history_depth));

match ledger.claimed_rewards.binary_search(&era) {
Ok(_) =>
return Err(Error::<T>::AlreadyClaimed
.with_weight(T::WeightInfo::payout_stakers_alive_staked(0))),
Err(pos) => ledger.claimed_rewards.insert(pos, era),
Err(pos) => ledger
.claimed_rewards
.try_insert(pos, era)
// Since we retain era entries in `claimed_rewards` only upto
// `HistoryDepth`, following bound is always expected to be
// satisfied.
.defensive_map_err(|_| Error::<T>::BoundNotMet)?,
}

let exposure = <ErasStakersClipped<T>>::get(&era, &ledger.stash);
Expand Down Expand Up @@ -417,7 +424,7 @@ impl<T: Config> Pallet<T> {
ErasStartSessionIndex::<T>::insert(&new_planned_era, &start_session_index);

// Clean old era information.
if let Some(old_era) = new_planned_era.checked_sub(Self::history_depth() + 1) {
if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) {
Self::clear_era_information(old_era);
}

Expand Down Expand Up @@ -966,7 +973,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {
active: stake,
total: stake,
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
},
);

Expand All @@ -984,7 +991,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {
active: stake,
total: stake,
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
},
);
Self::do_add_validator(
Expand Down Expand Up @@ -1025,7 +1032,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {
active: stake,
total: stake,
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
},
);
Self::do_add_validator(
Expand All @@ -1046,7 +1053,7 @@ impl<T: Config> ElectionDataProvider for Pallet<T> {
active: stake,
total: stake,
unlocking: Default::default(),
claimed_rewards: vec![],
claimed_rewards: Default::default(),
},
);
Self::do_add_nominator(
Expand Down
Loading