mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 04:41:03 +00:00
refactor election score (#10834)
* refactor election score * Test for ord * remove reference * vec -> slice * change iter to iter_by_significance * improve doc * fix typo * add explanation about [u128; 3] * consolidate threshold and epsilon * random fixes * rename * remove Into * make iter_by_sig private * remove vec * Fix tests
This commit is contained in:
@@ -148,7 +148,10 @@ fn solution_with_size<T: Config>(
|
||||
let score = solution.clone().score(stake_of, voter_at, target_at).unwrap();
|
||||
let round = <MultiPhase<T>>::round();
|
||||
|
||||
assert!(score[0] > 0, "score is zero, this probably means that the stakes are not set.");
|
||||
assert!(
|
||||
score.minimal_stake > 0,
|
||||
"score is zero, this probably means that the stakes are not set."
|
||||
);
|
||||
Ok(RawSolution { solution, score, round })
|
||||
}
|
||||
|
||||
@@ -312,7 +315,7 @@ frame_benchmarking::benchmarks! {
|
||||
// the solution will be worse than all of them meaning the score need to be checked against
|
||||
// ~ log2(c)
|
||||
let solution = RawSolution {
|
||||
score: [(10_000_000u128 - 1).into(), 0, 0],
|
||||
score: ElectionScore { minimal_stake: 10_000_000u128 - 1, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -323,7 +326,7 @@ frame_benchmarking::benchmarks! {
|
||||
let mut signed_submissions = SignedSubmissions::<T>::get();
|
||||
for i in 0..c {
|
||||
let raw_solution = RawSolution {
|
||||
score: [(10_000_000 + i).into(), 0, 0],
|
||||
score: ElectionScore { minimal_stake: 10_000_000u128 + (i as u128), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let signed_submission = SignedSubmission {
|
||||
|
||||
@@ -944,8 +944,11 @@ pub mod pallet {
|
||||
// Note: we don't `rotate_round` at this point; the next call to
|
||||
// `ElectionProvider::elect` will succeed and take care of that.
|
||||
|
||||
let solution =
|
||||
ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Emergency };
|
||||
let solution = ReadySolution {
|
||||
supports,
|
||||
score: Default::default(),
|
||||
compute: ElectionCompute::Emergency,
|
||||
};
|
||||
|
||||
<QueuedSolution<T>>::put(solution);
|
||||
Ok(())
|
||||
@@ -1059,8 +1062,11 @@ pub mod pallet {
|
||||
},
|
||||
)?;
|
||||
|
||||
let solution =
|
||||
ReadySolution { supports, score: [0, 0, 0], compute: ElectionCompute::Fallback };
|
||||
let solution = ReadySolution {
|
||||
supports,
|
||||
score: Default::default(),
|
||||
compute: ElectionCompute::Fallback,
|
||||
};
|
||||
|
||||
<QueuedSolution<T>>::put(solution);
|
||||
Ok(())
|
||||
@@ -1138,10 +1144,10 @@ pub mod pallet {
|
||||
.map_err(dispatch_error_to_invalid)?;
|
||||
|
||||
ValidTransaction::with_tag_prefix("OffchainElection")
|
||||
// The higher the score[0], the better a solution is.
|
||||
// The higher the score.minimal_stake, the better a solution is.
|
||||
.priority(
|
||||
T::MinerTxPriority::get()
|
||||
.saturating_add(raw_solution.score[0].saturated_into()),
|
||||
.saturating_add(raw_solution.score.minimal_stake.saturated_into()),
|
||||
)
|
||||
// Used to deduplicate unsigned solutions: each validator should produce one
|
||||
// solution per round at most, and solutions are not propagate.
|
||||
@@ -1430,7 +1436,7 @@ impl<T: Config> Pallet<T> {
|
||||
let submitted_score = raw_solution.score.clone();
|
||||
ensure!(
|
||||
Self::minimum_untrusted_score().map_or(true, |min_score| {
|
||||
sp_npos_elections::is_score_better(submitted_score, min_score, Perbill::zero())
|
||||
submitted_score.strict_threshold_better(min_score, Perbill::zero())
|
||||
}),
|
||||
FeasibilityError::UntrustedScoreTooLow
|
||||
);
|
||||
@@ -1750,7 +1756,7 @@ mod feasibility_check {
|
||||
assert_eq!(MultiPhase::snapshot().unwrap().voters.len(), 8);
|
||||
|
||||
// Simply faff with the score.
|
||||
solution.score[0] += 1;
|
||||
solution.score.minimal_stake += 1;
|
||||
|
||||
assert_noop!(
|
||||
MultiPhase::feasibility_check(solution, COMPUTE),
|
||||
@@ -1960,7 +1966,10 @@ mod tests {
|
||||
|
||||
// fill the queue with signed submissions
|
||||
for s in 0..SignedMaxSubmissions::get() {
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(MultiPhase::submit(
|
||||
crate::mock::Origin::signed(99),
|
||||
Box::new(solution),
|
||||
@@ -2087,13 +2096,19 @@ mod tests {
|
||||
crate::mock::Balancing::set(Some((2, 0)));
|
||||
|
||||
let (solution, _) = MultiPhase::mine_solution::<<Runtime as Config>::Solver>().unwrap();
|
||||
// Default solution has a score of [50, 100, 5000].
|
||||
assert_eq!(solution.score, [50, 100, 5000]);
|
||||
// Default solution's score.
|
||||
assert!(matches!(solution.score, ElectionScore { minimal_stake: 50, .. }));
|
||||
|
||||
<MinimumUntrustedScore<Runtime>>::put([49, 0, 0]);
|
||||
<MinimumUntrustedScore<Runtime>>::put(ElectionScore {
|
||||
minimal_stake: 49,
|
||||
..Default::default()
|
||||
});
|
||||
assert_ok!(MultiPhase::feasibility_check(solution.clone(), ElectionCompute::Signed));
|
||||
|
||||
<MinimumUntrustedScore<Runtime>>::put([51, 0, 0]);
|
||||
<MinimumUntrustedScore<Runtime>>::put(ElectionScore {
|
||||
minimal_stake: 51,
|
||||
..Default::default()
|
||||
});
|
||||
assert_noop!(
|
||||
MultiPhase::feasibility_check(solution, ElectionCompute::Signed),
|
||||
FeasibilityError::UntrustedScoreTooLow,
|
||||
|
||||
@@ -28,7 +28,7 @@ use frame_support::{
|
||||
traits::{defensive_prelude::*, Currency, Get, OnUnbalanced, ReservableCurrency},
|
||||
};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_npos_elections::{is_score_better, ElectionScore, NposSolution};
|
||||
use sp_npos_elections::{ElectionScore, NposSolution};
|
||||
use sp_runtime::{
|
||||
traits::{Saturating, Zero},
|
||||
RuntimeDebug,
|
||||
@@ -293,7 +293,7 @@ impl<T: Config> SignedSubmissions<T> {
|
||||
let threshold = T::SolutionImprovementThreshold::get();
|
||||
|
||||
// if we haven't improved on the weakest score, don't change anything.
|
||||
if !is_score_better(insert_score, weakest_score, threshold) {
|
||||
if !insert_score.strict_threshold_better(weakest_score, threshold) {
|
||||
return InsertResult::NotInserted
|
||||
}
|
||||
|
||||
@@ -592,7 +592,7 @@ mod tests {
|
||||
assert_eq!(balances(&99), (100, 0));
|
||||
|
||||
// make the solution invalid.
|
||||
solution.score[0] += 1;
|
||||
solution.score.minimal_stake += 1;
|
||||
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
assert_eq!(balances(&99), (95, 5));
|
||||
@@ -618,7 +618,7 @@ mod tests {
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution.clone()));
|
||||
|
||||
// make the solution invalid and weaker.
|
||||
solution.score[0] -= 1;
|
||||
solution.score.minimal_stake -= 1;
|
||||
assert_ok!(submit_with_witness(Origin::signed(999), solution));
|
||||
assert_eq!(balances(&99), (95, 5));
|
||||
assert_eq!(balances(&999), (95, 5));
|
||||
@@ -641,12 +641,18 @@ mod tests {
|
||||
|
||||
for s in 0..SignedMaxSubmissions::get() {
|
||||
// score is always getting better
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
|
||||
// weaker.
|
||||
let solution = RawSolution { score: [4, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 4, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_noop!(
|
||||
submit_with_witness(Origin::signed(99), solution),
|
||||
@@ -663,27 +669,33 @@ mod tests {
|
||||
|
||||
for s in 0..SignedMaxSubmissions::get() {
|
||||
// score is always getting better
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.map(|s| s.raw_solution.score.minimal_stake)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7, 8, 9]
|
||||
);
|
||||
|
||||
// better.
|
||||
let solution = RawSolution { score: [20, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 20, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
|
||||
// the one with score 5 was rejected, the new one inserted.
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.map(|s| s.raw_solution.score.minimal_stake)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![6, 7, 8, 9, 20]
|
||||
);
|
||||
@@ -698,30 +710,39 @@ mod tests {
|
||||
|
||||
for s in 1..SignedMaxSubmissions::get() {
|
||||
// score is always getting better
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
|
||||
let solution = RawSolution { score: [4, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 4, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.map(|s| s.raw_solution.score.minimal_stake)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![4, 6, 7, 8, 9],
|
||||
);
|
||||
|
||||
// better.
|
||||
let solution = RawSolution { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
|
||||
// the one with score 5 was rejected, the new one inserted.
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.map(|s| s.raw_solution.score.minimal_stake)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7, 8, 9],
|
||||
);
|
||||
@@ -736,7 +757,10 @@ mod tests {
|
||||
|
||||
for s in 0..SignedMaxSubmissions::get() {
|
||||
// score is always getting better
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
|
||||
@@ -744,7 +768,10 @@ mod tests {
|
||||
assert_eq!(balances(&999).1, 0);
|
||||
|
||||
// better.
|
||||
let solution = RawSolution { score: [20, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 20, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(999), solution));
|
||||
|
||||
// got one bond back.
|
||||
@@ -760,19 +787,25 @@ mod tests {
|
||||
assert!(MultiPhase::current_phase().is_signed());
|
||||
|
||||
for i in 0..SignedMaxSubmissions::get() {
|
||||
let solution = RawSolution { score: [(5 + i).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + i).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
assert_eq!(
|
||||
MultiPhase::signed_submissions()
|
||||
.iter()
|
||||
.map(|s| s.raw_solution.score[0])
|
||||
.map(|s| s.raw_solution.score.minimal_stake)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![5, 6, 7]
|
||||
);
|
||||
|
||||
// 5 is not accepted. This will only cause processing with no benefit.
|
||||
let solution = RawSolution { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_noop!(
|
||||
submit_with_witness(Origin::signed(99), solution),
|
||||
Error::<Runtime>::SignedQueueFull,
|
||||
@@ -800,13 +833,13 @@ mod tests {
|
||||
|
||||
// make the solution invalidly better and submit. This ought to be slashed.
|
||||
let mut solution_999 = solution.clone();
|
||||
solution_999.score[0] += 1;
|
||||
solution_999.score.minimal_stake += 1;
|
||||
assert_ok!(submit_with_witness(Origin::signed(999), solution_999));
|
||||
|
||||
// make the solution invalidly worse and submit. This ought to be suppressed and
|
||||
// returned.
|
||||
let mut solution_9999 = solution.clone();
|
||||
solution_9999.score[0] -= 1;
|
||||
solution_9999.score.minimal_stake -= 1;
|
||||
assert_ok!(submit_with_witness(Origin::signed(9999), solution_9999));
|
||||
|
||||
assert_eq!(
|
||||
@@ -889,13 +922,19 @@ mod tests {
|
||||
|
||||
for s in 0..SignedMaxSubmissions::get() {
|
||||
// score is always getting better
|
||||
let solution = RawSolution { score: [(5 + s).into(), 0, 0], ..Default::default() };
|
||||
let solution = RawSolution {
|
||||
score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
assert_ok!(submit_with_witness(Origin::signed(99), solution));
|
||||
}
|
||||
|
||||
// this solution has a higher score than any in the queue
|
||||
let solution = RawSolution {
|
||||
score: [(5 + SignedMaxSubmissions::get()).into(), 0, 0],
|
||||
score: ElectionScore {
|
||||
minimal_stake: (5 + SignedMaxSubmissions::get()).into(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -26,10 +26,9 @@ use codec::Encode;
|
||||
use frame_election_provider_support::{NposSolver, PerThing128};
|
||||
use frame_support::{dispatch::DispatchResult, ensure, traits::Get};
|
||||
use frame_system::offchain::SubmitTransaction;
|
||||
use sp_arithmetic::Perbill;
|
||||
use sp_npos_elections::{
|
||||
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, is_score_better,
|
||||
ElectionResult, NposSolution,
|
||||
assignment_ratio_to_staked_normalized, assignment_staked_to_ratio_normalized, ElectionResult,
|
||||
NposSolution,
|
||||
};
|
||||
use sp_runtime::{
|
||||
offchain::storage::{MutateStorageError, StorageValueRef},
|
||||
@@ -624,11 +623,9 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
// ensure score is being improved. Panic henceforth.
|
||||
ensure!(
|
||||
Self::queued_solution().map_or(true, |q: ReadySolution<_>| is_score_better::<Perbill>(
|
||||
raw_solution.score,
|
||||
q.score,
|
||||
T::SolutionImprovementThreshold::get()
|
||||
)),
|
||||
Self::queued_solution().map_or(true, |q: ReadySolution<_>| raw_solution
|
||||
.score
|
||||
.strict_threshold_better(q.score, T::SolutionImprovementThreshold::get())),
|
||||
Error::<T>::PreDispatchWeakSubmission,
|
||||
);
|
||||
|
||||
@@ -748,11 +745,11 @@ mod tests {
|
||||
use frame_support::{
|
||||
assert_noop, assert_ok, bounded_vec, dispatch::Dispatchable, traits::OffchainWorker,
|
||||
};
|
||||
use sp_npos_elections::IndexAssignment;
|
||||
use sp_npos_elections::{ElectionScore, IndexAssignment};
|
||||
use sp_runtime::{
|
||||
offchain::storage_lock::{BlockAndTime, StorageLock},
|
||||
traits::ValidateUnsigned,
|
||||
ModuleError, PerU16,
|
||||
ModuleError, PerU16, Perbill,
|
||||
};
|
||||
|
||||
type Assignment = crate::unsigned::Assignment<Runtime>;
|
||||
@@ -760,8 +757,10 @@ mod tests {
|
||||
#[test]
|
||||
fn validate_unsigned_retracts_wrong_phase() {
|
||||
ExtBuilder::default().desired_targets(0).build_and_execute(|| {
|
||||
let solution =
|
||||
RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let call = Call::submit_unsigned {
|
||||
raw_solution: Box::new(solution.clone()),
|
||||
witness: witness(),
|
||||
@@ -833,8 +832,10 @@ mod tests {
|
||||
roll_to(25);
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
let solution =
|
||||
RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let call = Call::submit_unsigned {
|
||||
raw_solution: Box::new(solution.clone()),
|
||||
witness: witness(),
|
||||
@@ -849,7 +850,10 @@ mod tests {
|
||||
assert!(<MultiPhase as ValidateUnsigned>::pre_dispatch(&call).is_ok());
|
||||
|
||||
// set a better score
|
||||
let ready = ReadySolution { score: [10, 0, 0], ..Default::default() };
|
||||
let ready = ReadySolution {
|
||||
score: ElectionScore { minimal_stake: 10, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
<QueuedSolution<Runtime>>::put(ready);
|
||||
|
||||
// won't work anymore.
|
||||
@@ -874,7 +878,10 @@ mod tests {
|
||||
roll_to(25);
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
let raw = RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let raw = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let call =
|
||||
Call::submit_unsigned { raw_solution: Box::new(raw.clone()), witness: witness() };
|
||||
assert_eq!(raw.solution.unique_targets().len(), 0);
|
||||
@@ -900,8 +907,10 @@ mod tests {
|
||||
roll_to(25);
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
let solution =
|
||||
RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let call = Call::submit_unsigned {
|
||||
raw_solution: Box::new(solution.clone()),
|
||||
witness: witness(),
|
||||
@@ -930,8 +939,10 @@ mod tests {
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
// This is in itself an invalid BS solution.
|
||||
let solution =
|
||||
RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
let call = Call::submit_unsigned {
|
||||
raw_solution: Box::new(solution.clone()),
|
||||
witness: witness(),
|
||||
@@ -950,8 +961,10 @@ mod tests {
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
// This solution is unfeasible as well, but we won't even get there.
|
||||
let solution =
|
||||
RawSolution::<TestNposSolution> { score: [5, 0, 0], ..Default::default() };
|
||||
let solution = RawSolution::<TestNposSolution> {
|
||||
score: ElectionScore { minimal_stake: 5, ..Default::default() },
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut correct_witness = witness();
|
||||
correct_witness.voters += 1;
|
||||
@@ -1070,7 +1083,7 @@ mod tests {
|
||||
Box::new(solution),
|
||||
witness
|
||||
));
|
||||
assert_eq!(MultiPhase::queued_solution().unwrap().score[0], 10);
|
||||
assert_eq!(MultiPhase::queued_solution().unwrap().score.minimal_stake, 10);
|
||||
|
||||
// trial 1: a solution who's score is only 2, i.e. 20% better in the first element.
|
||||
let result = ElectionResult {
|
||||
@@ -1086,7 +1099,7 @@ mod tests {
|
||||
};
|
||||
let (solution, _) = MultiPhase::prepare_election_result(result).unwrap();
|
||||
// 12 is not 50% more than 10
|
||||
assert_eq!(solution.score[0], 12);
|
||||
assert_eq!(solution.score.minimal_stake, 12);
|
||||
assert_noop!(
|
||||
MultiPhase::unsigned_pre_dispatch_checks(&solution),
|
||||
Error::<Runtime>::PreDispatchWeakSubmission,
|
||||
@@ -1107,7 +1120,7 @@ mod tests {
|
||||
],
|
||||
};
|
||||
let (solution, witness) = MultiPhase::prepare_election_result(result).unwrap();
|
||||
assert_eq!(solution.score[0], 17);
|
||||
assert_eq!(solution.score.minimal_stake, 17);
|
||||
|
||||
// and it is fine
|
||||
assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution));
|
||||
|
||||
Reference in New Issue
Block a user