mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 11:41:02 +00:00
Execute try-state at end of each test to ensure pallet data integrity (#12453)
* execute try-state at end of tests * run post condition only with try runtime * Revert "run post condition only with try runtime" This reverts commit 7db0ecf7eaa2ee5afa5a995487b73d023ba3bcd9. * voterlist contains validators as well * fmt * simplify * fmt Co-authored-by: parity-processbot <>
This commit is contained in:
@@ -18,9 +18,7 @@
|
||||
//! Test utilities
|
||||
|
||||
use crate::{self as pallet_staking, *};
|
||||
use frame_election_provider_support::{
|
||||
onchain, SequentialPhragmen, SortedListProvider, VoteWeight,
|
||||
};
|
||||
use frame_election_provider_support::{onchain, SequentialPhragmen, VoteWeight};
|
||||
use frame_support::{
|
||||
assert_ok, parameter_types,
|
||||
traits::{
|
||||
@@ -548,108 +546,10 @@ impl ExtBuilder {
|
||||
sp_tracing::try_init_simple();
|
||||
let mut ext = self.build();
|
||||
ext.execute_with(test);
|
||||
ext.execute_with(post_conditions);
|
||||
}
|
||||
}
|
||||
|
||||
fn post_conditions() {
|
||||
check_nominators();
|
||||
check_exposures();
|
||||
check_ledgers();
|
||||
check_count();
|
||||
}
|
||||
|
||||
fn check_count() {
|
||||
let nominator_count = Nominators::<Test>::iter_keys().count() as u32;
|
||||
let validator_count = Validators::<Test>::iter().count() as u32;
|
||||
assert_eq!(nominator_count, Nominators::<Test>::count());
|
||||
assert_eq!(validator_count, Validators::<Test>::count());
|
||||
|
||||
// the voters that the `VoterList` list is storing for us.
|
||||
let external_voters = <Test as Config>::VoterList::count();
|
||||
assert_eq!(external_voters, nominator_count + validator_count);
|
||||
}
|
||||
|
||||
fn check_ledgers() {
|
||||
// check the ledger of all stakers.
|
||||
Bonded::<Test>::iter().for_each(|(_, ctrl)| assert_ledger_consistent(ctrl))
|
||||
}
|
||||
|
||||
fn check_exposures() {
|
||||
// a check per validator to ensure the exposure struct is always sane.
|
||||
let era = active_era();
|
||||
ErasStakers::<Test>::iter_prefix_values(era).for_each(|expo| {
|
||||
assert_eq!(
|
||||
expo.total as u128,
|
||||
expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::<u128>(),
|
||||
"wrong total exposure.",
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
fn check_nominators() {
|
||||
// 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 = active_era();
|
||||
<Nominators<Test>>::iter()
|
||||
.filter_map(
|
||||
|(nominator, nomination)| {
|
||||
if nomination.submitted_in > era {
|
||||
Some(nominator)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
.for_each(|nominator| {
|
||||
// must be bonded.
|
||||
assert_is_stash(nominator);
|
||||
let mut sum = 0;
|
||||
Session::validators()
|
||||
.iter()
|
||||
.map(|v| Staking::eras_stakers(era, v))
|
||||
.for_each(|e| {
|
||||
let individual =
|
||||
e.others.iter().filter(|e| e.who == nominator).collect::<Vec<_>>();
|
||||
let len = individual.len();
|
||||
match len {
|
||||
0 => { /* not supporting this validator at all. */ },
|
||||
1 => sum += individual[0].value,
|
||||
_ => panic!("nominator cannot back a validator more than once."),
|
||||
};
|
||||
});
|
||||
|
||||
let nominator_stake = Staking::slashable_balance_of(&nominator);
|
||||
// a nominator cannot over-spend.
|
||||
assert!(
|
||||
nominator_stake >= sum,
|
||||
"failed: Nominator({}) stake({}) >= sum divided({})",
|
||||
nominator,
|
||||
nominator_stake,
|
||||
sum,
|
||||
);
|
||||
|
||||
let diff = nominator_stake - sum;
|
||||
assert!(diff < 100);
|
||||
ext.execute_with(|| {
|
||||
Staking::do_try_state(System::block_number()).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
fn assert_is_stash(acc: AccountId) {
|
||||
assert!(Staking::bonded(&acc).is_some(), "Not a stash.");
|
||||
}
|
||||
|
||||
fn assert_ledger_consistent(ctrl: AccountId) {
|
||||
// ensures ledger.total == ledger.active + sum(ledger.unlocking).
|
||||
let ledger = Staking::ledger(ctrl).expect("Not a controller.");
|
||||
let real_total: Balance = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value);
|
||||
assert_eq!(real_total, ledger.total);
|
||||
assert!(
|
||||
ledger.active >= Balances::minimum_balance() || ledger.active == 0,
|
||||
"{}: active ledger amount ({}) must be greater than ED {}",
|
||||
ctrl,
|
||||
ledger.active,
|
||||
Balances::minimum_balance()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn active_era() -> EraIndex {
|
||||
|
||||
@@ -1552,11 +1552,12 @@ impl<T: Config> StakingInterface for Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "try-runtime")]
|
||||
#[cfg(any(test, feature = "try-runtime"))]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub(crate) fn do_try_state(_: BlockNumberFor<T>) -> Result<(), &'static str> {
|
||||
ensure!(
|
||||
T::VoterList::iter().all(|x| <Nominators<T>>::contains_key(&x)),
|
||||
T::VoterList::iter()
|
||||
.all(|x| <Nominators<T>>::contains_key(&x) || <Validators<T>>::contains_key(&x)),
|
||||
"VoterList contains non-nominators"
|
||||
);
|
||||
T::VoterList::try_state()?;
|
||||
|
||||
Reference in New Issue
Block a user