Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
acab9a3
Block builder (substrate)
gavofyork Feb 12, 2018
9acd3f9
Fix wasm build
gavofyork Feb 12, 2018
ca5900f
Bulid on any block
gavofyork Feb 13, 2018
d11cfe1
Test for block builder.
gavofyork Feb 13, 2018
b973ccc
Block import tests for client.
gavofyork Feb 13, 2018
ec61865
Tidy ups
gavofyork Feb 13, 2018
cec06a7
Repotted client
gavofyork Feb 13, 2018
38cd36a
Avoid pointless work
gavofyork Feb 13, 2018
8b7abca
All backend stuff now manages optional storage.
gavofyork Feb 13, 2018
9dba812
Native runtime-io now supports empty storage items.
gavofyork Feb 13, 2018
0f591c6
Finish up the API transition.
gavofyork Feb 14, 2018
79c6b4c
Merge branch 'master' into gav-optional-storage
gavofyork Feb 15, 2018
a802b7e
Build fix.
gavofyork Feb 15, 2018
3928c1c
Fix tests.
gavofyork Feb 15, 2018
002ab5f
Merge branch 'master' into gav-optional-storage
gavofyork Feb 16, 2018
61db63f
Remerge in changes to client.
gavofyork Feb 16, 2018
5d1a3a7
Final fixes.
gavofyork Feb 16, 2018
212d370
Unrevert typos
gavofyork Feb 17, 2018
780e549
Remove accidentally committed change
gavofyork Feb 18, 2018
e552875
Bring back zero copy
gavofyork Feb 18, 2018
0a08196
Fix merge.
gavofyork Feb 18, 2018
e25960b
Refactor out some duped code
gavofyork Feb 19, 2018
9042880
Merge branch 'master' into gav-demo
gavofyork Feb 20, 2018
af3a413
Add docs.
gavofyork Feb 20, 2018
2b13856
More mssing doc.
gavofyork Feb 20, 2018
08060a6
Fix up wasm build.
gavofyork Feb 20, 2018
036142c
Introduce substrate-demo
gavofyork Feb 20, 2018
38bf4d7
Remove bad files.
gavofyork Feb 20, 2018
a2fb006
Tidy up unneeded code.
gavofyork Feb 20, 2018
775cb5a
Add needed file.
gavofyork Feb 20, 2018
0b83481
Initial staging ground for interior wasm smart-contracts.
gavofyork Feb 20, 2018
3413d14
More work on Ext & calls.
gavofyork Feb 22, 2018
0a82fd2
Fix logic
gavofyork Feb 23, 2018
b098eb2
comment
gavofyork Feb 23, 2018
73c4141
Remove unneeded call depth.
gavofyork Feb 25, 2018
9ef9c01
Use BTreeMap rather than HashMap in demo runtime.
gavofyork Feb 25, 2018
59c371f
Initial draft of stakeholder democracy.
gavofyork Feb 25, 2018
696f22a
Tests for referenda.
gavofyork Feb 26, 2018
98b74bc
Design of the approval voting module for council election.
gavofyork Feb 27, 2018
87bc061
Implement next_tally.
gavofyork Feb 28, 2018
f5ad966
More work on governance.
gavofyork Feb 28, 2018
afcff76
Submit candidacy.
gavofyork Mar 1, 2018
264384d
presenting a winner.
gavofyork Mar 1, 2018
822a5dc
Final bit of core logic for the council.
gavofyork Mar 1, 2018
9a1d638
remove inactive voter.
gavofyork Mar 1, 2018
4618367
Space out votes by a minimum period.
gavofyork Mar 1, 2018
9af17a5
Candidacy tests
gavofyork Mar 2, 2018
511775c
More candidate tests.
gavofyork Mar 2, 2018
2eeb88e
More tests for voting.
gavofyork Mar 2, 2018
5ea3f2b
Test for tally
gavofyork Mar 2, 2018
bcb2b39
More tests, for runners-up.
gavofyork Mar 2, 2018
3541d4e
test: second tally uses runners-up.
gavofyork Mar 2, 2018
a0c405f
Tests: various error cases with present.
gavofyork Mar 2, 2018
899e26e
tests: presenting losers
gavofyork Mar 2, 2018
4777806
cleanups.
gavofyork Mar 2, 2018
f0d5f53
Merge branch 'master' into gav-demo
gavofyork Mar 2, 2018
f276b4d
tests: Retract inactive voter
gavofyork Mar 2, 2018
05b6a8d
Additional docs & test.
gavofyork Mar 2, 2018
2bf2799
Add one vote worth of time for voters to unregister before they becom…
gavofyork Mar 2, 2018
999c082
Avoid allowing same accounts to be doubly-elected.
gavofyork Mar 2, 2018
0c9265f
test: against double presentations.
gavofyork Mar 2, 2018
3c911cd
Update docs
gavofyork Mar 2, 2018
002ddab
Simultaneous referendums and multiple voting variants.
gavofyork Mar 3, 2018
b8cc3a1
Introduce logic for deposits.
gavofyork Mar 3, 2018
9aeb95c
Deposits, not fees.
gavofyork Mar 3, 2018
fffbadd
cleanups.
gavofyork Mar 3, 2018
6dfe148
Introduce minimum deposit
gavofyork Mar 3, 2018
907fac7
Tests for public referenda.
gavofyork Mar 4, 2018
0bbd6b3
Tests for public referenda.
gavofyork Mar 4, 2018
8df2342
remove string constants <-- @rphmeier
gavofyork Mar 4, 2018
c73e3f9
Ensure council always sorted by expiry.
gavofyork Mar 4, 2018
0bb5791
Initial council vote logic.
gavofyork Mar 4, 2018
f780504
More tests for council voting.
gavofyork Mar 5, 2018
25b8c20
council vetoing & tests.
gavofyork Mar 5, 2018
7ef0b17
Another few tests for council_vote.
gavofyork Mar 5, 2018
8b37acf
Final tests.
gavofyork Mar 6, 2018
bb7f398
Move council over to new Keyring API.
gavofyork Mar 6, 2018
8be2cc8
Move democracy module over no new Keyring API
gavofyork Mar 6, 2018
7e6e40d
Introduce stake reservation; make panicking tests better.
gavofyork Mar 6, 2018
7e8e404
Genesis map.
gavofyork Mar 7, 2018
2d66a63
Use a struct!
gavofyork Mar 7, 2018
22d4829
Tests for staking reserved balances & slashing.
gavofyork Mar 10, 2018
5450807
Public function dispatching.
gavofyork Mar 10, 2018
e09096c
Safe panic.
gavofyork Mar 10, 2018
128fa23
Fix tests and avoid use of old keys.
gavofyork Mar 10, 2018
d347030
Fix grumbles.
gavofyork Mar 11, 2018
b6897d5
Minor typos.
gavofyork Mar 11, 2018
6029553
Cleanups and introduce all dispatchable endpoints.
gavofyork Mar 12, 2018
f3439c9
Additional function ids for derivation.
gavofyork Mar 12, 2018
23b030a
Formatting.
gavofyork Mar 12, 2018
016a7b6
Remove stray printlns.
gavofyork Mar 14, 2018
0f81021
Merge branch 'master' into gav-demo
gavofyork Mar 14, 2018
5c9a40a
Update wasm.
gavofyork Mar 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Design of the approval voting module for council election.
  • Loading branch information
gavofyork committed Feb 27, 2018
commit 98b74bcdb4775ea0370749da6566f6aa002e9bd0
272 changes: 272 additions & 0 deletions demo/runtime/src/runtime/council.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.

// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.

//! Council system: Handles the voting in and maintenance of council members.

use rstd::prelude::*;
use codec::KeyedVec;
use runtime_support::storage;
use demo_primitives::{Proposal, AccountId, Hash, BlockNumber};
use runtime::{staking, system, session};
use runtime::staking::Balance;

// no polynomial attack:
// all public operations should be constant time.
Copy link
Contributor

@rphmeier rphmeier Mar 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constant time in what parameter? storage access isn't constant time in general.

// all protected operations may be at most O(public operations)

// public operations:
// - express approval (ideally, express all approvals)
// - re-express approval (ideally, re-express all approvals)
// - clear all approvals
// - submit candidacy
// protected operations:
// - remove candidacy (remove all votes for a candidate)

// for an approval vote of C councilers:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a vote for approval of C councillors or a vote by C councillors for approval of something?


// top K candidates are maintained between votes. all others are discarded.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the candidates are candidates in the councillor election?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invariant: K >= C?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are, yes. and no - K and C have no relation.

// - candidate removed & bond returned when elected.
// - candidate removed & bond burned when discarded.

// at the point that the vote ends, all voters' balances are snapshotted.

// for B blocks following, there's a counting period whereby each of the candidates that believe
// they fall in the top K+C voted can present themselves. they get the total stake
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why K+C?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C winners + K runners-up that are persisted as candidates (with the approvals) between votes.

// recorded (based on the snapshot); an ordered list is maintained. Noone may present themselves
// that, if elected, would result in being included twice on the council (important since existing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how can that happen? are existing councillors migrated over? someone shouldn't be able to announce candidacy if they are already on the council or have already announced their candidacy.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elections don't (necessarily) replace all of the councillors; only the ones that are expiring or for seats that are for whatever reason unfilled.

// councilers will will have their approval votes as it may be that they don't get removed), nor
// if existing presenters would mean they're not in the top K+C.

// following B blocks, the top C+K that presented themselves have their bond returned and the
// top C candidates are elected. the top C candidates have their bond returned.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it the top C+K or the top C that have their bond returned?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and everyone who loses the election loses their money?

Copy link
Member Author

@gavofyork gavofyork Mar 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everyone who outright loses it, yes. those who come close enough (within K) of winning get to stick around for the next vote.


// the top C candidates and all other candidates beyond the top C+K are cleared and the clearing
// mask is appended to mask list (ready to be applied to vote arrays).

// vote-clearing happens lazily, with previous write also storing the round and all subsequent
// rounds' operations applied at the next read/write time.

// vote buffer size increases as required.
// bond taken for initial approval, returned when clearing.

// vec<candidate> (list of addresses, each bonded, can contain "holes" of null addresses). Order important.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the order important?

Copy link
Member Author

@gavofyork gavofyork Mar 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because approvals are provided and stored in a single chunk and are allowed to stick around between votes without further effort by voters. so index needs to persist.

// vec<voter> (all voters. order unimportant - just need to be enumerable.)
// voter -> (last round, Vec<bool>)

const CURRENT_VOTE: &[u8] = b"cou:cur";
const APPROVALS_OF: &[u8] = b"cou:apr:";
const VOTERS: &[u8] = b"cou:vrs";
const CANDIDATES: &[u8] = b"cou:can";

const CANDIDACY_BOND: &[u8] = b"cou:cbo";
const VOTING_BOND: &[u8] = b"cou:vbo";

const CARRY_COUNT: &[u8] = b"cou:cco";
const PRESENTATION_DURATION: &[u8] = b"cou:pdu";

const WINNERS: &[u8] = b"cou:win";

/// How much should be locked up in order to submit one's candidacy.
pub fn candidacy_bond() -> Balance {
unimplemented!();
}

/// How much should be locked up in order to be able to submit votes.
pub fn voting_bond() -> Balance {
unimplemented!();
}

/// How long to give each top candidate to present themselves after the vote ends.
pub fn presentation_duration() -> BlockNumber {
unimplemented!();
}

/// How many runners-up should have their approvals persist until the next vote.
pub fn carry_count() -> u32 {
unimplemented!();
}

/// The current council. When there's a vote going on, this should still be used for executive
/// matters.
pub fn active_council() -> Vec<AccountId> {
unimplemented!();
}

/// The information on the current vote:
/// - The block number where voting will end;
/// - The specific council members to be replaced.
pub fn current_vote() -> Option<(BlockNumber, Vec<AccountId>)> {
unimplemented!();
}

/// The total number of votes that have happened or are in progress.
pub fn vote_index() -> VoteIndex {
unimplemented!();
}

/// The queue of candidate indices that will be cleared.
pub fn candidate_clear_queue() -> {
unimplemented!();
}

/// The last cleared vote index that this voter was last active at.
pub fn voter_last_active(voter: &AddressId) -> VoteIndex {
unimplemented!();
}

pub mod public {
use super::*;

/// Remove a voter. For it not to panic, the combination of candidate_clear_queue from the
/// when it was last active until the penultimate vote should result in no approvals.
///
/// May be called by anyone. Returns the voter deposit to `signed`.
pub fn kill_inactive_voter(signed: &AccountId, who: &AddressId) {
unimplemented!();
}

/// Remove a voter. All votes are cancelled and the voter deposit is returned.
pub fn retract_voter(signed: AccountId) {
unimplemented!();
}

/// Submit oneself for candidacy.
///
/// Account must have enough cash in it to pay the bond.
pub fn submit_candidacy(signed: &AccountId) {
unimplemented!();
}

/// Claim that `signed` is one of the top carry_count() + current_vote().1 candidates.
/// Only works if the block number >= current_vote().0 and < current_vote().0 + presentation_duration()
pub fn present(signed: &AccountId) {
unimplemented!();
}
}

pub mod privileged {
use super::*;

/// Set the desired member count; if lower than the current count, then seats will not be up
/// election when they expire. If more, then a new vote will be started if one is not already
/// in progress.
pub fn set_desired_seats(count: u32) {
unimplemented!();
}

/// Remove a particular member. A new vote will be started if one is not already in progress.
/// This is effective immediately.
pub fn remove_member(who: AddressId) {
unimplemented!();
}
}

pub mod internal {
use super::*;
use demo_primitives::Proposal;
use dispatch::enact_proposal;

/// Current era is ending; we should finish up any proposals.
pub fn end_block() {
if let Some((number, removals)) = current_vote() {
if system::block_number() == number {
close_voting(removals.len() as u32);
}
if system::block_number() == number + presentation_duration() {
finalise_vote(removals);
}
}
}
}

/// Close the voting, snapshot the staking and the number of seats that are actually up for grabs.
fn close_voting(removal_count: u32) {
unimplemented!();
}

/// Finalise the vote, removing each of the `removals` and inserting `seats` of the most approved
/// candidates in their place. If the total council members is less than the desired membership
/// a new vote is started.
/// Clears all presented candidates, returning the bond of the elected ones.
fn finalise_vote(seats: u32, removals: Vec<AccountId>) {
unimplemented!();
}

#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::{KeyedVec, Joiner};
use keyring::Keyring;
use environment::with_env;
use demo_primitives::{AccountId, Proposal};
use runtime::{staking, session, democracy};

fn new_test_ext() -> TestExternalities {
let alice = Keyring::Alice.to_raw_public();
let bob = Keyring::Bob.to_raw_public();
let charlie = Keyring::Charlie.to_raw_public();
let dave = Keyring::Dave.to_raw_public();
let eve = Keyring::Eve.to_raw_public();
let ferdie = Keyring::Ferdie.to_raw_public();
let one = Keyring::One.to_raw_public();

map![
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should use constants for this rather than arcane string constants.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should add a helper in genesismap anyway

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess we can export the constants.

Copy link
Contributor

@rphmeier rphmeier Mar 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally would do something like #78 ; we are already manually writing getters. having a macro that automatically generates strongly-types getters and setters would be an improvement.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup.

twox_128(b"ses:len").to_vec() => vec![].and(&1u64),
twox_128(b"ses:val:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => alice.to_vec(),
twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => bob.to_vec(),
twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => charlie.to_vec(),
twox_128(b"sta:wil:len").to_vec() => vec![].and(&3u32),
twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => alice.to_vec(),
twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => bob.to_vec(),
twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => charlie.to_vec(),
twox_128(&alice.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&10u64),
twox_128(&bob.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&20u64),
twox_128(&charlie.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&30u64),
twox_128(&dave.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&40u64),
twox_128(&eve.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&50u64),
twox_128(&ferdie.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&60u64),
twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![].and(&1u64),
twox_128(b"sta:tot").to_vec() => vec![].and(&210u64),
twox_128(b"sta:spe").to_vec() => vec![].and(&1u64),
twox_128(b"sta:vac").to_vec() => vec![].and(&3u64),
twox_128(b"sta:era").to_vec() => vec![].and(&1u64)
]
}

#[test]
fn simple_passing_should_work() {
let alice = Keyring::Alice.to_raw_public();
let mut t = new_test_ext();

with_externalities(&mut t, || {
assert_eq!(staking::era_length(), 1u64);
assert_eq!(staking::total_stake(), 210u64);

with_env(|e| e.block_number = 1);
public::propose(&alice, &Proposal::StakingSetSessionsPerEra(2));
public::vote(&alice, 1, true);

assert_eq!(public::tally(), (10, 0));

democracy::internal::end_of_an_era();
staking::internal::check_new_era();

assert_eq!(staking::era_length(), 2u64);
});
}
}
6 changes: 3 additions & 3 deletions demo/runtime/src/runtime/democracy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use runtime_support::storage;
use demo_primitives::{Proposal, AccountId, Hash, BlockNumber};
use runtime::{staking, system, session};

const CURRENT_PROPOSAL: &[u8] = b"gov:pro";
const VOTE_OF: &[u8] = b"gov:vot:";
const VOTERS: &[u8] = b"gov:vtr:";
const CURRENT_PROPOSAL: &[u8] = b"dem:pro";
const VOTE_OF: &[u8] = b"dem:vot:";
const VOTERS: &[u8] = b"dem:vtr:";

pub mod public {
use super::*;
Expand Down