Skip to content

Commit

Permalink
adds max backers per winner trimming test
Browse files Browse the repository at this point in the history
  • Loading branch information
gpestana committed Dec 3, 2024
1 parent 676db53 commit fe8b9ae
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions substrate/frame/election-provider-multi-phase/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@ impl ExtBuilder {
<SignedMaxWeight>::set(weight);
self
}
pub fn max_backers_per_winner(self, max: u32) -> Self {
MaxBackersPerWinner::set(max);
self
}
pub fn build(self) -> sp_io::TestExternalities {
sp_tracing::try_init_simple();
let mut storage =
Expand Down
93 changes: 93 additions & 0 deletions substrate/frame/election-provider-multi-phase/src/unsigned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,99 @@ mod tests {
})
}

#[test]
fn mine_solution_always_respects_max_backers_per_winner() {
use crate::mock::MaxBackersPerWinner;
use frame_election_provider_support::BoundedSupport;

let targets = vec![10, 20, 30, 40];
let voters = vec![
(1, 10, bounded_vec![10, 20, 30]),
(2, 10, bounded_vec![10, 20, 30]),
(3, 10, bounded_vec![10, 20, 30]),
(4, 10, bounded_vec![10, 20, 30]),
(5, 10, bounded_vec![10, 20, 40]),
];
let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() };
let (round, desired_targets) = (1, 3);

let expected_score_unbounded =
ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 };
let expected_score_bounded =
ElectionScore { minimal_stake: 2, sum_stake: 10, sum_stake_squared: 44 };

// solution without max_backers_per_winner set will be higher than the score when bounds
// are set, confirming the trimming when using the same snapshot state.
assert!(expected_score_unbounded > expected_score_bounded);

// election with unbounded max backers per winnner.
ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| {
assert_eq!(MaxBackersPerWinner::get(), u32::MAX);

let solution = Miner::<Runtime>::mine_solution_with_snapshot::<
<Runtime as Config>::Solver,
>(voters.clone(), targets.clone(), desired_targets)
.unwrap()
.0;

let ready_solution = Miner::<Runtime>::feasibility_check(
RawSolution { solution, score: expected_score_unbounded, round },
Default::default(),
desired_targets,
snapshot.clone(),
round,
Default::default(),
)
.unwrap();

assert_eq!(
ready_solution.supports.into_iter().collect::<Vec<_>>(),
vec![
(
10,
BoundedSupport { total: 21, voters: bounded_vec![(1, 10), (4, 8), (5, 3)] }
),
(20, BoundedSupport { total: 17, voters: bounded_vec![(2, 10), (5, 7)] }),
(30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }),
]
);
});

// election with max 1 backer per winnner.
ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| {
assert_eq!(MaxBackersPerWinner::get(), 1);

let solution = Miner::<Runtime>::mine_solution_with_snapshot::<
<Runtime as Config>::Solver,
>(voters, targets, desired_targets)
.unwrap()
.0;

let ready_solution = Miner::<Runtime>::feasibility_check(
RawSolution { solution, score: expected_score_bounded, round },
Default::default(),
desired_targets,
snapshot,
round,
Default::default(),
)
.unwrap();

for (_, supports) in ready_solution.supports.iter() {
assert!((supports.voters.len() as u32) <= MaxBackersPerWinner::get());
}

assert_eq!(
ready_solution.supports.into_iter().collect::<Vec<_>>(),
vec![
(10, BoundedSupport { total: 6, voters: bounded_vec![(1, 6)] }),
(20, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }),
(30, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }),
]
);
});
}

#[test]
fn trim_assignments_length_does_not_modify_when_short_enough() {
ExtBuilder::default().build_and_execute(|| {
Expand Down

0 comments on commit fe8b9ae

Please sign in to comment.