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

Commit 68514eb

Browse files
author
Ross Bulat
committed
Revert "Configurable voting-degree in council elections pallet (#13305)"
This reverts commit 8e9f249.
1 parent 1f95dc1 commit 68514eb

File tree

5 files changed

+240
-216
lines changed

5 files changed

+240
-216
lines changed

bin/node/runtime/src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,9 +1003,8 @@ parameter_types! {
10031003
pub const TermDuration: BlockNumber = 7 * DAYS;
10041004
pub const DesiredMembers: u32 = 13;
10051005
pub const DesiredRunnersUp: u32 = 7;
1006-
pub const MaxVotesPerVoter: u32 = 16;
1007-
pub const MaxVoters: u32 = 512;
1008-
pub const MaxCandidates: u32 = 64;
1006+
pub const MaxVoters: u32 = 10 * 1000;
1007+
pub const MaxCandidates: u32 = 1000;
10091008
pub const ElectionsPhragmenPalletId: LockIdentifier = *b"phrelect";
10101009
}
10111010

@@ -1030,7 +1029,6 @@ impl pallet_elections_phragmen::Config for Runtime {
10301029
type DesiredRunnersUp = DesiredRunnersUp;
10311030
type TermDuration = TermDuration;
10321031
type MaxVoters = MaxVoters;
1033-
type MaxVotesPerVoter = MaxVotesPerVoter;
10341032
type MaxCandidates = MaxCandidates;
10351033
type WeightInfo = pallet_elections_phragmen::weights::SubstrateWeight<Runtime>;
10361034
}

frame/elections-phragmen/src/benchmarking.rs

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ fn clean<T: Config>() {
148148
benchmarks! {
149149
// -- Signed ones
150150
vote_equal {
151-
let v in 1 .. T::MaxVotesPerVoter::get();
151+
let v in 1 .. (MAXIMUM_VOTE as u32);
152152
clean::<T>();
153153

154154
// create a bunch of candidates.
@@ -168,7 +168,7 @@ benchmarks! {
168168
}: vote(RawOrigin::Signed(caller), votes, stake)
169169

170170
vote_more {
171-
let v in 2 .. T::MaxVotesPerVoter::get();
171+
let v in 2 .. (MAXIMUM_VOTE as u32);
172172
clean::<T>();
173173

174174
// create a bunch of candidates.
@@ -190,7 +190,7 @@ benchmarks! {
190190
}: vote(RawOrigin::Signed(caller), votes, stake / <BalanceOf<T>>::from(10u32))
191191

192192
vote_less {
193-
let v in 2 .. T::MaxVotesPerVoter::get();
193+
let v in 2 .. (MAXIMUM_VOTE as u32);
194194
clean::<T>();
195195

196196
// create a bunch of candidates.
@@ -212,7 +212,7 @@ benchmarks! {
212212

213213
remove_voter {
214214
// we fix the number of voted candidates to max
215-
let v = T::MaxVotesPerVoter::get();
215+
let v = MAXIMUM_VOTE as u32;
216216
clean::<T>();
217217

218218
// create a bunch of candidates.
@@ -368,7 +368,7 @@ benchmarks! {
368368
clean::<T>();
369369

370370
let all_candidates = submit_candidates::<T>(T::MaxCandidates::get(), "candidates")?;
371-
distribute_voters::<T>(all_candidates, v, T::MaxVotesPerVoter::get() as usize)?;
371+
distribute_voters::<T>(all_candidates, v, MAXIMUM_VOTE)?;
372372

373373
// all candidates leave.
374374
<Candidates<T>>::kill();
@@ -389,17 +389,17 @@ benchmarks! {
389389
// that we give all candidates a self vote to make sure they are all considered.
390390
let c in 1 .. T::MaxCandidates::get();
391391
let v in 1 .. T::MaxVoters::get();
392-
let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * T::MaxVotesPerVoter::get();
392+
let e in (T::MaxVoters::get()) .. T::MaxVoters::get() as u32 * MAXIMUM_VOTE as u32;
393393
clean::<T>();
394394

395395
// so we have a situation with v and e. we want e to basically always be in the range of `e
396-
// -> e * T::MaxVotesPerVoter::get()`, but we cannot express that now with the benchmarks.
397-
// So what we do is: when c is being iterated, v, and e are max and fine. when v is being
398-
// iterated, e is being set to max and this is a problem. In these cases, we cap e to a
399-
// lower value, namely v * T::MaxVotesPerVoter::get(). when e is being iterated, v is at
400-
// max, and again fine. all in all, votes_per_voter can never be more than
401-
// T::MaxVotesPerVoter::get(). Note that this might cause `v` to be an overestimate.
402-
let votes_per_voter = (e / v).min(T::MaxVotesPerVoter::get());
396+
// -> e * MAXIMUM_VOTE`, but we cannot express that now with the benchmarks. So what we do
397+
// is: when c is being iterated, v, and e are max and fine. when v is being iterated, e is
398+
// being set to max and this is a problem. In these cases, we cap e to a lower value, namely
399+
// v * MAXIMUM_VOTE. when e is being iterated, v is at max, and again fine. all in all,
400+
// votes_per_voter can never be more than MAXIMUM_VOTE. Note that this might cause `v` to be
401+
// an overestimate.
402+
let votes_per_voter = (e / v).min(MAXIMUM_VOTE as u32);
403403

404404
let all_candidates = submit_candidates_with_self_vote::<T>(c, "candidates")?;
405405
let _ = distribute_voters::<T>(all_candidates, v.saturating_sub(c), votes_per_voter as usize)?;
@@ -421,6 +421,68 @@ benchmarks! {
421421
}
422422
}
423423

424+
#[extra]
425+
election_phragmen_c_e {
426+
let c in 1 .. T::MaxCandidates::get();
427+
let e in (T::MaxVoters::get()) .. T::MaxVoters::get() * MAXIMUM_VOTE as u32;
428+
let fixed_v = T::MaxVoters::get();
429+
clean::<T>();
430+
431+
let votes_per_voter = e / fixed_v;
432+
433+
let all_candidates = submit_candidates_with_self_vote::<T>(c, "candidates")?;
434+
let _ = distribute_voters::<T>(
435+
all_candidates,
436+
fixed_v - c,
437+
votes_per_voter as usize,
438+
)?;
439+
}: {
440+
<Elections<T>>::on_initialize(T::TermDuration::get());
441+
}
442+
verify {
443+
assert_eq!(<Elections<T>>::members().len() as u32, T::DesiredMembers::get().min(c));
444+
assert_eq!(
445+
<Elections<T>>::runners_up().len() as u32,
446+
T::DesiredRunnersUp::get().min(c.saturating_sub(T::DesiredMembers::get())),
447+
);
448+
449+
#[cfg(test)]
450+
{
451+
// reset members in between benchmark tests.
452+
use crate::tests::MEMBERS;
453+
MEMBERS.with(|m| *m.borrow_mut() = vec![]);
454+
}
455+
}
456+
457+
#[extra]
458+
election_phragmen_v {
459+
let v in 4 .. 16;
460+
let fixed_c = T::MaxCandidates::get() / 10;
461+
let fixed_e = 64;
462+
clean::<T>();
463+
464+
let votes_per_voter = fixed_e / v;
465+
466+
let all_candidates = submit_candidates_with_self_vote::<T>(fixed_c, "candidates")?;
467+
let _ = distribute_voters::<T>(all_candidates, v, votes_per_voter as usize)?;
468+
}: {
469+
<Elections<T>>::on_initialize(T::TermDuration::get());
470+
}
471+
verify {
472+
assert_eq!(<Elections<T>>::members().len() as u32, T::DesiredMembers::get().min(fixed_c));
473+
assert_eq!(
474+
<Elections<T>>::runners_up().len() as u32,
475+
T::DesiredRunnersUp::get().min(fixed_c.saturating_sub(T::DesiredMembers::get())),
476+
);
477+
478+
#[cfg(test)]
479+
{
480+
// reset members in between benchmark tests.
481+
use crate::tests::MEMBERS;
482+
MEMBERS.with(|m| *m.borrow_mut() = vec![]);
483+
}
484+
}
485+
424486
impl_benchmark_test_suite!(
425487
Elections,
426488
crate::tests::ExtBuilder::default().desired_members(13).desired_runners_up(7),

frame/elections-phragmen/src/lib.rs

Lines changed: 31 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@
4343
//! ### Voting
4444
//!
4545
//! Voters can vote for a limited number of the candidates by providing a list of account ids,
46-
//! bounded by [`Config::MaxVotesPerVoter`]. Invalid votes (voting for non-candidates) and duplicate
47-
//! votes are ignored during election. Yet, a voter _might_ vote for a future candidate. Voters
48-
//! reserve a bond as they vote. Each vote defines a `value`. This amount is locked from the account
49-
//! of the voter and indicates the weight of the vote. Voters can update their votes at any time by
50-
//! calling `vote()` again. This can update the vote targets (which might update the deposit) or
51-
//! update the vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be
52-
//! valid for further rounds. A voter is responsible for calling `remove_voter` once they are done
53-
//! to have their bond back and remove the lock.
46+
//! bounded by [`MAXIMUM_VOTE`]. Invalid votes (voting for non-candidates) and duplicate votes are
47+
//! ignored during election. Yet, a voter _might_ vote for a future candidate. Voters reserve a bond
48+
//! as they vote. Each vote defines a `value`. This amount is locked from the account of the voter
49+
//! and indicates the weight of the vote. Voters can update their votes at any time by calling
50+
//! `vote()` again. This can update the vote targets (which might update the deposit) or update the
51+
//! vote's stake ([`Voter::stake`]). After a round, votes are kept and might still be valid for
52+
//! further rounds. A voter is responsible for calling `remove_voter` once they are done to have
53+
//! their bond back and remove the lock.
5454
//!
5555
//! See [`Call::vote`], [`Call::remove_voter`].
5656
//!
@@ -124,6 +124,9 @@ pub mod migrations;
124124

125125
const LOG_TARGET: &str = "runtime::elections-phragmen";
126126

127+
/// The maximum votes allowed per voter.
128+
pub const MAXIMUM_VOTE: usize = 16;
129+
127130
type BalanceOf<T> =
128131
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
129132
type NegativeImbalanceOf<T> = <<T as Config>::Currency as Currency<
@@ -251,29 +254,19 @@ pub mod pallet {
251254

252255
/// The maximum number of candidates in a phragmen election.
253256
///
254-
/// Warning: This impacts the size of the election which is run onchain. Chose wisely, and
255-
/// consider how it will impact `T::WeightInfo::election_phragmen`.
256-
///
257-
/// When this limit is reached no more candidates are accepted in the election.
257+
/// Warning: The election happens onchain, and this value will determine
258+
/// the size of the election. When this limit is reached no more
259+
/// candidates are accepted in the election.
258260
#[pallet::constant]
259261
type MaxCandidates: Get<u32>;
260262

261263
/// The maximum number of voters to allow in a phragmen election.
262264
///
263-
/// Warning: This impacts the size of the election which is run onchain. Chose wisely, and
264-
/// consider how it will impact `T::WeightInfo::election_phragmen`.
265-
///
265+
/// Warning: This impacts the size of the election which is run onchain.
266266
/// When the limit is reached the new voters are ignored.
267267
#[pallet::constant]
268268
type MaxVoters: Get<u32>;
269269

270-
/// Maximum numbers of votes per voter.
271-
///
272-
/// Warning: This impacts the size of the election which is run onchain. Chose wisely, and
273-
/// consider how it will impact `T::WeightInfo::election_phragmen`.
274-
#[pallet::constant]
275-
type MaxVotesPerVoter: Get<u32>;
276-
277270
/// Weight information for extrinsics in this pallet.
278271
type WeightInfo: WeightInfo;
279272
}
@@ -291,41 +284,6 @@ pub mod pallet {
291284
Weight::zero()
292285
}
293286
}
294-
295-
fn integrity_test() {
296-
let block_weight = T::BlockWeights::get().max_block;
297-
// mind the order.
298-
let election_weight = T::WeightInfo::election_phragmen(
299-
T::MaxCandidates::get(),
300-
T::MaxVoters::get(),
301-
T::MaxVotesPerVoter::get() * T::MaxVoters::get(),
302-
);
303-
304-
let to_seconds = |w: &Weight| {
305-
w.ref_time() as f32 /
306-
frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND as f32
307-
};
308-
309-
frame_support::log::debug!(
310-
target: LOG_TARGET,
311-
"election weight {}s ({:?}) // chain's block weight {}s ({:?})",
312-
to_seconds(&election_weight),
313-
election_weight,
314-
to_seconds(&block_weight),
315-
block_weight,
316-
);
317-
assert!(
318-
election_weight.all_lt(block_weight),
319-
"election weight {}s ({:?}) will exceed a {}s chain's block weight ({:?}) (MaxCandidates {}, MaxVoters {}, MaxVotesPerVoter {} -- tweak these parameters)",
320-
election_weight,
321-
to_seconds(&election_weight),
322-
to_seconds(&block_weight),
323-
block_weight,
324-
T::MaxCandidates::get(),
325-
T::MaxVoters::get(),
326-
T::MaxVotesPerVoter::get(),
327-
);
328-
}
329287
}
330288

331289
#[pallet::call]
@@ -349,6 +307,10 @@ pub mod pallet {
349307
///
350308
/// It is the responsibility of the caller to **NOT** place all of their balance into the
351309
/// lock and keep some for further operations.
310+
///
311+
/// # <weight>
312+
/// We assume the maximum weight among all 3 cases: vote_equal, vote_more and vote_less.
313+
/// # </weight>
352314
#[pallet::call_index(0)]
353315
#[pallet::weight(
354316
T::WeightInfo::vote_more(votes.len() as u32)
@@ -362,10 +324,8 @@ pub mod pallet {
362324
) -> DispatchResultWithPostInfo {
363325
let who = ensure_signed(origin)?;
364326

365-
ensure!(
366-
votes.len() <= T::MaxVotesPerVoter::get() as usize,
367-
Error::<T>::MaximumVotesExceeded
368-
);
327+
// votes should not be empty and more than `MAXIMUM_VOTE` in any case.
328+
ensure!(votes.len() <= MAXIMUM_VOTE, Error::<T>::MaximumVotesExceeded);
369329
ensure!(!votes.is_empty(), Error::<T>::NoVotes);
370330

371331
let candidates_count = <Candidates<T>>::decode_len().unwrap_or(0);
@@ -1046,15 +1006,15 @@ impl<T: Config> Pallet<T> {
10461006
// count](https://en.wikipedia.org/wiki/Borda_count). We weigh everyone's vote for
10471007
// that new member by a multiplier based on the order of the votes. i.e. the
10481008
// first person a voter votes for gets a 16x multiplier, the next person gets a
1049-
// 15x multiplier, an so on... (assuming `T::MaxVotesPerVoter` = 16)
1009+
// 15x multiplier, an so on... (assuming `MAXIMUM_VOTE` = 16)
10501010
let mut prime_votes = new_members_sorted_by_id
10511011
.iter()
10521012
.map(|c| (&c.0, BalanceOf::<T>::zero()))
10531013
.collect::<Vec<_>>();
10541014
for (_, stake, votes) in voters_and_stakes.into_iter() {
10551015
for (vote_multiplier, who) in
10561016
votes.iter().enumerate().map(|(vote_position, who)| {
1057-
((T::MaxVotesPerVoter::get() as usize - vote_position) as u32, who)
1017+
((MAXIMUM_VOTE - vote_position) as u32, who)
10581018
}) {
10591019
if let Ok(i) = prime_votes.binary_search_by_key(&who, |k| k.0) {
10601020
prime_votes[i].1 = prime_votes[i]
@@ -1213,9 +1173,16 @@ mod tests {
12131173
};
12141174
use substrate_test_utils::assert_eq_uvec;
12151175

1176+
parameter_types! {
1177+
pub BlockWeights: frame_system::limits::BlockWeights =
1178+
frame_system::limits::BlockWeights::simple_max(
1179+
frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX),
1180+
);
1181+
}
1182+
12161183
impl frame_system::Config for Test {
12171184
type BaseCallFilter = frame_support::traits::Everything;
1218-
type BlockWeights = ();
1185+
type BlockWeights = BlockWeights;
12191186
type BlockLength = ();
12201187
type DbWeight = ();
12211188
type RuntimeOrigin = RuntimeOrigin;
@@ -1330,7 +1297,6 @@ mod tests {
13301297
type KickedMember = ();
13311298
type WeightInfo = ();
13321299
type MaxVoters = PhragmenMaxVoters;
1333-
type MaxVotesPerVoter = ConstU32<16>;
13341300
type MaxCandidates = PhragmenMaxCandidates;
13351301
}
13361302

0 commit comments

Comments
 (0)