mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 13:31:10 +00:00
Offchain Phragmén BREAKING. (#4517)
* Initial skeleton for offchain phragmen * Basic compact encoding decoding for results * add compact files * Bring back Self::ensure_storage_upgraded(); * Make staking use compact stuff. * First seemingly working version of reduce, full of todos * Everything phragmen related works again. * Signing made easier, still issues. * Signing from offchain compile fine 😎 * make compact work with staked asssignment * Evaluation basics are in place. * Move reduce into crate. Document stuff * move reduce into no_std * Add files * Remove other std deps. Runtime compiles * Seemingly it is al stable; cycle implemented but not integrated. * Add fuzzing code. * Cleanup reduce a bit more. * a metric ton of tests for staking; wip 🔨 * Implement a lot more of the tests. * wip getting the unsigned stuff to work * A bit gleanup for unsigned debug * Clean and finalize compact code. * Document reduce. * Still problems with signing * We officaly duct taped the transaction submission stuff. 🤓 * Deadlock with keys again * Runtime builds * Unsigned test works 🙌 * Some cleanups * Make all the tests compile and stuff * Minor cleanup * fix more merge stuff * Most tests work again. * a very nasty bug in reduce * Fix all integrations * Fix more todos * Revamp everything and everything * Remove bogus test * Some review grumbles. * Some fixes * Fix doc test * loop for submission * Fix cli, keyring etc. * some cleanup * Fix staking tests again * fix per-things; bring patches from benchmarking * better score prediction * Add fuzzer, more patches. * Some fixes * More docs * Remove unused generics * Remove max-nominator footgun * Better fuzzer * Disable it ❌ * Bump. * Another round of self-review * Refactor a lot * More major fixes in perThing * Add new fuzz file * Update lock * fix fuzzing code. * Fix nominator retain test * Add slashing check * Update frame/staking/src/tests.rs Co-Authored-By: Joshy Orndorff <JoshOrndorff@users.noreply.github.com> * Some formatting nits * Review comments. * Fix cargo file * Almost all tests work again * Update frame/staking/src/tests.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Fix review comments * More review stuff * Some nits * Fix new staking / session / babe relation * Update primitives/phragmen/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Update primitives/phragmen/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Update primitives/phragmen/compact/src/lib.rs Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * Some doc updates to slashing * Fix derive * Remove imports * Remove unimplemented tests * nits * Remove dbg * Better fuzzing params * Remove unused pref map * Deferred Slashing/Offence for offchain Phragmen (#5151) * Some boilerplate * Add test * One more test * Review comments * Fix build * review comments * fix more * fix build * Some cleanups and self-reviews * More minor self reviews * Final nits * Some merge fixes. * opt comment * Fix build * Fix build again. * Update frame/staking/fuzz/fuzz_targets/submit_solution.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Update frame/staking/src/slashing.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Update frame/staking/src/offchain_election.rs Co-Authored-By: Gavin Wood <gavin@parity.io> * Fix review comments * fix test * === 🔑 Revamp without staking key. * final round of changes. * Fix cargo-deny * Update frame/staking/src/lib.rs Co-Authored-By: Gavin Wood <gavin@parity.io> Co-authored-by: Joshy Orndorff <JoshOrndorff@users.noreply.github.com> Co-authored-by: thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Gavin Wood <gavin@parity.io>
This commit is contained in:
@@ -19,11 +19,12 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use crate::mock::*;
|
||||
use crate::{elect, PhragmenResult, PhragmenStakedAssignment, build_support_map, Support, equalize};
|
||||
use crate::{
|
||||
elect, equalize, build_support_map, is_score_better,
|
||||
Support, StakedAssignment, Assignment, PhragmenResult, ExtendedBalance,
|
||||
};
|
||||
use substrate_test_utils::assert_eq_uvec;
|
||||
use sp_runtime::Perbill;
|
||||
|
||||
type Output = Perbill;
|
||||
use sp_runtime::{Perbill, Permill, Percent, PerU16, traits::Convert};
|
||||
|
||||
#[test]
|
||||
fn float_phragmen_poc_works() {
|
||||
@@ -81,7 +82,7 @@ fn phragmen_poc_works() {
|
||||
];
|
||||
|
||||
let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]);
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates,
|
||||
@@ -92,9 +93,21 @@ fn phragmen_poc_works() {
|
||||
assert_eq_uvec!(
|
||||
assignments,
|
||||
vec![
|
||||
(10, vec![(2, Perbill::from_percent(100))]),
|
||||
(20, vec![(3, Perbill::from_percent(100))]),
|
||||
(30, vec![(2, Perbill::from_percent(100/2)), (3, Perbill::from_percent(100/2))]),
|
||||
Assignment {
|
||||
who: 10u64,
|
||||
distribution: vec![(2, Perbill::from_percent(100))],
|
||||
},
|
||||
Assignment {
|
||||
who: 20,
|
||||
distribution: vec![(3, Perbill::from_percent(100))],
|
||||
},
|
||||
Assignment {
|
||||
who: 30,
|
||||
distribution: vec![
|
||||
(2, Perbill::from_percent(100/2)),
|
||||
(3, Perbill::from_percent(100/2)),
|
||||
],
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -115,7 +128,10 @@ fn phragmen_poc_2_works() {
|
||||
(4, 500),
|
||||
]);
|
||||
|
||||
run_and_compare(candidates, voters, stake_of, 2, 2);
|
||||
run_and_compare::<Perbill>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<Permill>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<Percent>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<PerU16>(candidates, voters, &stake_of, 2, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -133,7 +149,10 @@ fn phragmen_poc_3_works() {
|
||||
(4, 1000),
|
||||
]);
|
||||
|
||||
run_and_compare(candidates, voters, stake_of, 2, 2);
|
||||
run_and_compare::<Perbill>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<Permill>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<Percent>(candidates.clone(), voters.clone(), &stake_of, 2, 2);
|
||||
run_and_compare::<PerU16>(candidates, voters, &stake_of, 2, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -149,7 +168,7 @@ fn phragmen_accuracy_on_large_scale_only_validators() {
|
||||
(5, (u64::max_value() - 2).into()),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates.clone(),
|
||||
@@ -158,7 +177,7 @@ fn phragmen_accuracy_on_large_scale_only_validators() {
|
||||
|
||||
assert_eq_uvec!(winners, vec![(1, 18446744073709551614u128), (5, 18446744073709551613u128)]);
|
||||
assert_eq!(assignments.len(), 2);
|
||||
check_assignments(assignments);
|
||||
check_assignments_sum(assignments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -179,7 +198,7 @@ fn phragmen_accuracy_on_large_scale_validators_and_nominators() {
|
||||
(14, u64::max_value().into()),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates,
|
||||
@@ -190,13 +209,25 @@ fn phragmen_accuracy_on_large_scale_validators_and_nominators() {
|
||||
assert_eq!(
|
||||
assignments,
|
||||
vec![
|
||||
(13, vec![(1, Perbill::one())]),
|
||||
(14, vec![(2, Perbill::one())]),
|
||||
(1, vec![(1, Perbill::one())]),
|
||||
(2, vec![(2, Perbill::one())]),
|
||||
Assignment {
|
||||
who: 13u64,
|
||||
distribution: vec![(1, Perbill::one())],
|
||||
},
|
||||
Assignment {
|
||||
who: 14,
|
||||
distribution: vec![(2, Perbill::one())],
|
||||
},
|
||||
Assignment {
|
||||
who: 1,
|
||||
distribution: vec![(1, Perbill::one())],
|
||||
},
|
||||
Assignment {
|
||||
who: 2,
|
||||
distribution: vec![(2, Perbill::one())],
|
||||
},
|
||||
]
|
||||
);
|
||||
check_assignments(assignments);
|
||||
check_assignments_sum(assignments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -210,7 +241,7 @@ fn phragmen_accuracy_on_small_scale_self_vote() {
|
||||
(30, 1),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
3,
|
||||
3,
|
||||
candidates,
|
||||
@@ -240,7 +271,7 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() {
|
||||
(3, 1),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
3,
|
||||
3,
|
||||
candidates,
|
||||
@@ -273,7 +304,7 @@ fn phragmen_large_scale_test() {
|
||||
(50, 990000000000000000),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates,
|
||||
@@ -281,7 +312,7 @@ fn phragmen_large_scale_test() {
|
||||
).unwrap();
|
||||
|
||||
assert_eq_uvec!(winners, vec![(24, 1490000000000200000u128), (22, 1490000000000100000u128)]);
|
||||
check_assignments(assignments);
|
||||
check_assignments_sum(assignments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -299,7 +330,7 @@ fn phragmen_large_scale_test_2() {
|
||||
(50, nom_budget.into()),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates,
|
||||
@@ -310,12 +341,24 @@ fn phragmen_large_scale_test_2() {
|
||||
assert_eq!(
|
||||
assignments,
|
||||
vec![
|
||||
(50, vec![(2, Perbill::from_parts(500000001)), (4, Perbill::from_parts(499999999))]),
|
||||
(2, vec![(2, Perbill::one())]),
|
||||
(4, vec![(4, Perbill::one())]),
|
||||
Assignment {
|
||||
who: 50u64,
|
||||
distribution: vec![
|
||||
(2, Perbill::from_parts(500000001)),
|
||||
(4, Perbill::from_parts(499999999))
|
||||
],
|
||||
},
|
||||
Assignment {
|
||||
who: 2,
|
||||
distribution: vec![(2, Perbill::one())],
|
||||
},
|
||||
Assignment {
|
||||
who: 4,
|
||||
distribution: vec![(4, Perbill::one())],
|
||||
},
|
||||
],
|
||||
);
|
||||
check_assignments(assignments);
|
||||
check_assignments_sum(assignments);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -348,7 +391,7 @@ fn phragmen_linear_equalize() {
|
||||
(130, 1000),
|
||||
]);
|
||||
|
||||
run_and_compare(candidates, voters, stake_of, 2, 2);
|
||||
run_and_compare::<Perbill>(candidates, voters, &stake_of, 2, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -363,7 +406,7 @@ fn elect_has_no_entry_barrier() {
|
||||
(2, 10),
|
||||
]);
|
||||
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let PhragmenResult { winners, assignments: _ } = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
3,
|
||||
3,
|
||||
candidates,
|
||||
@@ -390,7 +433,7 @@ fn minimum_to_elect_is_respected() {
|
||||
(2, 10),
|
||||
]);
|
||||
|
||||
let maybe_result = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let maybe_result = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
10,
|
||||
10,
|
||||
candidates,
|
||||
@@ -416,7 +459,7 @@ fn self_votes_should_be_kept() {
|
||||
(1, 8),
|
||||
]);
|
||||
|
||||
let result = elect::<_, _, TestCurrencyToVote, Output>(
|
||||
let result = elect::<_, _, TestCurrencyToVote, Perbill>(
|
||||
2,
|
||||
2,
|
||||
candidates,
|
||||
@@ -427,27 +470,28 @@ fn self_votes_should_be_kept() {
|
||||
assert_eq!(
|
||||
result.assignments,
|
||||
vec![
|
||||
(10, vec![(10, Perbill::from_percent(100))]),
|
||||
(20, vec![(20, Perbill::from_percent(100))]),
|
||||
(1, vec![
|
||||
Assignment { who: 10, distribution: vec![(10, Perbill::from_percent(100))] },
|
||||
Assignment { who: 20, distribution: vec![(20, Perbill::from_percent(100))] },
|
||||
Assignment { who: 1, distribution: vec![
|
||||
(10, Perbill::from_percent(50)),
|
||||
(20, Perbill::from_percent(50))
|
||||
]
|
||||
)
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
let mut supports = build_support_map::<
|
||||
Balance,
|
||||
AccountId,
|
||||
_,
|
||||
TestCurrencyToVote,
|
||||
Output,
|
||||
>(
|
||||
&result.winners.into_iter().map(|(who, _)| who).collect(),
|
||||
&result.assignments,
|
||||
&stake_of
|
||||
);
|
||||
let staked_assignments: Vec<StakedAssignment<AccountId>> = result.assignments
|
||||
.into_iter()
|
||||
.map(|a| {
|
||||
let stake = <TestCurrencyToVote as Convert<Balance, u64>>::convert(stake_of(&a.who)) as ExtendedBalance;
|
||||
a.into_staked(stake, true)
|
||||
}).collect();
|
||||
|
||||
let winners = result.winners.into_iter().map(|(who, _)| who).collect::<Vec<AccountId>>();
|
||||
let (mut supports, _) = build_support_map::<AccountId>(
|
||||
winners.as_slice(),
|
||||
&staked_assignments,
|
||||
);
|
||||
|
||||
assert_eq!(supports.get(&5u64), None);
|
||||
assert_eq!(
|
||||
@@ -459,23 +503,13 @@ fn self_votes_should_be_kept() {
|
||||
&Support { total: 24u128, voters: vec![(20u64, 20u128), (1u64, 4u128)] },
|
||||
);
|
||||
|
||||
let assignments = result.assignments;
|
||||
let mut staked_assignments
|
||||
: Vec<(AccountId, Vec<PhragmenStakedAssignment<AccountId>>)>
|
||||
= Vec::with_capacity(assignments.len());
|
||||
for (n, assignment) in assignments.iter() {
|
||||
let mut staked_assignment
|
||||
: Vec<PhragmenStakedAssignment<AccountId>>
|
||||
= Vec::with_capacity(assignment.len());
|
||||
let stake = stake_of(&n);
|
||||
for (c, per_thing) in assignment.iter() {
|
||||
let vote_stake = *per_thing * stake;
|
||||
staked_assignment.push((c.clone(), vote_stake));
|
||||
}
|
||||
staked_assignments.push((n.clone(), staked_assignment));
|
||||
}
|
||||
|
||||
equalize::<Balance, AccountId, TestCurrencyToVote, _>(staked_assignments, &mut supports, 0, 2usize, &stake_of);
|
||||
equalize::<Balance, AccountId, TestCurrencyToVote, _>(
|
||||
staked_assignments,
|
||||
&mut supports,
|
||||
0,
|
||||
2usize,
|
||||
&stake_of,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
supports.get(&10u64).unwrap(),
|
||||
@@ -486,3 +520,462 @@ fn self_votes_should_be_kept() {
|
||||
&Support { total: 20u128, voters: vec![(20u64, 20u128)] },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assignment_convert_works() {
|
||||
let staked = StakedAssignment {
|
||||
who: 1 as AccountId,
|
||||
distribution: vec![
|
||||
(20, 100 as Balance),
|
||||
(30, 25),
|
||||
],
|
||||
};
|
||||
|
||||
let assignment = staked.clone().into_assignment(true);
|
||||
assert_eq!(
|
||||
assignment,
|
||||
Assignment {
|
||||
who: 1,
|
||||
distribution: vec![
|
||||
(20, Perbill::from_percent(80)),
|
||||
(30, Perbill::from_percent(20)),
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
assignment.into_staked(125, true),
|
||||
staked,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn score_comparison_is_lexicographical() {
|
||||
// only better in the fist parameter, worse in the other two ✅
|
||||
assert_eq!(
|
||||
is_score_better([10, 20, 30], [12, 10, 35]),
|
||||
true,
|
||||
);
|
||||
|
||||
// worse in the first, better in the other two ❌
|
||||
assert_eq!(
|
||||
is_score_better([10, 20, 30], [9, 30, 10]),
|
||||
false,
|
||||
);
|
||||
|
||||
// equal in the first, the second one dictates.
|
||||
assert_eq!(
|
||||
is_score_better([10, 20, 30], [10, 25, 40]),
|
||||
true,
|
||||
);
|
||||
|
||||
// equal in the first two, the last one dictates.
|
||||
assert_eq!(
|
||||
is_score_better([10, 20, 30], [10, 20, 40]),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
mod compact {
|
||||
use codec::{Decode, Encode};
|
||||
use crate::generate_compact_solution_type;
|
||||
use super::{AccountId, Balance};
|
||||
// these need to come from the same dev-dependency `sp-phragmen`, not from the crate.
|
||||
use sp_phragmen::{Assignment, StakedAssignment, Error as PhragmenError};
|
||||
use sp_std::{convert::{TryInto, TryFrom}, fmt::Debug};
|
||||
use sp_runtime::Percent;
|
||||
|
||||
type Accuracy = Percent;
|
||||
|
||||
generate_compact_solution_type!(TestCompact, 16);
|
||||
|
||||
#[test]
|
||||
fn compact_struct_is_codec() {
|
||||
let compact = TestCompact::<_, _, _> {
|
||||
votes1: vec![(2u64, 20), (4, 40)],
|
||||
votes2: vec![
|
||||
(1, (10, Accuracy::from_percent(80)), 11),
|
||||
(5, (50, Accuracy::from_percent(85)), 51),
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let encoded = compact.encode();
|
||||
|
||||
assert_eq!(
|
||||
compact,
|
||||
Decode::decode(&mut &encoded[..]).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
fn basic_ratio_test_with<V, T>() where
|
||||
V: codec::Codec + Copy + Default + PartialEq + Eq + TryInto<usize> + TryFrom<usize> + From<u8> + Debug,
|
||||
T: codec::Codec + Copy + Default + PartialEq + Eq + TryInto<usize> + TryFrom<usize> + From<u8> + Debug,
|
||||
<V as TryFrom<usize>>::Error: std::fmt::Debug,
|
||||
<T as TryFrom<usize>>::Error: std::fmt::Debug,
|
||||
<V as TryInto<usize>>::Error: std::fmt::Debug,
|
||||
<T as TryInto<usize>>::Error: std::fmt::Debug,
|
||||
{
|
||||
let voters = vec![
|
||||
2 as AccountId,
|
||||
4,
|
||||
1,
|
||||
5,
|
||||
3,
|
||||
];
|
||||
let targets = vec![
|
||||
10 as AccountId,
|
||||
11,
|
||||
20, // 2
|
||||
30,
|
||||
31, // 4
|
||||
32,
|
||||
40, // 6
|
||||
50,
|
||||
51, // 8
|
||||
];
|
||||
|
||||
let assignments = vec![
|
||||
Assignment {
|
||||
who: 2 as AccountId,
|
||||
distribution: vec![(20u64, Accuracy::from_percent(100))]
|
||||
},
|
||||
Assignment {
|
||||
who: 4,
|
||||
distribution: vec![(40, Accuracy::from_percent(100))],
|
||||
},
|
||||
Assignment {
|
||||
who: 1,
|
||||
distribution: vec![
|
||||
(10, Accuracy::from_percent(80)),
|
||||
(11, Accuracy::from_percent(20))
|
||||
],
|
||||
},
|
||||
Assignment {
|
||||
who: 5,
|
||||
distribution: vec![
|
||||
(50, Accuracy::from_percent(85)),
|
||||
(51, Accuracy::from_percent(15)),
|
||||
]
|
||||
},
|
||||
Assignment {
|
||||
who: 3,
|
||||
distribution: vec![
|
||||
(30, Accuracy::from_percent(50)),
|
||||
(31, Accuracy::from_percent(25)),
|
||||
(32, Accuracy::from_percent(25)),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
let voter_index = |a: &AccountId| -> Option<V> {
|
||||
voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
let target_index = |a: &AccountId| -> Option<T> {
|
||||
targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
|
||||
let compacted = <TestCompact<V, T, Percent>>::from_assignment(
|
||||
assignments.clone(),
|
||||
voter_index,
|
||||
target_index,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
compacted,
|
||||
TestCompact {
|
||||
votes1: vec![(V::from(0u8), T::from(2u8)), (V::from(1u8), T::from(6u8))],
|
||||
votes2: vec![
|
||||
(V::from(2u8), (T::from(0u8), Accuracy::from_percent(80)), T::from(1u8)),
|
||||
(V::from(3u8), (T::from(7u8), Accuracy::from_percent(85)), T::from(8u8)),
|
||||
],
|
||||
votes3: vec![
|
||||
(
|
||||
V::from(4),
|
||||
[(T::from(3u8), Accuracy::from_percent(50)), (T::from(4u8), Accuracy::from_percent(25))],
|
||||
T::from(5u8),
|
||||
),
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
let voter_at = |a: V| -> Option<AccountId> { voters.get(<V as TryInto<usize>>::try_into(a).unwrap()).cloned() };
|
||||
let target_at = |a: T| -> Option<AccountId> { targets.get(<T as TryInto<usize>>::try_into(a).unwrap()).cloned() };
|
||||
|
||||
assert_eq!(
|
||||
compacted.into_assignment(voter_at, target_at).unwrap(),
|
||||
assignments,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_from_and_into_compact_works_assignments() {
|
||||
basic_ratio_test_with::<u16, u16>();
|
||||
basic_ratio_test_with::<u16, u32>();
|
||||
basic_ratio_test_with::<u8, u32>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_from_and_into_compact_works_staked_assignments() {
|
||||
let voters = vec![
|
||||
2 as AccountId,
|
||||
4,
|
||||
1,
|
||||
5,
|
||||
3,
|
||||
];
|
||||
let targets = vec![
|
||||
10 as AccountId, 11,
|
||||
20,
|
||||
30, 31, 32,
|
||||
40,
|
||||
50, 51,
|
||||
];
|
||||
|
||||
let assignments = vec![
|
||||
StakedAssignment {
|
||||
who: 2 as AccountId,
|
||||
distribution: vec![(20, 100 as Balance)]
|
||||
},
|
||||
StakedAssignment {
|
||||
who: 4,
|
||||
distribution: vec![(40, 100)],
|
||||
},
|
||||
StakedAssignment {
|
||||
who: 1,
|
||||
distribution: vec![
|
||||
(10, 80),
|
||||
(11, 20)
|
||||
],
|
||||
},
|
||||
StakedAssignment {
|
||||
who: 5, distribution:
|
||||
vec![
|
||||
(50, 85),
|
||||
(51, 15),
|
||||
]
|
||||
},
|
||||
StakedAssignment {
|
||||
who: 3,
|
||||
distribution: vec![
|
||||
(30, 50),
|
||||
(31, 25),
|
||||
(32, 25),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
let voter_index = |a: &AccountId| -> Option<u16> {
|
||||
voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
let target_index = |a: &AccountId| -> Option<u16> {
|
||||
targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
|
||||
let compacted = <TestCompact<u16, u16, Balance>>::from_staked(
|
||||
assignments.clone(),
|
||||
voter_index,
|
||||
target_index,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
compacted,
|
||||
TestCompact {
|
||||
votes1: vec![(0, 2), (1, 6)],
|
||||
votes2: vec![
|
||||
(2, (0, 80), 1),
|
||||
(3, (7, 85), 8),
|
||||
],
|
||||
votes3: vec![
|
||||
(4, [(3, 50), (4, 25)], 5),
|
||||
],
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
|
||||
let max_of_fn = |_: &AccountId| -> Balance { 100u128 };
|
||||
let voter_at = |a: u16| -> Option<AccountId> { voters.get(a as usize).cloned() };
|
||||
let target_at = |a: u16| -> Option<AccountId> { targets.get(a as usize).cloned() };
|
||||
|
||||
assert_eq!(
|
||||
compacted.into_staked(
|
||||
max_of_fn,
|
||||
voter_at,
|
||||
target_at,
|
||||
).unwrap(),
|
||||
assignments,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_into_stake_must_report_overflow() {
|
||||
// The last edge which is computed from the rest should ALWAYS be positive.
|
||||
// in votes2
|
||||
let compact = TestCompact::<u16, u16, Balance> {
|
||||
votes1: Default::default(),
|
||||
votes2: vec![(0, (1, 10), 2)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let entity_at = |a: u16| -> Option<AccountId> { Some(a as AccountId) };
|
||||
let max_of = |_: &AccountId| -> Balance { 5 };
|
||||
|
||||
assert_eq!(
|
||||
compact.into_staked(&max_of, &entity_at, &entity_at).unwrap_err(),
|
||||
PhragmenError::CompactStakeOverflow,
|
||||
);
|
||||
|
||||
// in votes3 onwards
|
||||
let compact = TestCompact::<u16, u16, Balance> {
|
||||
votes1: Default::default(),
|
||||
votes2: Default::default(),
|
||||
votes3: vec![(0, [(1, 7), (2, 8)], 3)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compact.into_staked(&max_of, &entity_at, &entity_at).unwrap_err(),
|
||||
PhragmenError::CompactStakeOverflow,
|
||||
);
|
||||
|
||||
// Also if equal
|
||||
let compact = TestCompact::<u16, u16, Balance> {
|
||||
votes1: Default::default(),
|
||||
votes2: Default::default(),
|
||||
// 5 is total, we cannot leave none for 30 here.
|
||||
votes3: vec![(0, [(1, 3), (2, 2)], 3)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compact.into_staked(&max_of, &entity_at, &entity_at).unwrap_err(),
|
||||
PhragmenError::CompactStakeOverflow,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compact_into_assignment_must_report_overflow() {
|
||||
// in votes2
|
||||
let compact = TestCompact::<u16, u16, Accuracy> {
|
||||
votes1: Default::default(),
|
||||
votes2: vec![(0, (1, Accuracy::from_percent(100)), 2)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let entity_at = |a: u16| -> Option<AccountId> { Some(a as AccountId) };
|
||||
|
||||
assert_eq!(
|
||||
compact.into_assignment(&entity_at, &entity_at).unwrap_err(),
|
||||
PhragmenError::CompactStakeOverflow,
|
||||
);
|
||||
|
||||
// in votes3 onwards
|
||||
let compact = TestCompact::<u16, u16, Accuracy> {
|
||||
votes1: Default::default(),
|
||||
votes2: Default::default(),
|
||||
votes3: vec![(0, [(1, Accuracy::from_percent(70)), (2, Accuracy::from_percent(80))], 3)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
compact.into_assignment(&entity_at, &entity_at).unwrap_err(),
|
||||
PhragmenError::CompactStakeOverflow,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_count_overflow_is_detected() {
|
||||
let assignments = vec![
|
||||
StakedAssignment {
|
||||
who: 1 as AccountId,
|
||||
distribution: (10..26).map(|i| (i as AccountId, i as Balance)).collect::<Vec<_>>(),
|
||||
},
|
||||
];
|
||||
|
||||
let entity_index = |a: &AccountId| -> Option<u16> { Some(*a as u16) };
|
||||
|
||||
let compacted = <TestCompact<u16, u16, Balance>>::from_staked(
|
||||
assignments.clone(),
|
||||
entity_index,
|
||||
entity_index,
|
||||
);
|
||||
|
||||
assert!(compacted.is_ok());
|
||||
|
||||
let assignments = vec![
|
||||
StakedAssignment {
|
||||
who: 1 as AccountId,
|
||||
distribution: (10..27).map(|i| (i as AccountId, i as Balance)).collect::<Vec<_>>(),
|
||||
},
|
||||
];
|
||||
|
||||
let compacted = <TestCompact<u16, u16, Balance>>::from_staked(
|
||||
assignments.clone(),
|
||||
entity_index,
|
||||
entity_index,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compacted.unwrap_err(),
|
||||
PhragmenError::CompactTargetOverflow,
|
||||
);
|
||||
|
||||
let assignments = vec![
|
||||
Assignment {
|
||||
who: 1 as AccountId,
|
||||
distribution: (10..27).map(|i| (i as AccountId, Percent::from_parts(i as u8))).collect::<Vec<_>>(),
|
||||
},
|
||||
];
|
||||
|
||||
let compacted = <TestCompact<u16, u16, Percent>>::from_assignment(
|
||||
assignments.clone(),
|
||||
entity_index,
|
||||
entity_index,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compacted.unwrap_err(),
|
||||
PhragmenError::CompactTargetOverflow,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_target_count_is_ignored() {
|
||||
let voters = vec![1 as AccountId, 2];
|
||||
let targets = vec![10 as AccountId, 11];
|
||||
|
||||
let assignments = vec![
|
||||
StakedAssignment {
|
||||
who: 1 as AccountId,
|
||||
distribution: vec![(10, 100 as Balance), (11, 100)]
|
||||
},
|
||||
StakedAssignment {
|
||||
who: 2,
|
||||
distribution: vec![],
|
||||
},
|
||||
];
|
||||
|
||||
let voter_index = |a: &AccountId| -> Option<u16> {
|
||||
voters.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
let target_index = |a: &AccountId| -> Option<u16> {
|
||||
targets.iter().position(|x| x == a).map(TryInto::try_into).unwrap().ok()
|
||||
};
|
||||
|
||||
let compacted = <TestCompact<u16, u16, Balance>>::from_staked(
|
||||
assignments.clone(),
|
||||
voter_index,
|
||||
target_index,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
compacted,
|
||||
TestCompact {
|
||||
votes1: Default::default(),
|
||||
votes2: vec![(0, (0, 100), 1)],
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user