From bac2c2e1f28a91503b1092103f82c7073f193521 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 27 Feb 2020 00:55:09 +0800 Subject: [PATCH 1/3] remove: unused file --- client/cli/README.adoc | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 client/cli/README.adoc diff --git a/client/cli/README.adoc b/client/cli/README.adoc deleted file mode 100644 index fc58908fd..000000000 --- a/client/cli/README.adoc +++ /dev/null @@ -1,6 +0,0 @@ - -= Substrate CLI - -Substrate CLI library - -include::doc/shell-completion.adoc[] From deb27ed6eccbe1cdae58591f54f6a59dfcfa4a8e Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 27 Feb 2020 00:55:27 +0800 Subject: [PATCH 2/3] update: format --- bin/node/runtime/src/lib.rs | 2 +- primitives/phragmen/src/mock.rs | 24 +++++++-------- primitives/phragmen/src/tests.rs | 52 ++++++++++++++++---------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index d8c40ef03..2137fc95e 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -523,7 +523,6 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment::{Module, Storage}, Session: pallet_session::{Module, Call, Storage, Event, Config}, Council: pallet_collective::::{Module, Call, Storage, Origin, Event, Config}, - Elections: pallet_elections_phragmen::{Module, Call, Storage, Event}, TechnicalCommittee: pallet_collective::::{Module, Call, Storage, Origin, Event, Config}, TechnicalMembership: pallet_membership ::, FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent}, @@ -536,6 +535,7 @@ construct_runtime!( RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, Nicks: pallet_nicks::{Module, Call, Storage, Event}, + Elections: pallet_elections_phragmen::{Module, Call, Storage, Event}, EthBacking: pallet_eth_backing, EthRelay: pallet_eth_relay, Kton: pallet_kton, diff --git a/primitives/phragmen/src/mock.rs b/primitives/phragmen/src/mock.rs index 3b25824ef..d8f13ce59 100644 --- a/primitives/phragmen/src/mock.rs +++ b/primitives/phragmen/src/mock.rs @@ -53,8 +53,8 @@ pub(crate) fn create_stake_of(stakes: &[(AccountId, Power)]) -> Box Power { storage.get(who).unwrap().to_owned() }; - Box::new(stake_of) + let power_of = move |who: &AccountId| -> Power { storage.get(who).unwrap().to_owned() }; + Box::new(power_of) } pub(crate) fn auto_generate_self_voters(candidates: &[A]) -> Vec<(A, Vec)> { @@ -71,16 +71,16 @@ pub(crate) fn check_assignments(assignments: Vec<(AccountId, Vec, voters: Vec<(AccountId, Vec)>, - stake_of: Box Power>, + power_of: Box Power>, to_elect: usize, min_to_elect: usize, ) { // run fixed point code. let PhragmenResult { winners, assignments } = - elect::<_, _>(to_elect, min_to_elect, candidates.clone(), voters.clone(), &stake_of).unwrap(); + elect::<_, _>(to_elect, min_to_elect, candidates.clone(), voters.clone(), &power_of).unwrap(); // run float poc code. - let truth_value = elect_float(to_elect, min_to_elect, candidates, voters, &stake_of).unwrap(); + let truth_value = elect_float(to_elect, min_to_elect, candidates, voters, &power_of).unwrap(); assert_eq!(winners, truth_value.winners); @@ -110,7 +110,7 @@ pub(crate) fn elect_float( minimum_candidate_count: usize, initial_candidates: Vec, initial_voters: Vec<(A, Vec)>, - stake_of: FS, + power_of: FS, ) -> Option<_PhragmenResult> where A: Default + Ord + Member + Copy, @@ -139,7 +139,7 @@ where } voters.extend(initial_voters.into_iter().map(|(who, votes)| { - let voter_stake = stake_of(&who) as f64; + let voter_stake = power_of(&who) as f64; let mut edges: Vec<_Edge> = Vec::with_capacity(votes.len()); for v in votes { if let Some(idx) = c_idx_cache.get(&v) { @@ -220,7 +220,7 @@ where }) } -pub(crate) fn build_support_map(result: &mut _PhragmenResult, stake_of: FS) -> _SupportMap +pub(crate) fn build_support_map(result: &mut _PhragmenResult, power_of: FS) -> _SupportMap where for<'r> FS: Fn(&'r AccountId) -> Power, { @@ -228,7 +228,7 @@ where result .winners .iter() - .map(|(e, _)| (e, stake_of(e) as f64)) + .map(|(e, _)| (e, power_of(e) as f64)) .for_each(|(e, s)| { let item = _Support { own: s, @@ -240,7 +240,7 @@ where for (n, assignment) in result.assignments.iter_mut() { for (c, r) in assignment.iter_mut() { - let nominator_stake = stake_of(n) as f64; + let nominator_stake = power_of(n) as f64; let other_stake = nominator_stake * *r; if let Some(support) = supports.get_mut(c) { support.total = support.total + other_stake; @@ -257,7 +257,7 @@ pub(crate) fn equalize_float( supports: &mut _SupportMap, tolerance: f64, iterations: usize, - stake_of: FS, + power_of: FS, ) where for<'r> FS: Fn(&'r A) -> Power, A: Ord + Clone + std::fmt::Debug, @@ -265,7 +265,7 @@ pub(crate) fn equalize_float( for _i in 0..iterations { let mut max_diff = 0.0; for (voter, assignment) in assignments.iter_mut() { - let voter_budget = stake_of(&voter); + let voter_budget = power_of(&voter); let diff = do_equalize_float(voter, voter_budget, assignment, supports, tolerance); if diff > max_diff { max_diff = diff; diff --git a/primitives/phragmen/src/tests.rs b/primitives/phragmen/src/tests.rs index 462ba31ad..a55d5d795 100644 --- a/primitives/phragmen/src/tests.rs +++ b/primitives/phragmen/src/tests.rs @@ -11,8 +11,8 @@ use crate::{elect, mock::*, PhragmenResult}; fn float_phragmen_poc_works() { 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), (1, 0), (2, 0), (3, 0)]); - let mut phragmen_result = elect_float(2, 2, candidates, voters, &stake_of).unwrap(); + let power_of = create_stake_of(&[(10, 10), (20, 20), (30, 30), (1, 0), (2, 0), (3, 0)]); + let mut phragmen_result = elect_float(2, 2, candidates, voters, &power_of).unwrap(); let winners = phragmen_result.clone().winners; let assignments = phragmen_result.clone().assignments; @@ -26,7 +26,7 @@ fn float_phragmen_poc_works() { ] ); - let mut support_map = build_support_map(&mut phragmen_result, &stake_of); + let mut support_map = build_support_map(&mut phragmen_result, &power_of); assert_eq!( support_map.get(&2).unwrap(), @@ -45,7 +45,7 @@ fn float_phragmen_poc_works() { } ); - equalize_float(phragmen_result.assignments, &mut support_map, 0.0, 2, stake_of); + equalize_float(phragmen_result.assignments, &mut support_map, 0.0, 2, power_of); assert_eq!( support_map.get(&2).unwrap(), @@ -97,18 +97,18 @@ fn phragmen_poc_works() { fn phragmen_poc_2_works() { let candidates = vec![10, 20, 30]; let voters = vec![(2, vec![10, 20, 30]), (4, vec![10, 20, 40])]; - let stake_of = create_stake_of(&[(10, 1_000), (20, 1_000), (30, 1_000), (40, 1_000), (2, 500), (4, 500)]); + let power_of = create_stake_of(&[(10, 1_000), (20, 1_000), (30, 1_000), (40, 1_000), (2, 500), (4, 500)]); - run_and_compare(candidates, voters, stake_of, 2, 2); + run_and_compare(candidates, voters, power_of, 2, 2); } #[test] fn phragmen_poc_3_works() { let candidates = vec![10, 20, 30]; let voters = vec![(2, vec![10, 20, 30]), (4, vec![10, 20, 40])]; - let stake_of = create_stake_of(&[(10, 1_000), (20, 1_000), (30, 1_000), (2, 50), (4, 1_000)]); + let power_of = create_stake_of(&[(10, 1_000), (20, 1_000), (30, 1_000), (2, 50), (4, 1_000)]); - run_and_compare(candidates, voters, stake_of, 2, 2); + run_and_compare(candidates, voters, power_of, 2, 2); } #[test] @@ -116,7 +116,7 @@ fn phragmen_accuracy_on_large_scale_only_validators() { // because of this particular situation we had per_u128 and now rational128. In practice, a // candidate can have the maximum amount of tokens, and also supported by the maximum. let candidates = vec![1, 2, 3, 4, 5]; - let stake_of = create_stake_of(&[ + let power_of = create_stake_of(&[ (1, (u32::max_value() - 1).into()), (2, (u32::max_value() - 4).into()), (3, (u32::max_value() - 5).into()), @@ -129,7 +129,7 @@ fn phragmen_accuracy_on_large_scale_only_validators() { 2, candidates.clone(), auto_generate_self_voters(&candidates), - stake_of, + power_of, ) .unwrap(); @@ -143,7 +143,7 @@ fn phragmen_accuracy_on_large_scale_validators_and_nominators() { let candidates = vec![1, 2, 3, 4, 5]; let mut voters = vec![(13, vec![1, 3, 5]), (14, vec![2, 4])]; voters.extend(auto_generate_self_voters(&candidates)); - let stake_of = create_stake_of(&[ + let power_of = create_stake_of(&[ (1, (u32::max_value() - 1).into()), (2, (u32::max_value() - 4).into()), (3, (u32::max_value() - 5).into()), @@ -153,7 +153,7 @@ fn phragmen_accuracy_on_large_scale_validators_and_nominators() { (14, u32::max_value().into()), ]); - let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, stake_of).unwrap(); + let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, power_of).unwrap(); assert_eq_uvec!(winners, vec![(2, 8_589_934_586_u64), (1, 8_589_934_579_u64)]); assert_eq!( @@ -172,12 +172,12 @@ fn phragmen_accuracy_on_large_scale_validators_and_nominators() { fn phragmen_accuracy_on_small_scale_self_vote() { let candidates = vec![40, 10, 20, 30]; let voters = auto_generate_self_voters(&candidates); - let stake_of = create_stake_of(&[(40, 0), (10, 1), (20, 2), (30, 1)]); + let power_of = create_stake_of(&[(40, 0), (10, 1), (20, 2), (30, 1)]); let PhragmenResult { winners, assignments: _, - } = elect::<_, _>(3, 3, candidates, voters, stake_of).unwrap(); + } = elect::<_, _>(3, 3, candidates, voters, power_of).unwrap(); assert_eq_uvec!(winners, vec![(20, 2), (10, 1), (30, 1)]); } @@ -186,7 +186,7 @@ fn phragmen_accuracy_on_small_scale_self_vote() { fn phragmen_accuracy_on_small_scale_no_self_vote() { let candidates = vec![40, 10, 20, 30]; let voters = vec![(1, vec![10]), (2, vec![20]), (3, vec![30]), (4, vec![40])]; - let stake_of = create_stake_of(&[ + let power_of = create_stake_of(&[ (40, 1000), // don't care (10, 1000), // don't care (20, 1000), // don't care @@ -200,7 +200,7 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() { let PhragmenResult { winners, assignments: _, - } = elect::<_, _>(3, 3, candidates, voters, stake_of).unwrap(); + } = elect::<_, _>(3, 3, candidates, voters, power_of).unwrap(); assert_eq_uvec!(winners, vec![(20, 2), (10, 1), (30, 1)]); } @@ -210,7 +210,7 @@ fn phragmen_large_scale_test() { let candidates = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24]; let mut voters = vec![(50, vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24])]; voters.extend(auto_generate_self_voters(&candidates)); - let stake_of = create_stake_of(&[ + let power_of = create_stake_of(&[ (2, 1), (4, 10), (6, 100), @@ -226,7 +226,7 @@ fn phragmen_large_scale_test() { (50, 99_000_000), ]); - let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, stake_of).unwrap(); + let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, power_of).unwrap(); assert_eq_uvec!(winners, vec![(24, 149_200_000_u64), (22, 149_100_000_u64)]); check_assignments(assignments); @@ -241,9 +241,9 @@ fn phragmen_large_scale_test_2() { let mut voters = vec![(50, vec![2, 4])]; voters.extend(auto_generate_self_voters(&candidates)); - let stake_of = create_stake_of(&[(2, c_budget as _), (4, c_budget as _), (50, nom_budget as _)]); + let power_of = create_stake_of(&[(2, c_budget as _), (4, c_budget as _), (50, nom_budget as _)]); - let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, stake_of).unwrap(); + let PhragmenResult { winners, assignments } = elect::<_, _>(2, 2, candidates, voters, power_of).unwrap(); assert_eq_uvec!(winners, vec![(2, 999_999_991_u64), (4, 999_999_991_u64)]); assert_eq!( @@ -275,7 +275,7 @@ fn phragmen_linear_equalize() { (120, vec![51, 61]), (130, vec![61, 71]), ]; - let stake_of = create_stake_of(&[ + let power_of = create_stake_of(&[ (11, 1000), (21, 1000), (31, 1000), @@ -292,19 +292,19 @@ fn phragmen_linear_equalize() { (130, 1000), ]); - run_and_compare(candidates, voters, stake_of, 2, 2); + run_and_compare(candidates, voters, power_of, 2, 2); } #[test] fn elect_has_no_entry_barrier() { let candidates = vec![10, 20, 30]; let voters = vec![(1, vec![10]), (2, vec![20])]; - let stake_of = create_stake_of(&[(1, 10), (2, 10)]); + let power_of = create_stake_of(&[(1, 10), (2, 10)]); let PhragmenResult { winners, assignments: _, - } = elect::<_, _>(3, 3, candidates, voters, stake_of).unwrap(); + } = elect::<_, _>(3, 3, candidates, voters, power_of).unwrap(); // 30 is elected with stake 0. The caller is responsible for stripping this. assert_eq_uvec!(winners, vec![(10, 10), (20, 10), (30, 0),]); @@ -314,9 +314,9 @@ fn elect_has_no_entry_barrier() { fn minimum_to_elect_is_respected() { let candidates = vec![10, 20, 30]; let voters = vec![(1, vec![10]), (2, vec![20])]; - let stake_of = create_stake_of(&[(1, 10), (2, 10)]); + let power_of = create_stake_of(&[(1, 10), (2, 10)]); - let maybe_result = elect::<_, _>(10, 10, candidates, voters, stake_of); + let maybe_result = elect::<_, _>(10, 10, candidates, voters, power_of); assert!(maybe_result.is_none()); } From ce60d9205eda0e779fd6963443bfb6b7b2fcbd7c Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Thu, 27 Feb 2020 01:59:30 +0800 Subject: [PATCH 3/3] update: do equalize for KTON and RING, optimize storage --- frame/staking/src/lib.rs | 9 ++------ primitives/phragmen/src/lib.rs | 38 +++++++++++++--------------------- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index e467b13e3..28e1ab042 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -626,10 +626,6 @@ where pub own_kton_balance: KtonBalance, pub own_power: Power, /// The total balance backing this validator. - #[codec(compact)] - pub total_ring_balance: RingBalance, - #[codec(compact)] - pub total_kton_balance: KtonBalance, pub total_power: Power, /// The portions of nominators stashes that are exposed. pub others: Vec>, @@ -1618,7 +1614,8 @@ impl Module { // PUBLIC IMMUTABLES // power is a mixture of ring and kton - // power = ring_ratio * POWER_COUNT / 2 + kton_ratio * POWER_COUNT / 2 + // For *RING* power = ring_ratio * POWER_COUNT / 2 + // For *KTON* power = kton_ratio * POWER_COUNT / 2 pub fn currency_to_power>(active: S, pool: S) -> Power { (Perquintill::from_rational_approximation( active.saturated_into::(), @@ -2093,8 +2090,6 @@ impl Module { own_ring_balance: s.own_ring_balance, own_kton_balance: s.own_kton_balance, own_power: to_power(s.own_votes), - total_ring_balance: s.total_ring_balance, - total_kton_balance: s.total_kton_balance, total_power: to_power(s.total_votes), others: s .others diff --git a/primitives/phragmen/src/lib.rs b/primitives/phragmen/src/lib.rs index 8a253367b..945f71b62 100644 --- a/primitives/phragmen/src/lib.rs +++ b/primitives/phragmen/src/lib.rs @@ -23,13 +23,13 @@ mod mock; mod tests; use sp_runtime::{ - traits::{Member, Saturating, SimpleArithmetic, Zero}, + helpers_128bit::multiply_by_rational, + traits::{Member, SaturatedConversion, Saturating, SimpleArithmetic, Zero}, Perbill, RuntimeDebug, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; use darwinia_support::Rational64; -use sp_runtime::traits::SaturatedConversion; /// Power of an account. pub type Power = u32; @@ -116,13 +116,11 @@ pub struct PhragmenResult { #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct Support { /// The amount of support as the effect of self-vote. - pub own_votes: Votes, pub own_ring_balance: RingBalance, pub own_kton_balance: KtonBalance, + pub own_votes: Votes, /// Total support. pub total_votes: Votes, - pub total_ring_balance: RingBalance, - pub total_kton_balance: KtonBalance, /// Support from voters. pub others: Vec>, } @@ -355,12 +353,12 @@ where for (c, per_thing) in assignment.iter() { if let Some(support) = supports.get_mut(c) { let nominator_stake = to_votes(power_of(n)); + // AUDIT: it is crucially important for the `Mul` implementation of all + // per-things to be sound. let (ring_balance, kton_balance) = { let (r, k) = stake_of(n); (*per_thing * r, *per_thing * k) }; - // AUDIT: it is crucially important for the `Mul` implementation of all - // per-things to be sound. let other_stake = *per_thing * nominator_stake; if c == n { // This is a nomination from `n` to themselves. This will increase both the @@ -368,10 +366,8 @@ where debug_assert!(*per_thing == Perbill::one()); // TODO: deal with this: do we want it? support.own_ring_balance = support.own_ring_balance.saturating_add(ring_balance); - support.total_ring_balance = support.total_ring_balance.saturating_add(ring_balance); support.own_kton_balance = support.own_kton_balance.saturating_add(kton_balance); - support.total_kton_balance = support.total_kton_balance.saturating_add(kton_balance); support.own_votes = support.own_votes.saturating_add(other_stake); support.total_votes = support.total_votes.saturating_add(other_stake); @@ -380,8 +376,6 @@ where // inside `others`. // For an astronomically rich validator with more astronomically rich // set of nominators, this might saturate. - support.total_ring_balance = support.total_ring_balance.saturating_add(ring_balance); - support.total_kton_balance = support.total_kton_balance.saturating_add(kton_balance); support.total_votes = support.total_votes.saturating_add(other_stake); support.others.push(PhragmenStakedAssignment { @@ -532,25 +526,21 @@ where idx += 1; } - let PhragmenStakedAssignment { - ring_balance: last_ring_balance, - kton_balance: last_kton_balance, - votes: last_votes, - .. - } = elected_edges[last_index]; + let last_votes = elected_edges[last_index].votes; let split_ways = last_index + 1; let excess = budget .saturating_add(cumulative_stake) .saturating_sub(last_votes.saturating_mul(split_ways as Votes)); elected_edges.iter_mut().take(split_ways).for_each(|e| { if let Some(support) = support_map.get_mut(&e.account_id) { - e.ring_balance = ((excess.saturated_into::() / split_ways.saturated_into::()) - + last_ring_balance) - .saturating_sub(support.total_ring_balance); - e.kton_balance = ((excess.saturated_into::() / split_ways.saturated_into::()) - + last_kton_balance) - .saturating_sub(support.total_kton_balance); - e.votes = ((excess / split_ways as Votes) + last_votes).saturating_sub(support.total_votes); + let votes = ((excess / split_ways as Votes) + last_votes).saturating_sub(support.total_votes); + e.ring_balance = multiply_by_rational(e.ring_balance.saturated_into(), votes as _, e.votes as _) + .unwrap_or(0) + .saturated_into(); + e.kton_balance = multiply_by_rational(e.kton_balance.saturated_into(), votes as _, e.votes as _) + .unwrap_or(0) + .saturated_into(); + e.votes = votes; support.total_votes = support.total_votes.saturating_add(e.votes); support.others.push(PhragmenStakedAssignment {