Initial council vote logic.

This commit is contained in:
Gav
2018-03-04 21:52:11 +01:00
parent f056dea47e
commit 8d84ca8b48
9 changed files with 197 additions and 401 deletions
+1 -35
View File
@@ -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
+1 -4
View File
@@ -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);
}
}
}
@@ -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 {
}
@@ -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
@@ -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);
});
}
}
+2 -5
View File
@@ -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;
@@ -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));
+3 -9
View File
@@ -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![], },
};
+20
View File
@@ -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| {