diff --git a/frame/election-provider-multi-phase/src/benchmarking.rs b/frame/election-provider-multi-phase/src/benchmarking.rs index 9c734c4823541..124fb7ad2cfbd 100644 --- a/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/frame/election-provider-multi-phase/src/benchmarking.rs @@ -143,7 +143,7 @@ fn solution_with_size( let solution = >::from_assignment(&assignments, &voter_index, &target_index).unwrap(); - let score = solution.clone().score(&winners, stake_of, voter_at, target_at).unwrap(); + let score = solution.clone().score(stake_of, voter_at, target_at).unwrap(); let round = >::round(); assert!(score[0] > 0, "score is zero, this probably means that the stakes are not set."); diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 1a130371f3b4d..977a4d34e84a9 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -535,8 +535,6 @@ pub enum FeasibilityError { InvalidVote, /// A voter is invalid. InvalidVoter, - /// A winner is invalid. - InvalidWinner, /// The given score was invalid. InvalidScore, /// The provided round is incorrect. @@ -1395,17 +1393,8 @@ impl Pallet { let target_at = helpers::target_at_fn::(&snapshot_targets); let voter_index = helpers::voter_index_fn_usize::(&cache); - // First, make sure that all the winners are sane. - // OPTIMIZATION: we could first build the assignments, and then extract the winners directly - // from that, as that would eliminate a little bit of duplicate work. For now, we keep them - // separate: First extract winners separately from solution, and then assignments. This is - // also better, because we can reject solutions that don't meet `desired_targets` early on. - let winners = winners - .into_iter() - .map(|i| target_at(i).ok_or(FeasibilityError::InvalidWinner)) - .collect::, FeasibilityError>>()?; - - // Then convert solution -> assignment. This will fail if any of the indices are gibberish. + // Then convert solution -> assignment. This will fail if any of the indices are gibberish, + // namely any of the voters or targets. let assignments = solution .into_assignment(voter_at, target_at) .map_err::(Into::into)?; @@ -1441,14 +1430,10 @@ impl Pallet { // This might fail if the normalization fails. Very unlikely. See `integrity_test`. let staked_assignments = assignment_ratio_to_staked_normalized(assignments, stake_of) .map_err::(Into::into)?; - - // This might fail if one of the voter edges is pointing to a non-winner, which is not - // really possible anymore because all the winners come from the same `solution`. - let supports = sp_npos_elections::to_supports(&winners, &staked_assignments) - .map_err::(Into::into)?; + let supports = sp_npos_elections::to_supports(&staked_assignments); // Finally, check that the claimed score was indeed correct. - let known_score = (&supports).evaluate(); + let known_score = supports.evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); Ok(ReadySolution { supports, compute, score }) @@ -1653,7 +1638,7 @@ mod feasibility_check { }); assert_noop!( MultiPhase::feasibility_check(raw, COMPUTE), - FeasibilityError::InvalidWinner + FeasibilityError::NposElection(sp_npos_elections::Error::SolutionInvalidIndex) ); }) } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index e63c171f4dcc0..a7e68491c272a 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -30,8 +30,8 @@ use sp_core::{ H256, }; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, to_without_backing, - ElectionResult, EvaluateSupport, ExtendedBalance, NposSolution, + assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, ElectionResult, + EvaluateSupport, ExtendedBalance, NposSolution, }; use sp_runtime::{ testing::Header, @@ -157,13 +157,14 @@ pub fn raw_solution() -> RawSolution> { let RoundSnapshot { voters, targets } = MultiPhase::snapshot().unwrap(); let desired_targets = MultiPhase::desired_targets().unwrap(); - let ElectionResult { winners, assignments } = seq_phragmen::<_, SolutionAccuracyOf>( - desired_targets as usize, - targets.clone(), - voters.clone(), - None, - ) - .unwrap(); + let ElectionResult { winners: _, assignments } = + seq_phragmen::<_, SolutionAccuracyOf>( + desired_targets as usize, + targets.clone(), + voters.clone(), + None, + ) + .unwrap(); // closures let cache = helpers::generate_voter_cache::(&voters); @@ -171,11 +172,9 @@ pub fn raw_solution() -> RawSolution> { let target_index = helpers::target_index_fn_linear::(&targets); let stake_of = helpers::stake_of_fn::(&voters, &cache); - let winners = to_without_backing(winners); - let score = { let staked = assignment_ratio_to_staked_normalized(assignments.clone(), &stake_of).unwrap(); - to_supports(&winners, &staked).unwrap().evaluate() + to_supports(&staked).evaluate() }; let solution = >::from_assignment(&assignments, &voter_index, &target_index).unwrap(); diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index f83d72827852a..72aa3e6680343 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -26,7 +26,6 @@ use codec::{Decode, Encode, HasCompact}; use frame_support::{ storage::bounded_btree_map::BoundedBTreeMap, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - DebugNoBound, }; use sp_arithmetic::traits::SaturatedConversion; use sp_npos_elections::{is_score_better, ElectionScore, NposSolution}; @@ -113,7 +112,7 @@ pub enum InsertResult { /// Mask type which pretends to be a set of `SignedSubmissionOf`, while in fact delegating to the /// actual implementations in `SignedSubmissionIndices`, `SignedSubmissionsMap`, and /// `SignedSubmissionNextIndex`. -#[cfg_attr(feature = "std", derive(DebugNoBound))] +#[cfg_attr(feature = "std", derive(frame_support::DebugNoBound))] pub struct SignedSubmissions { indices: SubmissionIndicesOf, next_idx: u32, diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 86d3a471bb7de..0afb6eee16121 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -315,7 +315,7 @@ impl Pallet { SolutionOf::::try_from(assignments).map(|s| s.encoded_size()) }; - let ElectionResult { assignments, winners } = election_result; + let ElectionResult { assignments, winners: _ } = election_result; // Reduce (requires round-trip to staked form) let sorted_assignments = { @@ -374,8 +374,7 @@ impl Pallet { let solution = SolutionOf::::try_from(&index_assignments)?; // re-calc score. - let winners = sp_npos_elections::to_without_backing(winners); - let score = solution.clone().score(&winners, stake_of, voter_at, target_at)?; + let score = solution.clone().score(stake_of, voter_at, target_at)?; let round = Self::round(); Ok((RawSolution { solution, score, round }, size)) diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index aa07a0527daab..8e548408ef1a3 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -81,14 +81,13 @@ impl ElectionProvider for OnChainSequen let stake_of = |w: &T::AccountId| -> VoteWeight { stake_map.get(w).cloned().unwrap_or_default() }; - let ElectionResult { winners, assignments } = + let ElectionResult { winners: _, assignments } = seq_phragmen::<_, T::Accuracy>(desired_targets as usize, targets, voters, None) .map_err(Error::from)?; let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; - let winners = to_without_backing(winners); - to_supports(&winners, &staked).map_err(Error::from) + Ok(to_supports(&staked)) } } diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index ee09660d23d20..091dd7817676d 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -40,8 +40,8 @@ pub use impls::*; use crate::{ migrations, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraIndex, EraPayout, EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, - Releases, RewardDestination, SessionInterface, StakerStatus, StakingLedger, UnappliedSlash, - UnlockChunk, ValidatorPrefs, + Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + ValidatorPrefs, }; pub const MAX_UNLOCKING_CHUNKS: usize = 32; @@ -453,7 +453,8 @@ pub mod pallet { pub force_era: Forcing, pub slash_reward_fraction: Perbill, pub canceled_payout: BalanceOf, - pub stakers: Vec<(T::AccountId, T::AccountId, BalanceOf, StakerStatus)>, + pub stakers: + Vec<(T::AccountId, T::AccountId, BalanceOf, crate::StakerStatus)>, pub min_nominator_bond: BalanceOf, pub min_validator_bond: BalanceOf, } @@ -502,11 +503,11 @@ pub mod pallet { RewardDestination::Staked, )); frame_support::assert_ok!(match status { - StakerStatus::Validator => >::validate( + crate::StakerStatus::Validator => >::validate( T::Origin::from(Some(controller.clone()).into()), Default::default(), ), - StakerStatus::Nominator(votes) => >::nominate( + crate::StakerStatus::Nominator(votes) => >::nominate( T::Origin::from(Some(controller.clone()).into()), votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(), ), diff --git a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs index 5da57ccfd9aea..0c140a8ce6fad 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_balancing.rs @@ -24,7 +24,7 @@ use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, is_score_better, seq_phragmen, to_supports, - to_without_backing, EvaluateSupport, VoteWeight, + EvaluateSupport, VoteWeight, }; use sp_runtime::Perbill; @@ -58,8 +58,7 @@ fn main() { &stake_of, ) .unwrap(); - let winners = to_without_backing(unbalanced.winners.clone()); - let score = to_supports(winners.as_ref(), staked.as_ref()).unwrap().evaluate(); + let score = to_supports(staked.as_ref()).evaluate(); if score[0] == 0 { // such cases cannot be improved by balancing. @@ -83,8 +82,7 @@ fn main() { &stake_of, ) .unwrap(); - let winners = to_without_backing(balanced.winners); - to_supports(winners.as_ref(), staked.as_ref()).unwrap().evaluate() + to_supports(staked.as_ref()).evaluate() }; let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); diff --git a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs index 0d8a07489d310..7b2aacfa85882 100644 --- a/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs +++ b/primitives/npos-elections/fuzzer/src/phragmms_balancing.rs @@ -23,8 +23,8 @@ use common::*; use honggfuzz::fuzz; use rand::{self, SeedableRng}; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, - to_without_backing, EvaluateSupport, VoteWeight, + assignment_ratio_to_staked_normalized, is_score_better, phragmms, to_supports, EvaluateSupport, + VoteWeight, }; use sp_runtime::Perbill; @@ -58,8 +58,7 @@ fn main() { &stake_of, ) .unwrap(); - let winners = to_without_backing(unbalanced.winners.clone()); - let score = to_supports(&winners, &staked).unwrap().evaluate(); + let score = to_supports(&staked).evaluate(); if score[0] == 0 { // such cases cannot be improved by balancing. @@ -80,8 +79,7 @@ fn main() { let staked = assignment_ratio_to_staked_normalized(balanced.assignments.clone(), &stake_of) .unwrap(); - let winners = to_without_backing(balanced.winners); - to_supports(winners.as_ref(), staked.as_ref()).unwrap().evaluate() + to_supports(staked.as_ref()).evaluate() }; let enhance = is_score_better(balanced_score, unbalanced_score, Perbill::zero()); diff --git a/primitives/npos-elections/fuzzer/src/reduce.rs b/primitives/npos-elections/fuzzer/src/reduce.rs index a7e77fdd516a5..5f8a4f0e13844 100644 --- a/primitives/npos-elections/fuzzer/src/reduce.rs +++ b/primitives/npos-elections/fuzzer/src/reduce.rs @@ -104,13 +104,11 @@ fn generate_random_phragmen_assignment( } fn assert_assignments_equal( - winners: &Vec, ass1: &Vec>, ass2: &Vec>, ) { - let support_1 = to_support_map::(winners, ass1).unwrap(); - let support_2 = to_support_map::(winners, ass2).unwrap(); - + let support_1 = to_support_map::(ass1); + let support_2 = to_support_map::(ass2); for (who, support) in support_1.iter() { assert_eq!(support.total, support_2.get(who).unwrap().total); } @@ -134,7 +132,7 @@ fn reduce_and_compare(assignment: &Vec>, winners: &V num_changed, ); - assert_assignments_equal(winners, &assignment, &altered_assignment); + assert_assignments_equal(&assignment, &altered_assignment); } fn assignment_len(assignments: &[StakedAssignment]) -> u32 { diff --git a/primitives/npos-elections/src/helpers.rs b/primitives/npos-elections/src/helpers.rs index 5b02eaf2ad2e8..ca97aeb996e48 100644 --- a/primitives/npos-elections/src/helpers.rs +++ b/primitives/npos-elections/src/helpers.rs @@ -17,9 +17,7 @@ //! Helper methods for npos-elections. -use crate::{ - Assignment, Error, IdentifierT, PerThing128, StakedAssignment, VoteWeight, WithApprovalOf, -}; +use crate::{Assignment, Error, IdentifierT, PerThing128, StakedAssignment, VoteWeight}; use sp_arithmetic::PerThing; use sp_std::prelude::*; @@ -81,11 +79,6 @@ pub fn assignment_staked_to_ratio_normalized( Ok(ratio) } -/// consumes a vector of winners with backing stake to just winners. -pub fn to_without_backing(winners: Vec>) -> Vec { - winners.into_iter().map(|(who, _)| who).collect::>() -} - #[cfg(test)] mod tests { use super::*; diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index 6a7e7e8c23cc0..84b5d480bef01 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -146,9 +146,6 @@ pub type ExtendedBalance = u128; /// [`EvaluateSupport::evaluate`]. pub type ElectionScore = [ExtendedBalance; 3]; -/// A winner, with their respective approval stake. -pub type WithApprovalOf = (A, ExtendedBalance); - /// A pointer to a candidate struct with interior mutability. pub type CandidatePtr = Rc>>; @@ -327,7 +324,7 @@ impl Voter { pub struct ElectionResult { /// Just winners zipped with their approval stake. Note that the approval stake is merely the /// sub of their received stake and could be used for very basic sorting and approval voting. - pub winners: Vec>, + pub winners: Vec<(AccountId, ExtendedBalance)>, /// Individual assignments. for each tuple, the first elements is a voter and the second is the /// list of candidates that it supports. pub assignments: Vec>, @@ -361,107 +358,50 @@ pub type Supports = Vec<(A, Support)>; /// This is more helpful than a normal [`Supports`] as it allows faster error checking. pub type SupportMap = BTreeMap>; -/// Helper trait to convert from a support map to a flat support vector. -pub trait FlattenSupportMap { - /// Flatten the support. - fn flatten(self) -> Supports; -} - -impl FlattenSupportMap for SupportMap { - fn flatten(self) -> Supports { - self.into_iter().collect::>() - } -} - -/// Build the support map from the winners and assignments. -/// -/// The list of winners is basically a redundancy for error checking only; It ensures that all the -/// targets pointed to by the [`Assignment`] are present in the `winners`. +/// Build the support map from the assignments. pub fn to_support_map( - winners: &[AccountId], assignments: &[StakedAssignment], -) -> Result, Error> { - // Initialize the support of each candidate. - let mut supports = >::new(); - winners.iter().for_each(|e| { - supports.insert(e.clone(), Default::default()); - }); +) -> SupportMap { + let mut supports = >>::new(); // build support struct. - for StakedAssignment { who, distribution } in assignments.iter() { - for (c, weight_extended) in distribution.iter() { - if let Some(support) = supports.get_mut(c) { - support.total = support.total.saturating_add(*weight_extended); - support.voters.push((who.clone(), *weight_extended)); - } else { - return Err(Error::InvalidSupportEdge) - } + for StakedAssignment { who, distribution } in assignments.into_iter() { + for (c, weight_extended) in distribution.into_iter() { + let mut support = supports.entry(c.clone()).or_default(); + support.total = support.total.saturating_add(*weight_extended); + support.voters.push((who.clone(), *weight_extended)); } } - Ok(supports) + + supports } -/// Same as [`to_support_map`] except it calls `FlattenSupportMap` on top of the result to return a +/// Same as [`to_support_map`] except it returns a /// flat vector. -/// -/// Similar to [`to_support_map`], `winners` is used for error checking. pub fn to_supports( - winners: &[AccountId], assignments: &[StakedAssignment], -) -> Result, Error> { - to_support_map(winners, assignments).map(FlattenSupportMap::flatten) +) -> Supports { + to_support_map(assignments).into_iter().collect() } /// Extension trait for evaluating a support map or vector. -pub trait EvaluateSupport { +pub trait EvaluateSupport { /// Evaluate a support map. The returned tuple contains: /// /// - Minimum support. This value must be **maximized**. /// - Sum of all supports. This value must be **maximized**. /// - Sum of all supports squared. This value must be **minimized**. - fn evaluate(self) -> ElectionScore; -} - -/// A common wrapper trait for both (&A, &B) and &(A, B). -/// -/// This allows us to implemented something for both `Vec<_>` and `BTreeMap<_>`, such as -/// [`EvaluateSupport`]. -pub trait TupleRef { - fn extract(&self) -> (&K, &V); -} - -impl TupleRef for &(K, V) { - fn extract(&self) -> (&K, &V) { - (&self.0, &self.1) - } -} - -impl TupleRef for (K, V) { - fn extract(&self) -> (&K, &V) { - (&self.0, &self.1) - } -} - -impl TupleRef for (&K, &V) { - fn extract(&self) -> (&K, &V) { - (self.0, self.1) - } + fn evaluate(&self) -> ElectionScore; } -impl EvaluateSupport for C -where - C: IntoIterator, - I: TupleRef>, - A: IdentifierT, -{ - fn evaluate(self) -> ElectionScore { +impl EvaluateSupport for Supports { + fn evaluate(&self) -> ElectionScore { let mut min_support = ExtendedBalance::max_value(); let mut sum: ExtendedBalance = Zero::zero(); // NOTE: The third element might saturate but fine for now since this will run on-chain and // need to be fast. let mut sum_squared: ExtendedBalance = Zero::zero(); - for item in self { - let (_, support) = item.extract(); + for (_, support) in self { sum = sum.saturating_add(support.total); let squared = support.total.saturating_mul(support.total); sum_squared = sum_squared.saturating_add(squared); diff --git a/primitives/npos-elections/src/tests.rs b/primitives/npos-elections/src/tests.rs index eac218f77e38b..bf9ca57677efa 100644 --- a/primitives/npos-elections/src/tests.rs +++ b/primitives/npos-elections/src/tests.rs @@ -19,8 +19,8 @@ use crate::{ balancing, helpers::*, is_score_better, mock::*, seq_phragmen, seq_phragmen_core, setup_inputs, - to_support_map, to_supports, Assignment, ElectionResult, EvaluateSupport, ExtendedBalance, - IndexAssignment, NposSolution, StakedAssignment, Support, Voter, + to_support_map, Assignment, ElectionResult, ExtendedBalance, IndexAssignment, NposSolution, + StakedAssignment, Support, Voter, }; use rand::{self, SeedableRng}; use sp_arithmetic::{PerU16, Perbill, Percent, Permill}; @@ -259,8 +259,7 @@ fn phragmen_poc_works() { ); let staked = assignment_ratio_to_staked(assignments, &stake_of); - let winners = to_without_backing(winners); - let support_map = to_support_map::(&winners, &staked).unwrap(); + let support_map = to_support_map::(&staked); assert_eq_uvec!( staked, @@ -315,8 +314,7 @@ fn phragmen_poc_works_with_balancing() { ); let staked = assignment_ratio_to_staked(assignments, &stake_of); - let winners = to_without_backing(winners); - let support_map = to_support_map::(&winners, &staked).unwrap(); + let support_map = to_support_map::(&staked); assert_eq_uvec!( staked, @@ -515,7 +513,7 @@ fn phragmen_large_scale_test() { ) .unwrap(); - assert_eq_uvec!(to_without_backing(winners.clone()), vec![24, 22]); + assert_eq_uvec!(winners.iter().map(|(x, _)| *x).collect::>(), vec![24, 22]); check_assignments_sum(&assignments); } @@ -649,8 +647,7 @@ fn phragmen_self_votes_should_be_kept() { ); let staked_assignments = assignment_ratio_to_staked(result.assignments, &stake_of); - let winners = to_without_backing(result.winners); - let supports = to_support_map::(&winners, &staked_assignments).unwrap(); + let supports = to_support_map::(&staked_assignments); assert_eq!(supports.get(&5u64), None); assert_eq!( @@ -670,9 +667,8 @@ fn duplicate_target_is_ignored() { let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>(2, candidates, voters, None).unwrap(); - let winners = to_without_backing(winners); - assert_eq!(winners, vec![(2), (3)]); + assert_eq!(winners, vec![(2, 140), (3, 110)]); assert_eq!( assignments .into_iter() @@ -689,9 +685,8 @@ fn duplicate_target_is_ignored_when_winner() { let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>(2, candidates, voters, None).unwrap(); - let winners = to_without_backing(winners); - assert_eq!(winners, vec![1, 2]); + assert_eq!(winners, vec![(1, 100), (2, 100)]); assert_eq!( assignments .into_iter() @@ -701,31 +696,6 @@ fn duplicate_target_is_ignored_when_winner() { ); } -#[test] -fn support_map_and_vec_can_be_evaluated() { - let candidates = vec![1, 2, 3]; - let voters = vec![(10, vec![1, 2]), (20, vec![1, 3]), (30, vec![2, 3])]; - - let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); - let ElectionResult { winners, assignments } = seq_phragmen::<_, Perbill>( - 2, - candidates, - voters - .iter() - .map(|(ref v, ref vs)| (v.clone(), stake_of(v), vs.clone())) - .collect::>(), - None, - ) - .unwrap(); - - let staked = assignment_ratio_to_staked(assignments, &stake_of); - let winners = to_without_backing(winners); - let support_map = to_support_map::(&winners, &staked).unwrap(); - let support_vec = to_supports(&winners, &staked).unwrap(); - - assert_eq!(support_map.evaluate(), support_vec.evaluate()); -} - mod assignment_convert_normalize { use super::*; #[test] diff --git a/primitives/npos-elections/src/traits.rs b/primitives/npos-elections/src/traits.rs index ac077680167f2..45b6fa368ae2a 100644 --- a/primitives/npos-elections/src/traits.rs +++ b/primitives/npos-elections/src/traits.rs @@ -112,7 +112,6 @@ where /// Compute the score of this solution type. fn score( self, - winners: &[A], stake_of: FS, voter_at: impl Fn(Self::VoterIndex) -> Option, target_at: impl Fn(Self::TargetIndex) -> Option, @@ -123,7 +122,7 @@ where { let ratio = self.into_assignment(voter_at, target_at)?; let staked = crate::helpers::assignment_ratio_to_staked_normalized(ratio, stake_of)?; - let supports = crate::to_supports(winners, &staked)?; + let supports = crate::to_supports(&staked); Ok(supports.evaluate()) }