diff --git a/substrate/demo/primitives/src/transaction.rs b/substrate/demo/primitives/src/transaction.rs index 6f4feab790e4e5e7bde262052d77c6a57d7c124b..090b64b27d60203135464bfd3238d456c8fe9cec 100644 --- a/substrate/demo/primitives/src/transaction.rs +++ b/substrate/demo/primitives/src/transaction.rs @@ -44,10 +44,6 @@ enum InternalFunctionId { StakingSetValidatorCount = 0x22, /// Force a new staking era. StakingForceNewEra = 0x23, - - /// Set the per-mille of validator approval required for governance changes. - GovernanceSetApprovalPpmRequired = 0x30, - } impl InternalFunctionId { @@ -61,7 +57,6 @@ impl InternalFunctionId { InternalFunctionId::StakingSetBondingDuration, InternalFunctionId::StakingSetValidatorCount, InternalFunctionId::StakingForceNewEra, - InternalFunctionId::GovernanceSetApprovalPpmRequired, ]; functions.iter().map(|&f| f).find(|&f| value == f as u8) } @@ -85,9 +80,6 @@ pub enum Proposal { StakingSetValidatorCount(u32), /// Force a new staking era. StakingForceNewEra, - /// Set the per-mille of validator approval required for governance changes. - GovernanceSetApprovalPpmRequired(u32), - } impl Slicable for Proposal { @@ -106,8 +98,6 @@ impl Slicable for Proposal { InternalFunctionId::StakingSetValidatorCount => Proposal::StakingSetValidatorCount(try_opt!(Slicable::decode(input))), InternalFunctionId::StakingForceNewEra => Proposal::StakingForceNewEra, - InternalFunctionId::GovernanceSetApprovalPpmRequired => - Proposal::GovernanceSetApprovalPpmRequired(try_opt!(Slicable::decode(input))), }; Some(function) @@ -142,10 +132,6 @@ impl Slicable for Proposal { Proposal::StakingForceNewEra => { (InternalFunctionId::StakingForceNewEra as u8).using_encoded(|s| v.extend(s)); } - Proposal::GovernanceSetApprovalPpmRequired(ref data) => { - (InternalFunctionId::GovernanceSetApprovalPpmRequired as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } } v @@ -167,10 +153,6 @@ enum FunctionId { StakingUnstake = 0x21, /// Staking subsystem: transfer stake. StakingTransfer = 0x22, - /// Make a proposal for the governance system. - GovernancePropose = 0x30, - /// Approve a proposal for the governance system. - GovernanceApprove = 0x31, } impl FunctionId { @@ -179,7 +161,7 @@ impl FunctionId { use self::*; let functions = [FunctionId::StakingStake, FunctionId::StakingUnstake, FunctionId::StakingTransfer, FunctionId::SessionSetKey, FunctionId::TimestampSet, - FunctionId::GovernancePropose, FunctionId::GovernanceApprove]; + ]; functions.iter().map(|&f| f).find(|&f| value == f as u8) } } @@ -198,10 +180,6 @@ pub enum Function { StakingUnstake, /// Staking subsystem: transfer stake. StakingTransfer(::AccountId, u64), - /// Make a proposal for the governance system. - GovernancePropose(Proposal), - /// Approve a proposal for the governance system. - GovernanceApprove(BlockNumber), } impl Slicable for Function { @@ -220,10 +198,6 @@ impl Slicable for Function { Function::StakingTransfer(to, amount) } - FunctionId::GovernancePropose => - Function::GovernancePropose(try_opt!(Slicable::decode(input))), - FunctionId::GovernanceApprove => - Function::GovernanceApprove(try_opt!(Slicable::decode(input))), }) } @@ -249,14 +223,6 @@ impl Slicable for Function { to.using_encoded(|s| v.extend(s)); amount.using_encoded(|s| v.extend(s)); } - Function::GovernancePropose(ref data) => { - (FunctionId::GovernancePropose as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Function::GovernanceApprove(ref data) => { - (FunctionId::GovernanceApprove as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } } v diff --git a/substrate/demo/runtime/src/dispatch.rs b/substrate/demo/runtime/src/dispatch.rs index 6b03667ff909b030e28debb1e69774a7343c27d3..b473a6a8781541402c7ef3500d36264f0674f521 100644 --- a/substrate/demo/runtime/src/dispatch.rs +++ b/substrate/demo/runtime/src/dispatch.rs @@ -17,7 +17,7 @@ //! Democratic system: Handles administration of general stakeholder voting. use demo_primitives::Proposal; -use runtime::{staking, system, session, governance}; +use runtime::{staking, system, session}; pub fn enact_proposal(proposal: Proposal) { match proposal { @@ -42,8 +42,5 @@ pub fn enact_proposal(proposal: Proposal) { Proposal::StakingForceNewEra => { staking::privileged::force_new_era() } - Proposal::GovernanceSetApprovalPpmRequired(value) => { - governance::privileged::set_approval_ppm_required(value); - } } } diff --git a/substrate/demo/runtime/src/runtime/council_vote.rs b/substrate/demo/runtime/src/runtime/council_vote.rs new file mode 100644 index 0000000000000000000000000000000000000000..394316a66ea0b3e2df1d0e8bd89fb7451bc10985 --- /dev/null +++ b/substrate/demo/runtime/src/runtime/council_vote.rs @@ -0,0 +1,169 @@ +// 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 voting system. + +use rstd::prelude::*; +use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable}; +use runtime_support::Hashable; +use runtime_support::storage; +use demo_primitives::{Proposal, AccountId, Hash, BlockNumber}; +use runtime::{system, democracy, council}; +use runtime::staking::Balance; + +type ProposalHash = [u8; 32]; + +pub const COOLOFF_PERIOD: &[u8] = b"cov:cooloff"; // BlockNumber +pub const VOTING_PERIOD: &[u8] = b"cov:period"; // BlockNumber + +pub const PROPOSALS: &[u8] = b"cov:prs"; // Vec<(expiry: BlockNumber, ProposalHash)> ordered by expiry. +pub const PROPOSAL_OF: &[u8] = b"cov:pro"; // ProposalHash -> Proposal +pub const PROPOSAL_VOTERS: &[u8] = b"cov:voters:"; // ProposalHash -> Vec<AccountId> +pub const COUNCIL_VOTE_OF: &[u8] = b"cov:vote:"; // (ProposalHash, AccountId) -> bool +pub const VETOED_PROPOSAL: &[u8] = b"cov:veto:"; // ProposalHash -> (BlockNumber, Vec<AccountId>) + +pub fn cooloff_period() -> BlockNumber { + storage::get(COOLOFF_PERIOD).expect("all parameters must be defined") +} + +pub fn voting_period() -> BlockNumber { + storage::get(VOTING_PERIOD).expect("all parameters must be defined") +} + +pub fn proposals() -> Vec<(BlockNumber, ProposalHash)> { + storage::get_or_default(PROPOSALS) +} + +pub fn was_vetoed(proposal: &ProposalHash) -> bool { + storage::exists(&proposal.to_keyed_vec(VETOED_PROPOSAL)) +} + +pub fn will_still_be_councillor_at(who: &AccountId, n: BlockNumber) -> bool { + council::active_council().iter() + .find(|&&(ref a, _)| a == who) + .map(|&(_, expires)| expires > n) + .unwrap_or(false) +} + +pub fn vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> { + storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF)) +} + +pub fn take_vote_of(who: &AccountId, proposal: &ProposalHash) -> Option<bool> { + storage::get(&(*who, *proposal).to_keyed_vec(COUNCIL_VOTE_OF)) +} + +pub fn tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) { + generic_tally(proposal_hash, vote_of) +} + +fn take_tally(proposal_hash: &ProposalHash) -> (u32, u32, u32) { + generic_tally(proposal_hash, take_vote_of) +} + +fn generic_tally<F: Fn(&AccountId, &ProposalHash) -> Option<bool>>(proposal_hash: &ProposalHash, vote_of: F) -> (u32, u32, u32) { + let c = council::active_council(); + let (approve, reject) = c.iter() + .filter_map(|&(ref a, _)| vote_of(a, proposal_hash)) + .map(|approve| if approve { (1, 0) } else { (0, 1) }) + .fold((0, 0), |(a, b), (c, d)| (a + c, b + d)); + (approve, reject, c.len() as u32 - approve - reject) +} + +fn set_proposals(p: &Vec<(BlockNumber, ProposalHash)>) { + storage::put(PROPOSALS, p) +} + +fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHash)> { + let mut proposals = proposals(); + match proposals.first() { + Some(&(expiry, hash)) if expiry == n => { + // yes this is horrible, but fixing it will need substantial work in storage. + set_proposals(&proposals[1..].to_vec()); + let proposal = storage::take(&hash.to_keyed_vec(PROPOSAL_OF)).expect("all queued proposal hashes must have associated proposals"); + Some((proposal, hash)) + } + _ => None, + } +} + +pub mod public { + use super::*; + + pub fn propose(signed: &AccountId, proposal: &Proposal) { + let expiry = system::block_number() + voting_period(); + assert!(will_still_be_councillor_at(signed, expiry)); + + let proposal_hash = proposal.blake2_256(); + assert!(!was_vetoed(&proposal_hash)); + + let mut proposals = proposals(); + proposals.push((expiry, proposal_hash)); + proposals.sort_by_key(|&(expiry, _)| expiry); + set_proposals(&proposals); + + storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), proposal); + storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*signed]); + storage::put(&(proposal_hash, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &true); + } + + pub fn vote(signed: AccountId, proposal: &ProposalHash, approve: bool) { + + } + + pub fn veto(signed: AccountId, proposal: &ProposalHash) { + + } + + pub fn repropose(signed: AccountId, proposal: &Proposal) { + + } +} + +pub mod privileged { + use super::*; + + pub fn set_cooloff_period(blocks: BlockNumber) { + storage::put(COOLOFF_PERIOD, &blocks); + } + + pub fn set_voting_period(blocks: BlockNumber) { + storage::put(VOTING_PERIOD, &blocks); + } +} + +pub mod internal { + use super::*; + use runtime::democracy::VoteThreshold; + use runtime::democracy::privileged::start_referendum; + + pub fn end_block(now: BlockNumber) { + while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) { + let tally = take_tally(&proposal_hash); + let vote_threshold = match tally.0 { + x if x == tally.2 => VoteThreshold::SuperMajorityAgainst, + x if x > tally.2 / 2 => VoteThreshold::SimpleMajority, + _ => VoteThreshold::SuperMajorityApprove, + }; + start_referendum(proposal, vote_threshold); + } + } +} + +#[cfg(test)] +mod tests { + +} diff --git a/substrate/demo/runtime/src/runtime/democracy.rs b/substrate/demo/runtime/src/runtime/democracy.rs index 36965153498923cb257ffb245dcc1f9c0cc94e91..cbc82f458dfc4d7f8ade6d1befb6a624953c677d 100644 --- a/substrate/demo/runtime/src/runtime/democracy.rs +++ b/substrate/demo/runtime/src/runtime/democracy.rs @@ -76,11 +76,6 @@ pub const DEPOSIT_OF: &[u8] = b"dem:dep:"; // PropIndex -> (Balance, Vec<Accou pub const LAUNCH_PERIOD: &[u8] = b"dem:lau"; // BlockNumber pub const MINIMUM_DEPOSIT: &[u8] = b"dem:min"; // Balance -// council proposals -pub const COUNCIL_PROPOSAL: &[u8] = b"dem:cou:pro"; // (BlockNumber, Proposal) -pub const COUNCIL_VOTE_OF: &[u8] = b"dem:cou:vot:"; // AccountId -> CouncilVote -pub const COUNCIL_VOTERS: &[u8] = b"dem:cou:vts"; // Vec<AccountId> - // referenda pub const VOTING_PERIOD: &[u8] = b"dem:per"; // BlockNumber pub const REFERENDUM_COUNT: &[u8] = b"dem:rco"; // ReferendumIndex diff --git a/substrate/demo/runtime/src/runtime/governance.rs b/substrate/demo/runtime/src/runtime/governance.rs deleted file mode 100644 index 4689941de4c40a5bf005c2f8196371cdc980fa14..0000000000000000000000000000000000000000 --- a/substrate/demo/runtime/src/runtime/governance.rs +++ /dev/null @@ -1,339 +0,0 @@ -// 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/>. - -//! Governance system: Handles administration and dispatch of sensitive operations including -//! setting new code, minting new tokens and changing parameters. -//! -//! For now this is limited to a simple qualified majority vote (whose parameter is retrieved from -//! storage) between validators. A single vote may be proposed per era, and at most one approval -//! vote may be cast by each validator. The tally is maintained through a simple tag in storage for -//! each validator that has approved. -//! -//! At the end of the era, all validators approvals are tallied and if there are sufficient to pass -//! the proposal then it is enacted. All items in storage concerning the proposal are reset. - -use rstd::prelude::*; -use codec::KeyedVec; -use runtime_support::storage; -use demo_primitives::{Proposal, AccountId, Hash, BlockNumber}; -use runtime::{staking, system, session}; -use dispatch::enact_proposal; - -pub const APPROVALS_REQUIRED: &[u8] = b"gov:apr"; -pub const CURRENT_PROPOSAL: &[u8] = b"gov:pro"; -pub const APPROVAL_OF: &[u8] = b"gov:app:"; - -/// The proportion of validators required for a propsal to be approved measured as the number out -/// of 1000. -pub fn approval_ppm_required() -> u32 { - storage::get_or(APPROVALS_REQUIRED, 1000) -} - -/// The number of concrete validator approvals required for a proposal to pass. -pub fn approvals_required() -> u32 { - approval_ppm_required() * session::validator_count() / 1000 -} - -pub mod public { - use super::*; - - /// Propose a sensitive action to be taken. Any action that is enactable by `Proposal` is valid. - /// Proposal is by the `transactor` and will automatically count as an approval. Transactor must - /// be a current validator. It is illegal to propose when there is already a proposal in effect. - pub fn propose(validator: &AccountId, proposal: &Proposal) { - if storage::exists(CURRENT_PROPOSAL) { - panic!("there may only be one proposal per era."); - } - storage::put(CURRENT_PROPOSAL, proposal); - approve(validator, staking::current_era()); - } - - /// Approve the current era's proposal. Transactor must be a validator. This may not be done more - /// than once for any validator in an era. - pub fn approve(validator: &AccountId, era_index: BlockNumber) { - if era_index != staking::current_era() { - panic!("approval vote applied on non-current era.") - } - if !storage::exists(CURRENT_PROPOSAL) { - panic!("there must be a proposal in order to approve."); - } - if session::validators().into_iter().position(|v| &v == validator).is_none() { - panic!("transactor must be a validator to approve."); - } - let key = validator.to_keyed_vec(APPROVAL_OF); - if storage::exists(&key) { - panic!("transactor may not approve a proposal twice in one era."); - } - storage::put(&key, &true); - } -} - -pub mod privileged { - use super::*; - - /// Set the proportion of validators that must approve for a proposal to be enacted at the end of - /// its era. The value, `ppm`, is measured as a fraction of 1000 rounded down to the nearest whole - /// validator. `1000` would require the approval of all validators; `667` would require two-thirds - /// (or there abouts) of validators. - pub fn set_approval_ppm_required(ppm: u32) { - storage::put(APPROVALS_REQUIRED, &ppm); - } -} - -pub mod internal { - use super::*; - use demo_primitives::Proposal; - - /// Current era is ending; we should finish up any proposals. - pub fn end_of_an_era() { - // tally up votes for the current proposal, if any. enact if there are sufficient approvals. - if let Some(proposal) = storage::take::<Proposal>(CURRENT_PROPOSAL) { - let approvals_required = approvals_required(); - let approved = session::validators().into_iter() - .filter_map(|v| storage::take::<bool>(&v.to_keyed_vec(APPROVAL_OF))) - .take(approvals_required as usize) - .count() as u32; - if approved == approvals_required { - enact_proposal(proposal); - } - } - } -} - -#[cfg(test)] -pub mod testing { - use super::*; - use runtime_io::{twox_128, TestExternalities}; - use codec::Joiner; - - pub fn externalities(session_length: u64, sessions_per_era: u64, current_era: u64) -> TestExternalities { - let extras: TestExternalities = map![ - twox_128(APPROVALS_REQUIRED).to_vec() => vec![].and(&667u32) - ]; - staking::testing::externalities(session_length, sessions_per_era, current_era) - .into_iter().chain(extras.into_iter()).collect() - } -} - -#[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}; - - fn new_test_ext() -> TestExternalities { - testing::externalities(1, 1, 1) - } - - #[test] - fn majority_voting_should_work() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Approve it. Era length changes. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::approve(&two, 1); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 2); - }); - } - - #[test] - fn majority_voting_should_work_after_unsuccessful_previous() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Fail it. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - - // Block 2: Make proposal. Approve it. It should change era length. - with_env(|e| e.block_number = 2); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::approve(&two, 2); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 2); - }); - } - - #[test] - fn minority_voting_should_not_succeed() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } - - #[test] - #[should_panic] - fn old_voting_should_be_illegal() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::approve(&two, 0); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } - - #[test] - #[should_panic] - fn double_voting_should_be_illegal() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::approve(&two, 1); - public::approve(&two, 1); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } - - #[test] - #[should_panic] - fn over_proposing_should_be_illegal() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::propose(&two, &Proposal::StakingSetSessionsPerEra(2)); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } - - #[test] - #[should_panic] - fn approving_without_proposal_should_be_illegal() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::approve(&two, 1); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } - - #[test] - #[should_panic] - fn non_validator_approving_should_be_illegal() { - let one = Keyring::One.to_raw_public(); - let two = Keyring::Two.to_raw_public(); - let three = [3u8; 32]; - let four = [4u8; 32]; - let mut t = new_test_ext(); - - with_externalities(&mut t, || { - assert_eq!(staking::era_length(), 1u64); - assert_eq!(staking::current_era(), 1u64); - assert_eq!(session::validator_count(), 3u32); - assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]); - assert!(!session::validators().into_iter().position(|v| &v == &one).is_none()); - - // Block 1: Make proposal. Will have only 1 vote. No change. - with_env(|e| e.block_number = 1); - public::propose(&one, &Proposal::StakingSetSessionsPerEra(2)); - public::approve(&four, 1); - staking::internal::check_new_era(); - assert_eq!(staking::era_length(), 1); - }); - } -} diff --git a/substrate/demo/runtime/src/runtime/mod.rs b/substrate/demo/runtime/src/runtime/mod.rs index 092b4eca2386cfc1b78aafdb6a939df399ccc3b1..e52e49c8aa13bd7c4e9697ed7244f9309760cbf6 100644 --- a/substrate/demo/runtime/src/runtime/mod.rs +++ b/substrate/demo/runtime/src/runtime/mod.rs @@ -27,11 +27,8 @@ pub mod timestamp; #[allow(unused)] pub mod session; #[allow(unused)] -pub mod governance; -#[allow(unused)] pub mod democracy; #[allow(unused)] pub mod council; - - -// TODO: polkadao +#[allow(unused)] +pub mod council_vote; diff --git a/substrate/demo/runtime/src/runtime/staking.rs b/substrate/demo/runtime/src/runtime/staking.rs index 6d357a52dac05ea697c5f9285ecdf15eef45d288..29b6ab793b296febd103aacb4d9620cf28fdb898 100644 --- a/substrate/demo/runtime/src/runtime/staking.rs +++ b/substrate/demo/runtime/src/runtime/staking.rs @@ -23,7 +23,7 @@ use runtime_io::{print, blake2_256}; use codec::KeyedVec; use runtime_support::{storage, StorageVec}; use demo_primitives::{BlockNumber, AccountId}; -use runtime::{system, session, governance}; +use runtime::{system, session}; /// The balance of an account. pub type Balance = u64; @@ -406,9 +406,6 @@ pub mod internal { /// NOTE: This always happens immediately before a session change to ensure that new validators /// get a chance to set their session keys. fn new_era() { - // Inform governance module that it's the end of an era - governance::internal::end_of_an_era(); - // Increment current era. storage::put(CURRENT_ERA, &(current_era() + 1)); diff --git a/substrate/demo/runtime/src/runtime/system.rs b/substrate/demo/runtime/src/runtime/system.rs index 009dac823902d57e6c15f18be732eeea74c8a29e..765e29e01ec5bb2facb5f3adf3f86abc7edef75c 100644 --- a/substrate/demo/runtime/src/runtime/system.rs +++ b/substrate/demo/runtime/src/runtime/system.rs @@ -144,12 +144,6 @@ pub mod internal { Function::TimestampSet(t) => { ::runtime::timestamp::public::set(t); } - Function::GovernancePropose(ref proposal) => { - ::runtime::governance::public::propose(transactor, proposal); - } - Function::GovernanceApprove(era_index) => { - ::runtime::governance::public::approve(transactor, era_index); - } } } } @@ -253,7 +247,7 @@ mod tests { use environment::with_env; use primitives::hexdisplay::HexDisplay; use demo_primitives::{Header, Digest, UncheckedTransaction, Transaction, Function}; - use runtime::{governance, staking}; + use runtime::staking; #[test] fn staking_balance_transfer_dispatch_works() { @@ -281,7 +275,7 @@ mod tests { } fn new_test_ext() -> TestExternalities { - governance::testing::externalities(2, 2, 0) + staking::testing::externalities(2, 2, 0) } #[test] @@ -294,7 +288,7 @@ mod tests { let h = Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("1ab2dbb7d4868a670b181327b0b6a58dc64b10cfb9876f737a5aa014b8da31e0").into(), + state_root: hex!("52eb24906a4110a605d29d4e2f01b43cb169d375d709b138cc8ce50ad5f7ce85").into(), transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), digest: Digest { logs: vec![], }, }; diff --git a/substrate/substrate/codec/src/slicable.rs b/substrate/substrate/codec/src/slicable.rs index 0304b51003765d70956b17b323b61d692e086b78..eb2b01db52fc841fb12febfdaf9957c0d67fa96d 100644 --- a/substrate/substrate/codec/src/slicable.rs +++ b/substrate/substrate/codec/src/slicable.rs @@ -89,6 +89,26 @@ impl<T: EndianSensitive> Slicable for T { } } +impl Slicable for Option<bool> { + fn decode<I: Input>(input: &mut I) -> Option<Self> { + u8::decode(input).and_then(|v| match v { + 0 => Some(Some(false)), + 1 => Some(Some(true)), + 2 => Some(None), + _ => None, + }) + } + + fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { + match *self { + Some(false) => 0u8, + Some(true) => 1u8, + None => 2u8, + }.using_encoded(f) + } +} +impl NonTrivialSlicable for Option<bool> {} + impl Slicable for Vec<u8> { fn decode<I: Input>(input: &mut I) -> Option<Self> { u32::decode(input).and_then(move |len| {