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

Commit fd2c136

Browse files
Better prime election. (#6939)
* Better prime election. * improve docs * more sensible variable names * link to Borda count wiki Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
1 parent e578af7 commit fd2c136

File tree

1 file changed

+24
-9
lines changed
  • frame/elections-phragmen/src

1 file changed

+24
-9
lines changed

frame/elections-phragmen/src/lib.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ use codec::{Encode, Decode};
8787
use sp_std::prelude::*;
8888
use sp_runtime::{
8989
DispatchError, RuntimeDebug, Perbill,
90-
traits::{Zero, StaticLookup, Convert},
90+
traits::{Zero, StaticLookup, Convert, Saturating},
9191
};
9292
use frame_support::{
9393
decl_storage, decl_event, ensure, decl_module, decl_error,
@@ -904,14 +904,20 @@ impl<T: Trait> Module<T> {
904904
to_votes(Self::locked_stake_of(who))
905905
};
906906

907-
let voters_and_votes = Voting::<T>::iter()
908-
.map(|(voter, (stake, targets))| { (voter, to_votes(stake), targets) })
907+
// used for prime election.
908+
let voters_and_stakes = Voting::<T>::iter()
909+
.map(|(voter, (stake, targets))| { (voter, stake, targets) })
910+
.collect::<Vec<_>>();
911+
// used for phragmen.
912+
let voters_and_votes = voters_and_stakes.iter()
913+
.cloned()
914+
.map(|(voter, stake, targets)| { (voter, to_votes(stake), targets)} )
909915
.collect::<Vec<_>>();
910916
let maybe_phragmen_result = sp_npos_elections::seq_phragmen::<T::AccountId, Perbill>(
911917
num_to_elect,
912918
0,
913919
candidates,
914-
voters_and_votes.clone(),
920+
voters_and_votes,
915921
);
916922

917923
if let Some(ElectionResult { winners, assignments }) = maybe_phragmen_result {
@@ -965,17 +971,26 @@ impl<T: Trait> Module<T> {
965971
// save the members, sorted based on account id.
966972
new_members.sort_by(|i, j| i.0.cmp(&j.0));
967973

968-
let mut prime_votes: Vec<_> = new_members.iter().map(|c| (&c.0, VoteWeight::zero())).collect();
969-
for (_, stake, targets) in voters_and_votes.into_iter() {
970-
for (votes, who) in targets.iter()
974+
// Now we select a prime member using a [Borda count](https://en.wikipedia.org/wiki/Borda_count).
975+
// We weigh everyone's vote for that new member by a multiplier based on the order
976+
// of the votes. i.e. the first person a voter votes for gets a 16x multiplier,
977+
// the next person gets a 15x multiplier, an so on... (assuming `MAXIMUM_VOTE` = 16)
978+
let mut prime_votes: Vec<_> = new_members.iter().map(|c| (&c.0, BalanceOf::<T>::zero())).collect();
979+
for (_, stake, targets) in voters_and_stakes.into_iter() {
980+
for (vote_multiplier, who) in targets.iter()
971981
.enumerate()
972-
.map(|(votes, who)| ((MAXIMUM_VOTE - votes) as u32, who))
982+
.map(|(vote_position, who)| ((MAXIMUM_VOTE - vote_position) as u32, who))
973983
{
974984
if let Ok(i) = prime_votes.binary_search_by_key(&who, |k| k.0) {
975-
prime_votes[i].1 += stake * votes as VoteWeight;
985+
prime_votes[i].1 = prime_votes[i].1.saturating_add(
986+
stake.saturating_mul(vote_multiplier.into())
987+
);
976988
}
977989
}
978990
}
991+
// We then select the new member with the highest weighted stake. In the case of
992+
// a tie, the last person in the list with the tied score is selected. This is
993+
// the person with the "highest" account id based on the sort above.
979994
let prime = prime_votes.into_iter().max_by_key(|x| x.1).map(|x| x.0.clone());
980995

981996
// new_members_ids is sorted by account id.

0 commit comments

Comments
 (0)