Update elections-phragmen weight to WeightInfo (#7161)

* Update elections-phragmen weight to WeightInfo

* Fix benchmark tests

* Update weights

* Update test

* Update another thest :"

* Weights from benchmarking machine

./substrate2/target/release/substrate benchmark --chain dev --steps 50 --repeat 20 --pallet pallet_elections_phragmen --extrinsic "*" --raw --execution=wasm --wasm-execution=compiled --output

* Update weights from the benchmarking machine

* Fix tests one last time

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Kian Paimani
2020-09-22 14:06:15 +02:00
committed by GitHub
parent fc77d1d466
commit f70ef87a0c
7 changed files with 336 additions and 128 deletions
@@ -28,10 +28,18 @@ use crate::Module as Elections;
const BALANCE_FACTOR: u32 = 250;
const MAX_VOTERS: u32 = 500;
const MAX_CANDIDATES: u32 = 100;
const MAX_CANDIDATES: u32 = 200;
type Lookup<T> = <<T as frame_system::Trait>::Lookup as StaticLookup>::Source;
macro_rules! whitelist {
($acc:ident) => {
frame_benchmarking::benchmarking::add_to_whitelist(
frame_system::Account::<T>::hashed_key_for(&$acc).into()
);
};
}
/// grab new account with infinite balance.
fn endowed_account<T: Trait>(name: &'static str, index: u32) -> T::AccountId {
let account: T::AccountId = account(name, index, 0);
@@ -40,6 +48,7 @@ fn endowed_account<T: Trait>(name: &'static str, index: u32) -> T::AccountId {
// important to increase the total issuance since T::CurrencyToVote will need it to be sane for
// phragmen to work.
T::Currency::issue(amount);
account
}
@@ -102,10 +111,9 @@ fn submit_candidates_with_self_vote<T: Trait>(c: u32, prefix: &'static str)
/// Submit one voter.
fn submit_voter<T: Trait>(caller: T::AccountId, votes: Vec<T::AccountId>, stake: BalanceOf<T>)
-> Result<(), &'static str>
-> Result<(), sp_runtime::DispatchError>
{
<Elections<T>>::vote(RawOrigin::Signed(caller).into(), votes, stake)
.map_err(|_| "failed to submit vote")
}
/// create `num_voter` voters who randomly vote for at most `votes` of `all_candidates` if
@@ -131,7 +139,7 @@ fn distribute_voters<T: Trait>(mut all_candidates: Vec<T::AccountId>, num_voters
/// Fill the seats of members and runners-up up until `m`. Note that this might include either only
/// members, or members and runners-up.
fn fill_seats_up_to<T: Trait>(m: u32) -> Result<Vec<T::AccountId>, &'static str> {
let candidates = submit_candidates_with_self_vote::<T>(m, "fill_seats_up_to")?;
let _ = submit_candidates_with_self_vote::<T>(m, "fill_seats_up_to")?;
assert_eq!(<Elections<T>>::candidates().len() as u32, m, "wrong number of candidates.");
<Elections<T>>::do_phragmen();
assert_eq!(<Elections<T>>::candidates().len(), 0, "some candidates remaining.");
@@ -140,7 +148,13 @@ fn fill_seats_up_to<T: Trait>(m: u32) -> Result<Vec<T::AccountId>, &'static str>
m as usize,
"wrong number of members and runners-up",
);
Ok(candidates)
Ok(
<Elections<T>>::members()
.into_iter()
.map(|(x, _)| x)
.chain(<Elections<T>>::runners_up().into_iter().map(|(x, _)| x))
.collect()
)
}
/// removes all the storage items to reverse any genesis state.
@@ -152,50 +166,46 @@ fn clean<T: Trait>() {
}
benchmarks! {
_ {
// User account seed
let u in 0 .. 1000 => ();
}
_ {}
// -- Signed ones
vote {
let u in ...;
// we fix the number of voted candidates to max
let v = MAXIMUM_VOTE;
let v in 1 .. (MAXIMUM_VOTE as u32);
clean::<T>();
// create a bunch of candidates.
let all_candidates = submit_candidates::<T>(MAXIMUM_VOTE as u32, "candidates")?;
let all_candidates = submit_candidates::<T>(v, "candidates")?;
let caller = endowed_account::<T>("caller", u);
let caller = endowed_account::<T>("caller", 0);
let stake = default_stake::<T>(BALANCE_FACTOR);
// vote for all of them.
let votes = all_candidates.into_iter().take(v).collect();
let votes = all_candidates;
whitelist!(caller);
}: _(RawOrigin::Signed(caller), votes, stake)
vote_update {
let u in ...;
// we fix the number of voted candidates to max
let v = MAXIMUM_VOTE;
let v in 1 .. (MAXIMUM_VOTE as u32);
clean::<T>();
// create a bunch of candidates.
let all_candidates = submit_candidates::<T>(MAXIMUM_VOTE as u32, "candidates")?;
let all_candidates = submit_candidates::<T>(v, "candidates")?;
let caller = endowed_account::<T>("caller", u);
let caller = endowed_account::<T>("caller", 0);
let stake = default_stake::<T>(BALANCE_FACTOR);
// original votes.
let mut votes = all_candidates.into_iter().take(v).collect::<Vec<T::AccountId>>();
let mut votes = all_candidates;
submit_voter::<T>(caller.clone(), votes.clone(), stake)?;
// new votes.
votes.rotate_left(1);
whitelist!(caller);
}: vote(RawOrigin::Signed(caller), votes, stake)
remove_voter {
let u in ...;
// we fix the number of voted candidates to max
let v = MAXIMUM_VOTE as u32;
clean::<T>();
@@ -203,11 +213,12 @@ benchmarks! {
// create a bunch of candidates.
let all_candidates = submit_candidates::<T>(v, "candidates")?;
let caller = endowed_account::<T>("caller", u);
let caller = endowed_account::<T>("caller", 0);
let stake = default_stake::<T>(BALANCE_FACTOR);
submit_voter::<T>(caller.clone(), all_candidates, stake)?;
whitelist!(caller);
}: _(RawOrigin::Signed(caller))
report_defunct_voter_correct {
@@ -217,11 +228,11 @@ benchmarks! {
// number of candidates that the reported voter voted for. The worse case of search here is
// basically `c * v`.
let v in 1 .. (MAXIMUM_VOTE as u32);
// we fix the number of members to when members and runners-up to the desired. We'll be in
// we fix the number of members to the number of desired members and runners-up. We'll be in
// this state almost always.
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
clean::<T>();
clean::<T>();
let stake = default_stake::<T>(BALANCE_FACTOR);
// create m members and runners combined.
@@ -231,8 +242,7 @@ benchmarks! {
let bailing_candidates = submit_candidates::<T>(v, "bailing_candidates")?;
let all_candidates = submit_candidates::<T>(c, "all_candidates")?;
// account 1 is the reporter and it doesn't matter how many it votes. But it has to be a
// voter.
// account 1 is the reporter and must be whitelisted, and a voter.
let account_1 = endowed_account::<T>("caller", 0);
submit_voter::<T>(
account_1.clone(),
@@ -248,7 +258,9 @@ benchmarks! {
stake,
)?;
// all the bailers go away.
// all the bailers go away. NOTE: we can simplify this. There's no need to create all these
// candidates and remove them. The defunct voter can just vote for random accounts as long
// as there are enough members (potential candidates).
bailing_candidates.into_iter().for_each(|b| {
let count = candidate_count::<T>();
assert!(<Elections<T>>::renounce_candidacy(
@@ -256,10 +268,13 @@ benchmarks! {
Renouncing::Candidate(count),
).is_ok());
});
let defunct = defunct_for::<T>(account_2.clone());
}: report_defunct_voter(RawOrigin::Signed(account_1.clone()), defunct)
let defunct_info = defunct_for::<T>(account_2.clone());
whitelist!(account_1);
assert!(<Elections<T>>::is_voter(&account_2));
}: report_defunct_voter(RawOrigin::Signed(account_1.clone()), defunct_info)
verify {
assert!(<Elections<T>>::is_voter(&account_1));
assert!(!<Elections<T>>::is_voter(&account_2));
#[cfg(test)]
{
@@ -276,7 +291,7 @@ benchmarks! {
// number of candidates that the reported voter voted for. The worse case of search here is
// basically `c * v`.
let v in 1 .. (MAXIMUM_VOTE as u32);
// we fix the number of members to when members and runners-up to the desired. We'll be in
// we fix the number of members to the number of desired members and runners-up. We'll be in
// this state almost always.
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
@@ -289,7 +304,7 @@ benchmarks! {
// create a bunch of candidates as well.
let all_candidates = submit_candidates::<T>(c, "candidates")?;
// account 1 is the reporter and it doesn't matter how many it votes.
// account 1 is the reporter and need to be whitelisted, and a voter.
let account_1 = endowed_account::<T>("caller", 0);
submit_voter::<T>(
account_1.clone(),
@@ -299,8 +314,9 @@ benchmarks! {
// account 2 votes for a bunch of crap, and finally a correct candidate.
let account_2 = endowed_account::<T>("caller_2", 1);
let mut invalid: Vec<T::AccountId> =
(0..(v-1)).map(|seed| account::<T::AccountId>("invalid", 0, seed).clone()).collect();
let mut invalid: Vec<T::AccountId> = (0..(v-1))
.map(|seed| account::<T::AccountId>("invalid", 0, seed).clone())
.collect();
invalid.push(all_candidates.last().unwrap().clone());
submit_voter::<T>(
account_2.clone(),
@@ -308,11 +324,11 @@ benchmarks! {
stake,
)?;
let defunct = defunct_for::<T>(account_2.clone());
// no one bails out. account_1 is slashed and removed as voter now.
}: report_defunct_voter(RawOrigin::Signed(account_1.clone()), defunct)
let defunct_info = defunct_for::<T>(account_2.clone());
whitelist!(account_1);
}: report_defunct_voter(RawOrigin::Signed(account_1.clone()), defunct_info)
verify {
assert!(!<Elections<T>>::is_voter(&account_1));
// account 2 is still a voter.
assert!(<Elections<T>>::is_voter(&account_2));
#[cfg(test)]
{
@@ -325,7 +341,7 @@ benchmarks! {
submit_candidacy {
// number of already existing candidates.
let c in 1 .. MAX_CANDIDATES;
// we fix the number of members to when members and runners-up to the desired. We'll be in
// we fix the number of members to the number of desired members and runners-up. We'll be in
// this state almost always.
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
@@ -340,6 +356,7 @@ benchmarks! {
// we assume worse case that: extrinsic is successful and candidate is not duplicate.
let candidate_account = endowed_account::<T>("caller", 0);
whitelist!(candidate_account);
}: _(RawOrigin::Signed(candidate_account.clone()), candidate_count::<T>())
verify {
#[cfg(test)]
@@ -355,7 +372,7 @@ benchmarks! {
// limited by the runtime bound, nonetheless we fill them by `m`.
// number of already existing candidates.
let c in 1 .. MAX_CANDIDATES;
// we fix the number of members to when members and runners-up to the desired. We'll be in
// we fix the number of members to the number of desired members and runners-up. We'll be in
// this state almost always.
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
@@ -367,6 +384,7 @@ benchmarks! {
let bailing = all_candidates[0].clone(); // Should be ("caller", 0)
let count = candidate_count::<T>();
whitelist!(bailing);
}: renounce_candidacy(RawOrigin::Signed(bailing), Renouncing::Candidate(count))
verify {
#[cfg(test)]
@@ -377,11 +395,10 @@ benchmarks! {
}
}
renounce_candidacy_member_runner_up {
renounce_candidacy_members {
// removing members and runners will be cheaper than a candidate.
// we fix the number of members to when members and runners-up to the desired. We'll be in
// this state almost always.
let u in ...;
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
clean::<T>();
@@ -389,14 +406,34 @@ benchmarks! {
let members_and_runners_up = fill_seats_up_to::<T>(m)?;
let bailing = members_and_runners_up[0].clone();
let renouncing = if <Elections<T>>::is_member(&bailing) {
Renouncing::Member
} else if <Elections<T>>::is_runner_up(&bailing) {
Renouncing::RunnerUp
} else {
panic!("Bailing must be a member or runner-up for this bench to be sane.");
};
}: renounce_candidacy(RawOrigin::Signed(bailing.clone()), renouncing)
assert!(<Elections<T>>::is_member(&bailing));
whitelist!(bailing);
}: renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::Member)
verify {
#[cfg(test)]
{
// reset members in between benchmark tests.
use crate::tests::MEMBERS;
MEMBERS.with(|m| *m.borrow_mut() = vec![]);
}
}
renounce_candidacy_runners_up {
// removing members and runners will be cheaper than a candidate.
// we fix the number of members to when members and runners-up to the desired. We'll be in
// this state almost always.
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
clean::<T>();
// create m members and runners combined.
let members_and_runners_up = fill_seats_up_to::<T>(m)?;
let bailing = members_and_runners_up[T::DesiredMembers::get() as usize + 1].clone();
assert!(<Elections<T>>::is_runner_up(&bailing));
whitelist!(bailing);
}: renounce_candidacy(RawOrigin::Signed(bailing.clone()), Renouncing::RunnerUp)
verify {
#[cfg(test)]
{
@@ -407,6 +444,7 @@ benchmarks! {
}
// -- Root ones
#[extra] // this calls into phragmen and consumes a full block for now.
remove_member_without_replacement {
// worse case is when we remove a member and we have no runner as a replacement. This
// triggers phragmen again. The only parameter is how many candidates will compete for the
@@ -440,7 +478,6 @@ benchmarks! {
remove_member_with_replacement {
// easy case. We have a runner up. Nothing will have that much of an impact. m will be
// number of members and runners. There is always at least one runner.
let u in ...;
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
clean::<T>();
@@ -461,7 +498,6 @@ benchmarks! {
remove_member_wrong_refund {
// The root call by mistake indicated that this will have no replacement, while it has!
// this has now consumed a lot of weight and need to refund.
let u in ...;
let m = T::DesiredMembers::get() + T::DesiredRunnersUp::get();
clean::<T>();
@@ -484,6 +520,7 @@ benchmarks! {
}
}
#[extra]
on_initialize {
// if n % TermDuration is zero, then we run phragmen. The weight function must and should
// check this as it is cheap to do so. TermDuration is not a storage item, it is a constant
@@ -514,6 +551,7 @@ benchmarks! {
}
}
#[extra]
phragmen {
// This is just to focus on phragmen in the context of this module. We always select 20
// members, this is hard-coded in the runtime and cannot be trivially changed at this stage.
@@ -578,7 +616,11 @@ mod tests {
});
ExtBuilder::default().desired_members(13).desired_runners_up(7).build_and_execute(|| {
assert_ok!(test_benchmark_renounce_candidacy_member_runner_up::<Test>());
assert_ok!(test_benchmark_renounce_candidacy_runners_up::<Test>());
});
ExtBuilder::default().desired_members(13).desired_runners_up(7).build_and_execute(|| {
assert_ok!(test_benchmark_renounce_candidacy_members::<Test>());
});
ExtBuilder::default().desired_members(13).desired_runners_up(7).build_and_execute(|| {