Redesign Democracy pallet (#5294)

* Repot a bit of democracy code

* Basic logic is drafted

* Lazy democracy builds.

* Add non-locked split-voting and instant-scheduling.

* Introduce delegation that works.

* Builds again.

* Indentation

* Building.

* Docs and migration

* Fix half of the tests

* Fix up & repot tests

* Fix runtime build

* Update docs

* Docs

* Nits.

* Turnout counts full capital

* Delegations could towards capital

* proxy delegation & proxy unvoting

* Fix

* Tests for split-voting

* Add missing file

* Persistent locking.
This commit is contained in:
Gavin Wood
2020-03-21 16:08:48 +01:00
committed by GitHub
parent 40f57f8ffa
commit 22f88bf9d1
19 changed files with 3080 additions and 1821 deletions
+16 -18
View File
@@ -21,6 +21,7 @@ use serde::{Serialize, Deserialize};
use codec::{Encode, Decode};
use sp_runtime::traits::{Zero, IntegerSquareRoot};
use sp_std::ops::{Add, Mul, Div, Rem};
use crate::Tally;
/// A means of determining if a vote is past pass threshold.
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug)]
@@ -35,10 +36,9 @@ pub enum VoteThreshold {
}
pub trait Approved<Balance> {
/// Given `approve` votes for and `against` votes against from a total electorate size of
/// `electorate` (`electorate - (approve + against)` are abstainers), then returns true if the
/// overall outcome is in favor of approval.
fn approved(&self, approve: Balance, against: Balance, voters: Balance, electorate: Balance) -> bool;
/// Given a `tally` of votes and a total size of `electorate`, this returns `true` if the
/// overall outcome is in favor of approval according to `self`'s threshold method.
fn approved(&self, tally: Tally<Balance>, electorate: Balance) -> bool;
}
/// Return `true` iff `n1 / d1 < n2 / d2`. `d1` and `d2` may not be zero.
@@ -69,23 +69,21 @@ fn compare_rationals<T: Zero + Mul<T, Output = T> + Div<T, Output = T> + Rem<T,
}
}
impl<Balance: IntegerSquareRoot + Zero + Ord + Add<Balance, Output = Balance> + Mul<Balance, Output = Balance> + Div<Balance, Output = Balance> + Rem<Balance, Output = Balance> + Copy> Approved<Balance> for VoteThreshold {
/// Given `approve` votes for and `against` votes against from a total electorate size of
/// `electorate` of whom `voters` voted (`electorate - voters` are abstainers) then returns true if the
/// overall outcome is in favor of approval.
///
/// We assume each *voter* may cast more than one *vote*, hence `voters` is not necessarily equal to
/// `approve + against`.
fn approved(&self, approve: Balance, against: Balance, voters: Balance, electorate: Balance) -> bool {
let sqrt_voters = voters.integer_sqrt();
impl<
Balance: IntegerSquareRoot + Zero + Ord + Add<Balance, Output = Balance>
+ Mul<Balance, Output = Balance> + Div<Balance, Output = Balance>
+ Rem<Balance, Output = Balance> + Copy,
> Approved<Balance> for VoteThreshold {
fn approved(&self, tally: Tally<Balance>, electorate: Balance) -> bool {
let sqrt_voters = tally.turnout.integer_sqrt();
let sqrt_electorate = electorate.integer_sqrt();
if sqrt_voters.is_zero() { return false; }
match *self {
VoteThreshold::SuperMajorityApprove =>
compare_rationals(against, sqrt_voters, approve, sqrt_electorate),
compare_rationals(tally.nays, sqrt_voters, tally.ayes, sqrt_electorate),
VoteThreshold::SuperMajorityAgainst =>
compare_rationals(against, sqrt_electorate, approve, sqrt_voters),
VoteThreshold::SimpleMajority => approve > against,
compare_rationals(tally.nays, sqrt_electorate, tally.ayes, sqrt_voters),
VoteThreshold::SimpleMajority => tally.ayes > tally.nays,
}
}
}
@@ -96,7 +94,7 @@ mod tests {
#[test]
fn should_work() {
assert_eq!(VoteThreshold::SuperMajorityApprove.approved(60, 50, 110, 210), false);
assert_eq!(VoteThreshold::SuperMajorityApprove.approved(100, 50, 150, 210), true);
assert!(!VoteThreshold::SuperMajorityApprove.approved(Tally{ayes: 60, nays: 50, turnout: 110}, 210));
assert!(VoteThreshold::SuperMajorityApprove.approved(Tally{ayes: 100, nays: 50, turnout: 150}, 210));
}
}