@@ -87,7 +87,7 @@ use codec::{Encode, Decode};
8787use sp_std:: prelude:: * ;
8888use sp_runtime:: {
8989 DispatchError , RuntimeDebug , Perbill ,
90- traits:: { Zero , StaticLookup , Convert } ,
90+ traits:: { Zero , StaticLookup , Convert , Saturating } ,
9191} ;
9292use 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