From a83059a95b61ad60e2e7204df51b35009463740c Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 13 Mar 2018 12:34:21 +0100 Subject: [PATCH 01/13] Completely rework dispatch mechanism into something modular. Not yet complete but 75% there. --- Cargo.lock | 2 + demo/primitives/src/block.rs | 33 -- demo/primitives/src/lib.rs | 4 +- demo/primitives/src/transaction.rs | 494 --------------------- demo/runtime/Cargo.toml | 4 + demo/runtime/src/block.rs | 53 +++ demo/runtime/src/dispatch.rs | 295 +++++++++---- demo/runtime/src/lib.rs | 47 +- demo/runtime/src/runtime/council.rs | 518 ++++++++++++----------- demo/runtime/src/runtime/council_vote.rs | 81 ++-- demo/runtime/src/runtime/democracy.rs | 206 ++++++--- demo/runtime/src/runtime/staking.rs | 236 +++++++---- demo/runtime/src/runtime/system.rs | 32 +- demo/runtime/src/runtime/timestamp.rs | 14 +- demo/runtime/src/transaction.rs | 190 +++++++++ substrate/codec/src/slicable.rs | 148 +++++-- 16 files changed, 1222 insertions(+), 1135 deletions(-) delete mode 100644 demo/primitives/src/transaction.rs create mode 100644 demo/runtime/src/block.rs create mode 100644 demo/runtime/src/transaction.rs diff --git a/Cargo.lock b/Cargo.lock index e29aa3a664c20..6307440de042b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -244,6 +244,8 @@ dependencies = [ "integer-sqrt 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", diff --git a/demo/primitives/src/block.rs b/demo/primitives/src/block.rs index 4183498fc7413..f5119ac4b3f22 100644 --- a/demo/primitives/src/block.rs +++ b/demo/primitives/src/block.rs @@ -21,7 +21,6 @@ use primitives::bytes; use primitives::H256; use rstd::vec::Vec; use codec::{Input, Slicable}; -use transaction::UncheckedTransaction; pub use primitives::block::Id; @@ -31,9 +30,6 @@ pub type Number = u64; /// Hash used to refer to a block hash. pub type HeaderHash = H256; -/// Hash used to refer to a transaction hash. -pub type TransactionHash = H256; - /// Execution log (event) #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] @@ -69,35 +65,6 @@ impl Slicable for Digest { } } -/// The block "body": A bunch of transactions. -pub type Body = Vec; - -/// A block on the chain. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -pub struct Block { - /// The block header. - pub header: Header, - /// All relay-chain transactions. - pub transactions: Body, -} - -impl Slicable for Block { - fn decode(input: &mut I) -> Option { - let (header, transactions) = try_opt!(Slicable::decode(input)); - Some(Block { header, transactions }) - } - - fn encode(&self) -> Vec { - let mut v = Vec::new(); - - v.extend(self.header.encode()); - v.extend(self.transactions.encode()); - - v - } -} - /// Header for a block. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] diff --git a/demo/primitives/src/lib.rs b/demo/primitives/src/lib.rs index e68d6d8727208..c65d4a63ef700 100644 --- a/demo/primitives/src/lib.rs +++ b/demo/primitives/src/lib.rs @@ -45,11 +45,9 @@ macro_rules! try_opt { } pub mod block; -pub mod transaction; -pub use self::block::{Header, Block, Log, Digest}; +pub use self::block::{Header, Log, Digest}; pub use self::block::Number as BlockNumber; -pub use self::transaction::{Transaction, UncheckedTransaction, Function, Proposal, VoteThreshold}; /// Alias to Ed25519 pubkey that identifies an account on the relay chain. This will almost /// certainly continue to be the same as the substrate's `AuthorityId`. diff --git a/demo/primitives/src/transaction.rs b/demo/primitives/src/transaction.rs deleted file mode 100644 index cc7e410a72c44..0000000000000 --- a/demo/primitives/src/transaction.rs +++ /dev/null @@ -1,494 +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 . - -//! Transaction type. - -use rstd::vec::Vec; -use codec::{Input, Slicable, NonTrivialSlicable}; -use {AccountId, SessionKey}; - -#[cfg(feature = "std")] -use std::fmt; - -use block::Number as BlockNumber; - -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[repr(u8)] -enum InternalFunctionId { - SystemSetCode = 0x00, - - SessionSetLength = 0x10, - SessionForceNewSession = 0x11, - - StakingSetSessionsPerEra = 0x20, - StakingSetBondingDuration = 0x21, - StakingSetValidatorCount = 0x22, - StakingForceNewEra = 0x23, - - DemocracyCancelReferendum = 0x30, - DemocracyStartReferendum = 0x31, - - CouncilSetDesiredSeats = 0x40, - CouncilRemoveMember = 0x41, - CouncilSetPresentationDuration = 0x42, - CouncilSetTermDuration = 0x43, - - CouncilVoteSetCooloffPeriod = 0x50, - CouncilVoteSetVotingPeriod = 0x51, -} - -impl InternalFunctionId { - /// Derive `Some` value from a `u8`, or `None` if it's invalid. - fn from_u8(value: u8) -> Option { - let functions = [ - InternalFunctionId::SystemSetCode, - InternalFunctionId::SessionSetLength, - InternalFunctionId::SessionForceNewSession, - InternalFunctionId::StakingSetSessionsPerEra, - InternalFunctionId::StakingSetBondingDuration, - InternalFunctionId::StakingSetValidatorCount, - InternalFunctionId::StakingForceNewEra, - InternalFunctionId::DemocracyCancelReferendum, - InternalFunctionId::DemocracyStartReferendum, - InternalFunctionId::CouncilSetDesiredSeats, - InternalFunctionId::CouncilRemoveMember, - InternalFunctionId::CouncilSetPresentationDuration, - InternalFunctionId::CouncilSetTermDuration, - InternalFunctionId::CouncilVoteSetCooloffPeriod, - InternalFunctionId::CouncilVoteSetVotingPeriod, - ]; - functions.iter().map(|&f| f).find(|&f| value == f as u8) - } -} - -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -pub enum VoteThreshold { - /// A supermajority of approvals is needed to pass this vote. - SuperMajorityApprove, - /// A supermajority of rejects is needed to fail this vote. - SuperMajorityAgainst, - /// A simple majority of approvals is needed to pass this vote. - SimpleMajority, -} - -impl Slicable for VoteThreshold { - fn decode(input: &mut I) -> Option { - u8::decode(input).and_then(|v| match v { - 0 => Some(VoteThreshold::SuperMajorityApprove), - 1 => Some(VoteThreshold::SuperMajorityAgainst), - 2 => Some(VoteThreshold::SimpleMajority), - _ => None, - }) - } - - fn using_encoded R>(&self, f: F) -> R { - match *self { - VoteThreshold::SuperMajorityApprove => 0u8, - VoteThreshold::SuperMajorityAgainst => 1u8, - VoteThreshold::SimpleMajority => 2u8, - }.using_encoded(f) - } -} -impl NonTrivialSlicable for VoteThreshold {} - -/// Internal functions that can be dispatched to. -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[allow(missing_docs)] -pub enum Proposal { - SystemSetCode(Vec), - SessionSetLength(BlockNumber), - SessionForceNewSession, - StakingSetSessionsPerEra(BlockNumber), - StakingSetBondingDuration(BlockNumber), - StakingSetValidatorCount(u32), - StakingForceNewEra, - DemocracyStartReferendum(Box, VoteThreshold), - DemocracyCancelReferendum(u32), - CouncilSetDesiredSeats(u32), - CouncilRemoveMember(AccountId), - CouncilSetPresentationDuration(BlockNumber), - CouncilSetTermDuration(BlockNumber), - CouncilVoteSetCooloffPeriod(BlockNumber), - CouncilVoteSetVotingPeriod(BlockNumber), -} - -impl Slicable for Proposal { - fn decode(input: &mut I) -> Option { - let id = u8::decode(input).and_then(InternalFunctionId::from_u8)?; - let function = match id { - InternalFunctionId::SystemSetCode => - Proposal::SystemSetCode(Slicable::decode(input)?), - InternalFunctionId::SessionSetLength => - Proposal::SessionSetLength(Slicable::decode(input)?), - InternalFunctionId::SessionForceNewSession => - Proposal::SessionForceNewSession, - InternalFunctionId::StakingSetSessionsPerEra => - Proposal::StakingSetSessionsPerEra(Slicable::decode(input)?), - InternalFunctionId::StakingSetBondingDuration => - Proposal::StakingSetBondingDuration(Slicable::decode(input)?), - InternalFunctionId::StakingSetValidatorCount => - Proposal::StakingSetValidatorCount(Slicable::decode(input)?), - InternalFunctionId::StakingForceNewEra => - Proposal::StakingForceNewEra, - InternalFunctionId::DemocracyStartReferendum => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - Proposal::DemocracyStartReferendum(Box::new(a), b) - } - InternalFunctionId::DemocracyCancelReferendum => - Proposal::DemocracyCancelReferendum(Slicable::decode(input)?), - InternalFunctionId::CouncilSetDesiredSeats => - Proposal::CouncilSetDesiredSeats(Slicable::decode(input)?), - InternalFunctionId::CouncilRemoveMember => - Proposal::CouncilRemoveMember(Slicable::decode(input)?), - InternalFunctionId::CouncilSetPresentationDuration => - Proposal::CouncilSetPresentationDuration(Slicable::decode(input)?), - InternalFunctionId::CouncilSetTermDuration => - Proposal::CouncilSetTermDuration(Slicable::decode(input)?), - InternalFunctionId::CouncilVoteSetCooloffPeriod => - Proposal::CouncilVoteSetCooloffPeriod(Slicable::decode(input)?), - InternalFunctionId::CouncilVoteSetVotingPeriod => - Proposal::CouncilVoteSetVotingPeriod(Slicable::decode(input)?), - }; - - Some(function) - } - - fn encode(&self) -> Vec { - let mut v = Vec::new(); - match *self { - Proposal::SystemSetCode(ref data) => { - (InternalFunctionId::SystemSetCode as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Proposal::SessionSetLength(ref data) => { - (InternalFunctionId::SessionSetLength as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Proposal::SessionForceNewSession => { - (InternalFunctionId::SessionForceNewSession as u8).using_encoded(|s| v.extend(s)); - } - Proposal::StakingSetSessionsPerEra(ref data) => { - (InternalFunctionId::StakingSetSessionsPerEra as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Proposal::StakingSetBondingDuration(ref data) => { - (InternalFunctionId::StakingSetBondingDuration as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Proposal::StakingSetValidatorCount(ref data) => { - (InternalFunctionId::StakingSetValidatorCount as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Proposal::StakingForceNewEra => { - (InternalFunctionId::StakingForceNewEra as u8).using_encoded(|s| v.extend(s)); - } - Proposal::DemocracyCancelReferendum(ref data) => { - (InternalFunctionId::DemocracyCancelReferendum as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - _ => { unimplemented!() } - } - - v - } -} - -/// Public functions that can be dispatched to. -#[derive(Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[repr(u8)] -enum FunctionId { - TimestampSet = 0x00, - - SessionSetKey = 0x10, - - StakingStake = 0x20, - StakingUnstake = 0x21, - StakingTransfer = 0x22, - - CouncilVotePropose = 0x30, - CouncilVoteVote = 0x31, - CouncilVoteVeto = 0x32, - - CouncilSetApprovals = 0x40, - CouncilReapInactiveVoter = 0x41, - CouncilRetractVoter = 0x42, - CouncilSubmitCandidacy = 0x43, - CouncilPresentWinner = 0x44, - - DemocracyPropose = 0x50, - DemocracySecond = 0x51, - DemocracyVote = 0x52, -} - -impl FunctionId { - /// Derive `Some` value from a `u8`, or `None` if it's invalid. - fn from_u8(value: u8) -> Option { - use self::*; - let functions = [FunctionId::StakingStake, FunctionId::StakingUnstake, - FunctionId::StakingTransfer, FunctionId::SessionSetKey, FunctionId::TimestampSet, - FunctionId::CouncilVotePropose, FunctionId::CouncilVoteVote, FunctionId::CouncilVoteVeto, - FunctionId::CouncilSetApprovals, FunctionId::CouncilReapInactiveVoter, - FunctionId::CouncilRetractVoter, FunctionId::CouncilSubmitCandidacy, - FunctionId::CouncilPresentWinner, FunctionId::DemocracyPropose, - FunctionId::DemocracySecond, FunctionId::DemocracyVote, - ]; - functions.iter().map(|&f| f).find(|&f| value == f as u8) - } -} - -/// Functions on the runtime. -#[derive(Clone, PartialEq, Eq)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[allow(missing_docs)] -pub enum Function { - TimestampSet(u64), - - SessionSetKey(SessionKey), - - StakingStake, - StakingUnstake, - StakingTransfer(AccountId, u64), - - CouncilVotePropose(Proposal), - CouncilVoteVote([u8; 32], bool), - CouncilVoteVeto([u8; 32]), - - CouncilSetApprovals(Vec, u32), - CouncilReapInactiveVoter(u32, AccountId, u32, u32), - CouncilRetractVoter(u32), - CouncilSubmitCandidacy(u32), - CouncilPresentWinner(AccountId, u64, u32), - - DemocracyPropose(Proposal, u64), - DemocracySecond(u32), - DemocracyVote(u32, bool), -} - -impl Slicable for Function { - fn decode(input: &mut I) -> Option { - let id = u8::decode(input).and_then(FunctionId::from_u8)?; - Some(match id { - FunctionId::TimestampSet => - Function::TimestampSet(Slicable::decode(input)?), - FunctionId::SessionSetKey => - Function::SessionSetKey(Slicable::decode(input)?), - FunctionId::StakingStake => Function::StakingStake, - FunctionId::StakingUnstake => Function::StakingUnstake, - FunctionId::StakingTransfer => { - let to = Slicable::decode(input)?; - let amount = Slicable::decode(input)?; - Function::StakingTransfer(to, amount) - } - FunctionId::CouncilVotePropose => Function::CouncilVotePropose(Slicable::decode(input)?), - FunctionId::CouncilVoteVote => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - Function::CouncilVoteVote(a, b) - } - FunctionId::CouncilVoteVeto => Function::CouncilVoteVeto(Slicable::decode(input)?), - FunctionId::CouncilSetApprovals => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - Function::CouncilSetApprovals(a, b) - } - FunctionId::CouncilReapInactiveVoter => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - let c = Slicable::decode(input)?; - let d = Slicable::decode(input)?; - Function::CouncilReapInactiveVoter(a, b, c, d) - } - FunctionId::CouncilRetractVoter => Function::CouncilRetractVoter(Slicable::decode(input)?), - FunctionId::CouncilSubmitCandidacy => Function::CouncilSubmitCandidacy(Slicable::decode(input)?), - FunctionId::CouncilPresentWinner => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - let c = Slicable::decode(input)?; - Function::CouncilPresentWinner(a, b, c) - } - FunctionId::DemocracyPropose => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - Function::DemocracyPropose(a, b) - } - FunctionId::DemocracySecond => Function::DemocracySecond(Slicable::decode(input)?), - FunctionId::DemocracyVote => { - let a = Slicable::decode(input)?; - let b = Slicable::decode(input)?; - Function::DemocracyVote(a, b) - } - }) - } - - fn encode(&self) -> Vec { - let mut v = Vec::new(); - match *self { - Function::TimestampSet(ref data) => { - (FunctionId::TimestampSet as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Function::SessionSetKey(ref data) => { - (FunctionId::SessionSetKey as u8).using_encoded(|s| v.extend(s)); - data.using_encoded(|s| v.extend(s)); - } - Function::StakingStake => { - (FunctionId::StakingStake as u8).using_encoded(|s| v.extend(s)); - } - Function::StakingUnstake => { - (FunctionId::StakingUnstake as u8).using_encoded(|s| v.extend(s)); - } - Function::StakingTransfer(ref to, ref amount) => { - (FunctionId::StakingTransfer as u8).using_encoded(|s| v.extend(s)); - to.using_encoded(|s| v.extend(s)); - amount.using_encoded(|s| v.extend(s)); - } - _ => { unimplemented!() } - } - - v - } - - fn using_encoded R>(&self, f: F) -> R { - f(self.encode().as_slice()) - } -} - -/// A vetted and verified transaction from the external world. -#[derive(PartialEq, Eq, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -pub struct Transaction { - /// Who signed it (note this is not a signature). - pub signed: super::AccountId, - /// The number of transactions have come before from the same signer. - pub nonce: super::TxOrder, - /// The function that should be called. - pub function: Function, -} - -impl Slicable for Transaction { - fn decode(input: &mut I) -> Option { - Some(Transaction { - signed: try_opt!(Slicable::decode(input)), - nonce: try_opt!(Slicable::decode(input)), - function: try_opt!(Slicable::decode(input)), - }) - } - - fn encode(&self) -> Vec { - let mut v = Vec::new(); - - self.signed.using_encoded(|s| v.extend(s)); - self.nonce.using_encoded(|s| v.extend(s)); - self.function.using_encoded(|s| v.extend(s)); - - v - } -} - -impl ::codec::NonTrivialSlicable for Transaction {} - -/// A transactions right from the external world. Unchecked. -#[derive(Eq, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct UncheckedTransaction { - /// The actual transaction information. - pub transaction: Transaction, - /// The signature; should be an Ed25519 signature applied to the serialised `transaction` field. - pub signature: super::Signature, -} - -impl Slicable for UncheckedTransaction { - fn decode(input: &mut I) -> Option { - // This is a little more complicated than usual since the binary format must be compatible - // with substrate's generic `Vec` type. Basically this just means accepting that there - // will be a prefix of u32, which has the total number of bytes following (we don't need - // to use this). - let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::decode(input)); - - Some(UncheckedTransaction { - transaction: try_opt!(Slicable::decode(input)), - signature: try_opt!(Slicable::decode(input)), - }) - } - - fn encode(&self) -> Vec { - let mut v = Vec::new(); - - // need to prefix with the total length as u32 to ensure it's binary comptible with - // Vec. we'll make room for it here, then overwrite once we know the length. - v.extend(&[0u8; 4]); - - self.transaction.signed.using_encoded(|s| v.extend(s)); - self.transaction.nonce.using_encoded(|s| v.extend(s)); - self.transaction.function.using_encoded(|s| v.extend(s)); - self.signature.using_encoded(|s| v.extend(s)); - - let length = (v.len() - 4) as u32; - length.using_encoded(|s| v[0..4].copy_from_slice(s)); - - v - } -} - -impl ::codec::NonTrivialSlicable for UncheckedTransaction {} - -impl PartialEq for UncheckedTransaction { - fn eq(&self, other: &Self) -> bool { - self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction - } -} - -#[cfg(feature = "std")] -impl fmt::Debug for UncheckedTransaction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "UncheckedTransaction({:?})", self.transaction) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use primitives; - use ::codec::Slicable; - use primitives::hexdisplay::HexDisplay; - - #[test] - fn serialize_unchecked() { - let tx = UncheckedTransaction { - transaction: Transaction { - signed: [1; 32], - nonce: 999u64, - function: Function::TimestampSet(135135), - }, - signature: primitives::hash::H512([0; 64]), - }; - // 71000000 - // 0101010101010101010101010101010101010101010101010101010101010101 - // e703000000000000 - // 00 - // df0f0200 - // 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - - let v = Slicable::encode(&tx); - println!("{}", HexDisplay::from(&v)); - assert_eq!(UncheckedTransaction::decode(&mut &v[..]).unwrap(), tx); - } -} diff --git a/demo/runtime/Cargo.toml b/demo/runtime/Cargo.toml index bcd3f5dcf00ba..4033111d7d093 100644 --- a/demo/runtime/Cargo.toml +++ b/demo/runtime/Cargo.toml @@ -7,6 +7,8 @@ authors = ["Parity Technologies "] rustc-hex = "1.0" hex-literal = "0.1.0" log = { version = "0.3", optional = true } +serde = { version = "1.0", default_features = false } +serde_derive = { version = "1.0", optional = true } substrate-codec = { path = "../../substrate/codec" } substrate-runtime-std = { path = "../../substrate/runtime-std" } substrate-runtime-io = { path = "../../substrate/runtime-io" } @@ -25,5 +27,7 @@ std = [ "substrate-runtime-support/std", "substrate-primitives/std", "demo-primitives/std", + "serde_derive", + "serde/std", "log" ] diff --git a/demo/runtime/src/block.rs b/demo/runtime/src/block.rs new file mode 100644 index 0000000000000..6e905f88037ab --- /dev/null +++ b/demo/runtime/src/block.rs @@ -0,0 +1,53 @@ +// 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 . + +//! Block and header type definitions. + +#[cfg(feature = "std")] +use rstd::vec::Vec; +use codec::{Input, Slicable}; +use transaction::UncheckedTransaction; + +pub use demo_primitives::block::{Header, Digest, Log, Number, HeaderHash}; + +/// The block "body": A bunch of transactions. +pub type Body = Vec; + +/// A block on the chain. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub struct Block { + /// The block header. + pub header: Header, + /// All relay-chain transactions. + pub transactions: Body, +} + +impl Slicable for Block { + fn decode(input: &mut I) -> Option { + let (header, transactions) = try_opt!(Slicable::decode(input)); + Some(Block { header, transactions }) + } + + fn encode(&self) -> Vec { + let mut v = Vec::new(); + + v.extend(self.header.encode()); + v.extend(self.transactions.encode()); + + v + } +} diff --git a/demo/runtime/src/dispatch.rs b/demo/runtime/src/dispatch.rs index 9a9aded039fb1..93be322e520f4 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -16,81 +16,230 @@ //! Dispatch system. Just dispatches calls. -use demo_primitives::{Function, Proposal, AccountId}; -use runtime::{staking, system, session, democracy, council, council_vote, timestamp}; - -/// Dispatch a proposal. -pub fn proposal(proposal: Proposal) { - match proposal { - Proposal::SystemSetCode(ref a) => - system::privileged::set_code(a), - Proposal::SessionSetLength(a) => - session::privileged::set_length(a), - Proposal::SessionForceNewSession => - session::privileged::force_new_session(), - Proposal::StakingSetSessionsPerEra(a) => - staking::privileged::set_sessions_per_era(a), - Proposal::StakingSetBondingDuration(a) => - staking::privileged::set_bonding_duration(a), - Proposal::StakingSetValidatorCount(a) => - staking::privileged::set_validator_count(a), - Proposal::StakingForceNewEra => - staking::privileged::force_new_era(), - Proposal::DemocracyCancelReferendum(a) => - democracy::privileged::cancel_referendum(a), - Proposal::DemocracyStartReferendum(a, b) => - democracy::privileged::start_referendum(*a, b), - Proposal::DemocracyCancelReferendum(a) => - democracy::privileged::cancel_referendum(a), - Proposal::CouncilSetDesiredSeats(a) => - council::privileged::set_desired_seats(a), - Proposal::CouncilRemoveMember(a) => - council::privileged::remove_member(&a), - Proposal::CouncilSetPresentationDuration(a) => - council::privileged::set_presentation_duration(a), - Proposal::CouncilSetTermDuration(a) => - council::privileged::set_term_duration(a), - Proposal::CouncilVoteSetCooloffPeriod(a) => - council_vote::privileged::set_cooloff_period(a), - Proposal::CouncilVoteSetVotingPeriod(a) => - council_vote::privileged::set_voting_period(a), +use demo_primitives::AccountId; +use runtime::{staking, system, session, democracy, council, council_vote}; +use runtime::staking::public::Dispatch as staking_d; +use runtime::staking::privileged::Dispatch as staking_pd; +use runtime::timestamp::public::Dispatch as timestamp_d; + +pub use rstd::prelude::Vec; +pub use codec::{Slicable, Input, NonTrivialSlicable}; + +#[macro_export] +macro_rules! impl_dispatch { + ( + pub mod $mod_name:ident; + $( + fn $fn_name:ident( + $( + $param_name:ident : $param:ty + ),* + ) + = $id:expr ; + )* + ) => { + pub mod $mod_name { + use super::*; + + #[derive(Clone, Copy, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] + #[repr(u32)] + #[allow(non_camel_case_types)] + enum Id { + $( + #[allow(non_camel_case_types)] + $fn_name = $id, + )* + } + + impl Id { + /// Derive `Some` value from a `u8`, or `None` if it's invalid. + fn from_u8(value: u8) -> Option { + use self::*; + let functions = [ + $( Id::$fn_name ),* + ]; + functions.iter().map(|&f| f).find(|&f| value == f as u8) + } + } + + #[derive(Clone, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] + #[allow(missing_docs)] + pub enum Call { + $( + #[allow(non_camel_case_types)] + $fn_name ( $( $param ),* ) + ,)* + } + + pub trait Dispatch: Sized { + $( + fn $fn_name (self, $( $param_name: $param ),* ); + )* + } + + impl Call { + pub fn dispatch(self, d: D) { + match self { + $( + Call::$fn_name( $( $param_name ),* ) => + d.$fn_name( $( $param_name ),* ), + )* + } + } + } + + impl $crate::dispatch::Slicable for Call { + fn decode(input: &mut I) -> Option { + let id = u8::decode(input).and_then(Id::from_u8)?; + Some(match id { + $( + Id::$fn_name => { + $( + let $param_name = $crate::dispatch::Slicable::decode(input)?; + )* + Call :: $fn_name( $( $param_name ),* ) + } + )* + }) + } + + fn encode(&self) -> Vec { + let mut v = $crate::dispatch::Vec::new(); + match *self { + $( + Call::$fn_name( + $( + ref $param_name + ),* + ) => { + (Id::$fn_name as u8).using_encoded(|s| v.extend(s)); + $( + $param_name.using_encoded(|s| v.extend(s)); + )* + } + )* + } + v + } + + fn using_encoded R>(&self, f: F) -> R { + f(self.encode().as_slice()) + } + } + impl $crate::dispatch::NonTrivialSlicable for Call {} + } } } -/// Dispatch a function. -pub fn function(function: &Function, transactor: &AccountId) { - match *function { - Function::StakingStake => - staking::public::stake(transactor), - Function::StakingUnstake => - staking::public::unstake(transactor), - Function::StakingTransfer(dest, value) => - staking::public::transfer(transactor, &dest, value), - Function::SessionSetKey(session) => - session::public::set_key(transactor, &session), - Function::TimestampSet(t) => - timestamp::public::set(t), - Function::CouncilVotePropose(ref a) => - council_vote::public::propose(transactor, a), - Function::CouncilVoteVote(ref a, b) => - council_vote::public::vote(transactor, a, b), - Function::CouncilVoteVeto(ref a) => - council_vote::public::veto(transactor, a), - Function::CouncilSetApprovals(ref a, b) => - council::public::set_approvals(transactor, a, b), - Function::CouncilReapInactiveVoter(a, ref b, c, d) => - council::public::reap_inactive_voter(transactor, a, b, c, d), - Function::CouncilRetractVoter(a) => - council::public::retract_voter(transactor, a), - Function::CouncilSubmitCandidacy(a) => - council::public::submit_candidacy(transactor, a), - Function::CouncilPresentWinner(ref a, b, c) => - council::public::present_winner(transactor, a, b, c), - Function::DemocracyPropose(ref a, b) => - democracy::public::propose(transactor, a, b), - Function::DemocracySecond(a) => - democracy::public::second(transactor, a), - Function::DemocracyVote(a, b) => - democracy::public::vote(transactor, a, b), +macro_rules! impl_meta_dispatch { + ( + pub mod $super_name:ident; + path $path:ident; + trait $trait:ty; + $( + $camelcase:ident(mod $sub_name:ident) = $id:expr ; + )* + ) => { + pub mod $super_name { + use super::*; + + #[derive(Clone, Copy, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] + #[repr(u32)] + #[allow(non_camel_case_types)] + enum Id { + $( + #[allow(non_camel_case_types)] + $camelcase = $id, + )* + } + + impl Id { + /// Derive `Some` value from a `u8`, or `None` if it's invalid. + fn from_u8(value: u8) -> Option { + use self::*; + let functions = [ + $( Id::$camelcase ),* + ]; + functions.iter().map(|&f| f).find(|&f| value == f as u8) + } + } + + #[derive(Clone, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] + #[allow(missing_docs)] + pub enum Call { + $( + #[allow(non_camel_case_types)] + $camelcase ( $crate::runtime::$sub_name::$path::Call ) + ,)* + } + + impl Call { + pub fn dispatch(self, d: $trait) { + match self { + $( + Call::$camelcase(x) => x.dispatch(d), + )* + } + } + } + + impl $crate::dispatch::Slicable for Call { + fn decode(input: &mut I) -> Option { + let id = u8::decode(input).and_then(Id::from_u8)?; + Some(match id { + $( + Id::$camelcase => + Call::$camelcase( $crate::dispatch::Slicable::decode(input)? ), + )* + }) + } + + fn encode(&self) -> Vec { + let mut v = $crate::dispatch::Vec::new(); + match *self { + $( + Call::$camelcase( ref sub ) => { + (Id::$camelcase as u8).using_encoded(|s| v.extend(s)); + sub.using_encoded(|s| v.extend(s)); + } + )* + } + v + } + + fn using_encoded R>(&self, f: F) -> R { + f(self.encode().as_slice()) + } + } + impl $crate::dispatch::NonTrivialSlicable for Call {} + } } } + +impl_meta_dispatch! { + pub mod public; + path public; + trait staking::PublicPass; + Staking(mod staking) = 0; + Timestamp(mod timestamp) = 1; + Democracy(mod democracy) = 5; + Council(mod council) = 6; + CouncilVote(mod council) = 7; +} + +impl_meta_dispatch! { + pub mod privileged; + path privileged; + trait system::PrivPass; + Staking(mod staking) = 0; + Democracy(mod democracy) = 5; + Council(mod council) = 6; + CouncilVote(mod council) = 7; +} + +pub use self::privileged::Call as PrivCall; +pub use self::public::Call as PubCall; diff --git a/demo/runtime/src/lib.rs b/demo/runtime/src/lib.rs index a351da4230daa..b9d0b32912691 100644 --- a/demo/runtime/src/lib.rs +++ b/demo/runtime/src/lib.rs @@ -23,6 +23,9 @@ extern crate substrate_runtime_support as runtime_support; #[cfg(any(feature = "std", test))] extern crate substrate_keyring as keyring; +#[cfg(feature = "std")] #[macro_use] extern crate serde_derive; +#[cfg(feature = "std")] extern crate serde; + #[cfg(feature = "std")] extern crate rustc_hex; extern crate substrate_codec as codec; @@ -33,48 +36,12 @@ extern crate demo_primitives; extern crate integer_sqrt; +#[macro_use] pub mod dispatch; + +pub mod block; +pub mod transaction; pub mod environment; pub mod runtime; pub mod api; -pub mod dispatch; #[cfg(feature = "std")] pub mod genesismap; - -/// Type definitions and helpers for transactions. -pub mod transaction { - use rstd::ops; - use demo_primitives::Signature; - pub use demo_primitives::{Transaction, UncheckedTransaction}; - - /// A type-safe indicator that a transaction has been checked. - #[derive(PartialEq, Eq, Clone)] - #[cfg_attr(feature = "std", derive(Debug))] - pub struct CheckedTransaction(UncheckedTransaction); - - impl CheckedTransaction { - /// Get a reference to the checked signature. - pub fn signature(&self) -> &Signature { - &self.0.signature - } - } - - impl ops::Deref for CheckedTransaction { - type Target = Transaction; - - fn deref(&self) -> &Transaction { - &self.0.transaction - } - } - - /// Check the signature on a transaction. - /// - /// On failure, return the transaction back. - pub fn check(tx: UncheckedTransaction) -> Result { - let msg = ::codec::Slicable::encode(&tx.transaction); - if ::runtime_io::ed25519_verify(&tx.signature.0, &msg, &tx.transaction.signed) { - Ok(CheckedTransaction(tx)) - } else { - Err(tx) - } - } -} diff --git a/demo/runtime/src/runtime/council.rs b/demo/runtime/src/runtime/council.rs index ce922f897179a..777144676f426 100644 --- a/demo/runtime/src/runtime/council.rs +++ b/demo/runtime/src/runtime/council.rs @@ -19,9 +19,10 @@ use rstd::prelude::*; use codec::KeyedVec; use runtime_support::storage; -use demo_primitives::{Proposal, AccountId, Hash, BlockNumber}; +use demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{staking, system, session}; -use runtime::staking::Balance; +use runtime::system::PrivPass; +use runtime::staking::{PublicPass, Balance}; // no polynomial attacks: // @@ -255,25 +256,33 @@ pub fn leaderboard() -> Option> { storage::get(LEADERBOARD) } -pub mod public { - use super::*; +impl_dispatch! { + pub mod public; + fn set_approvals(votes: Vec, index: VoteIndex) = 0; + fn reap_inactive_voter(signed_index: u32, who: AccountId, who_index: u32, assumed_vote_index: VoteIndex) = 1; + fn retract_voter(index: u32) = 2; + fn submit_candidacy(slot: u32) = 3; + fn present_winner(candidate: AccountId, total: Balance, index: VoteIndex) = 4; +} + +impl<'a> public::Dispatch for PublicPass<'a> { /// Set candidate approvals. Approval slots stay valid as long as candidates in those slots /// are registered. - pub fn set_approvals(signed: &AccountId, votes: &Vec, index: VoteIndex) { + fn set_approvals(self, votes: Vec, index: VoteIndex) { assert!(!presentation_active()); assert_eq!(index, vote_index()); - if !storage::exists(&signed.to_keyed_vec(LAST_ACTIVE_OF)) { + if !storage::exists(&self.to_keyed_vec(LAST_ACTIVE_OF)) { // not yet a voter - deduct bond. - staking::internal::reserve_balance(signed, voting_bond()); + staking::internal::reserve_balance(&self, voting_bond()); storage::put(VOTERS, &{ let mut v: Vec = storage::get_or_default(VOTERS); - v.push(signed.clone()); + v.push(self.clone()); v }); } - storage::put(&signed.to_keyed_vec(APPROVALS_OF), votes); - storage::put(&signed.to_keyed_vec(LAST_ACTIVE_OF), &index); + storage::put(&self.to_keyed_vec(APPROVALS_OF), &votes); + storage::put(&self.to_keyed_vec(LAST_ACTIVE_OF), &index); } /// Remove a voter. For it not to be a bond-consuming no-op, all approved candidate indices @@ -281,21 +290,21 @@ pub mod public { /// the voter gave their last approval set. /// /// May be called by anyone. Returns the voter deposit to `signed`. - pub fn reap_inactive_voter(signed: &AccountId, signed_index: u32, who: &AccountId, who_index: u32, assumed_vote_index: VoteIndex) { + fn reap_inactive_voter(self, signed_index: u32, who: AccountId, who_index: u32, assumed_vote_index: VoteIndex) { assert!(!presentation_active(), "cannot reap during presentation period"); - assert!(voter_last_active(signed).is_some(), "reaper must be a voter"); - let last_active = voter_last_active(who).expect("target for inactivity cleanup must be active"); + assert!(voter_last_active(&self).is_some(), "reaper must be a voter"); + let last_active = voter_last_active(&who).expect("target for inactivity cleanup must be active"); assert!(assumed_vote_index == vote_index(), "vote index not current"); assert!(last_active < assumed_vote_index - inactivity_grace_period(), "cannot reap during grace perid"); let voters = voters(); let signed_index = signed_index as usize; let who_index = who_index as usize; - assert!(signed_index < voters.len() && voters[signed_index] == *signed, "bad reporter index"); - assert!(who_index < voters.len() && voters[who_index] == *who, "bad target index"); + assert!(signed_index < voters.len() && voters[signed_index] == *self, "bad reporter index"); + assert!(who_index < voters.len() && voters[who_index] == who, "bad target index"); // will definitely kill one of signed or who now. - let valid = !approvals_of(who).iter() + let valid = !approvals_of(&who).iter() .zip(candidates().iter()) .any(|(&appr, addr)| appr && @@ -304,35 +313,35 @@ pub mod public { .expect("all items in candidates list are registered").0 <= last_active); remove_voter( - if valid { who } else { signed }, + if valid { &who } else { &self }, if valid { who_index } else { signed_index }, voters ); if valid { - staking::internal::transfer_reserved_balance(who, signed, voting_bond()); + staking::internal::transfer_reserved_balance(&who, &self, voting_bond()); } else { - staking::internal::slash_reserved(signed, voting_bond()); + staking::internal::slash_reserved(&self, voting_bond()); } } /// Remove a voter. All votes are cancelled and the voter deposit is returned. - pub fn retract_voter(signed: &AccountId, index: u32) { + fn retract_voter(self, index: u32) { assert!(!presentation_active(), "cannot retract when presenting"); - assert!(storage::exists(&signed.to_keyed_vec(LAST_ACTIVE_OF)), "cannot retract non-voter"); + assert!(storage::exists(&self.to_keyed_vec(LAST_ACTIVE_OF)), "cannot retract non-voter"); let voters = voters(); let index = index as usize; assert!(index < voters.len(), "retraction index invalid"); - assert!(voters[index] == *signed, "retraction index mismatch"); - remove_voter(signed, index, voters); - staking::internal::unreserve_balance(signed, voting_bond()); + assert!(voters[index] == *self, "retraction index mismatch"); + remove_voter(&self, index, voters); + staking::internal::unreserve_balance(&self, voting_bond()); } /// Submit oneself for candidacy. /// /// Account must have enough transferrable funds in it to pay the bond. - pub fn submit_candidacy(signed: &AccountId, slot: u32) { - assert!(!is_a_candidate(signed), "duplicate candidate submission"); - assert!(staking::internal::deduct_unbonded(signed, candidacy_bond()), "candidate has not enough funds"); + fn submit_candidacy(self, slot: u32) { + assert!(!is_a_candidate(&self), "duplicate candidate submission"); + assert!(staking::internal::deduct_unbonded(&self, candidacy_bond()), "candidate has not enough funds"); let slot = slot as usize; let count = storage::get_or_default::(CANDIDATE_COUNT) as usize; @@ -345,31 +354,31 @@ pub mod public { let mut candidates = candidates; if slot == candidates.len() { - candidates.push(signed.clone()); + candidates.push(self.clone()); } else { - candidates[slot] = signed.clone(); + candidates[slot] = self.clone(); } storage::put(CANDIDATES, &candidates); storage::put(CANDIDATE_COUNT, &(count as u32 + 1)); - storage::put(&signed.to_keyed_vec(REGISTER_INFO_OF), &(vote_index(), slot)); + storage::put(&self.to_keyed_vec(REGISTER_INFO_OF), &(vote_index(), slot)); } /// 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() /// `signed` should have at least - pub fn present_winner(signed: &AccountId, candidate: &AccountId, total: Balance, index: VoteIndex) { + fn present_winner(self, candidate: AccountId, total: Balance, index: VoteIndex) { assert_eq!(index, vote_index(), "index not current"); let (_, _, expiring): (BlockNumber, u32, Vec) = storage::get(NEXT_FINALISE) .expect("cannot present outside of presentation period"); let stakes: Vec = storage::get_or_default(SNAPSHOTED_STAKES); let voters: Vec = storage::get_or_default(VOTERS); let bad_presentation_punishment = present_slash_per_voter() * voters.len() as Balance; - assert!(staking::can_slash(signed, bad_presentation_punishment), "presenter must have sufficient slashable funds"); + assert!(staking::can_slash(&self, bad_presentation_punishment), "presenter must have sufficient slashable funds"); let mut leaderboard = leaderboard().expect("leaderboard must exist while present phase active"); assert!(total > leaderboard[0].0, "candidate not worthy of leaderboard"); - if let Some(p) = active_council().iter().position(|&(ref c, _)| c == candidate) { + if let Some(p) = active_council().iter().position(|&(ref c, _)| c == &candidate) { assert!(p < expiring.len(), "candidate must not form a duplicated member if elected"); } @@ -385,55 +394,60 @@ pub mod public { _ => None, }) .sum(); - let dupe = leaderboard.iter().find(|&&(_, ref c)| c == candidate).is_some(); + let dupe = leaderboard.iter().find(|&&(_, ref c)| c == &candidate).is_some(); if total == actual_total && !dupe { // insert into leaderboard leaderboard[0] = (total, candidate.clone()); leaderboard.sort_by_key(|&(t, _)| t); storage::put(LEADERBOARD, &leaderboard); } else { - staking::internal::slash(signed, bad_presentation_punishment); + staking::internal::slash(&self, bad_presentation_punishment); } } } -pub mod privileged { - use super::*; +impl_dispatch! { + pub mod privileged; + fn set_desired_seats(count: u32) = 0; + fn remove_member(who: AccountId) = 1; + fn set_presentation_duration(count: BlockNumber) = 2; + fn set_term_duration(count: BlockNumber) = 3; +} +impl privileged::Dispatch for PrivPass { /// 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) { + fn set_desired_seats(self, count: u32) { storage::put(DESIRED_SEATS, &count); } /// Remove a particular member. A tally will happen instantly (if not already in a presentation /// period) to fill the seat if removal means that the desired members are not met. /// This is effective immediately. - pub fn remove_member(who: &AccountId) { + fn remove_member(self, who: AccountId) { let new_council: Vec<(AccountId, BlockNumber)> = active_council() .into_iter() - .filter(|i| i.0 != *who) + .filter(|i| i.0 != who) .collect(); storage::put(ACTIVE_COUNCIL, &new_council); } /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalise_vote`. - pub fn set_presentation_duration(count: BlockNumber) { + fn set_presentation_duration(self, count: BlockNumber) { storage::put(PRESENTATION_DURATION, &count); } /// Set the presentation duration. If there is current a vote being presented for, will /// invoke `finalise_vote`. - pub fn set_term_duration(count: BlockNumber) { + fn set_term_duration(self, count: BlockNumber) { storage::put(TERM_DURATION, &count); } } pub mod internal { use super::*; - use demo_primitives::Proposal; /// Check there's nothing to do this block pub fn end_block() { @@ -578,8 +592,10 @@ mod tests { use codec::{KeyedVec, Joiner}; use keyring::Keyring::*; use environment::with_env; - use demo_primitives::{AccountId, Proposal}; + use demo_primitives::AccountId; use runtime::{staking, session, democracy}; + use super::public::Dispatch; + use super::privileged::Dispatch as PrivDispatch; fn new_test_ext() -> TestExternalities { testing::externalities() @@ -628,14 +644,14 @@ mod tests { assert_eq!(is_a_candidate(&Alice), false); assert_eq!(is_a_candidate(&Bob), false); - public::submit_candidacy(&Alice, 0); + PublicPass::test(&Alice).submit_candidacy(0); assert_eq!(candidates(), vec![Alice.to_raw_public()]); assert_eq!(candidate_reg_info(&Alice), Some((0 as VoteIndex, 0u32))); assert_eq!(candidate_reg_info(&Bob), None); assert_eq!(is_a_candidate(&Alice), true); assert_eq!(is_a_candidate(&Bob), false); - public::submit_candidacy(&Bob, 1); + PublicPass::test(&Bob).submit_candidacy(1); assert_eq!(candidates(), vec![Alice.to_raw_public(), Bob.into()]); assert_eq!(candidate_reg_info(&Alice), Some((0 as VoteIndex, 0u32))); assert_eq!(candidate_reg_info(&Bob), Some((0 as VoteIndex, 1u32))); @@ -660,10 +676,10 @@ mod tests { with_env(|e| e.block_number = 1); assert_eq!(candidates(), vec![AccountId::default(), AccountId::default(), Alice.to_raw_public()]); - public::submit_candidacy(&Bob, 1); + PublicPass::test(&Bob).submit_candidacy(1); assert_eq!(candidates(), vec![AccountId::default(), Bob.into(), Alice.to_raw_public()]); - public::submit_candidacy(&Charlie, 0); + PublicPass::test(&Charlie).submit_candidacy(0); assert_eq!(candidates(), vec![Charlie.into(), Bob.into(), Alice.to_raw_public()]); }); } @@ -676,10 +692,10 @@ mod tests { with_env(|e| e.block_number = 1); assert_eq!(candidates(), vec![AccountId::default(), AccountId::default(), Alice.into()]); - public::submit_candidacy(&Bob, 0); + PublicPass::test(&Bob).submit_candidacy(0); assert_eq!(candidates(), vec![Bob.into(), AccountId::default(), Alice.into()]); - public::submit_candidacy(&Charlie, 1); + PublicPass::test(&Charlie).submit_candidacy(1); assert_eq!(candidates(), vec![Bob.to_raw_public(), Charlie.into(), Alice.into()]); }); } @@ -691,7 +707,7 @@ mod tests { with_externalities(&mut t, || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Dave, 3); + PublicPass::test(&Dave).submit_candidacy(3); }); } @@ -701,7 +717,7 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); assert_eq!(candidates(), Vec::::new()); - public::submit_candidacy(&Alice, 1); + PublicPass::test(&Alice).submit_candidacy(1); }); } @@ -711,8 +727,8 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); assert_eq!(candidates(), Vec::::new()); - public::submit_candidacy(&Alice, 0); - public::submit_candidacy(&Bob, 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Bob).submit_candidacy(0); }); } @@ -722,8 +738,8 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); assert_eq!(candidates(), Vec::::new()); - public::submit_candidacy(&Alice, 0); - public::submit_candidacy(&Alice, 1); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Alice).submit_candidacy(1); }); } @@ -733,7 +749,7 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); assert_eq!(candidates(), Vec::::new()); - public::submit_candidacy(&One, 0); + PublicPass::test(&One).submit_candidacy(0); }); } @@ -742,20 +758,20 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Eve, 0); + PublicPass::test(&Eve).submit_candidacy(0); - public::set_approvals(&Alice, &vec![true], 0); - public::set_approvals(&Dave, &vec![true], 0); + PublicPass::test(&Alice).set_approvals(vec![true], 0); + PublicPass::test(&Dave).set_approvals(vec![true], 0); assert_eq!(approvals_of(&Alice), vec![true]); assert_eq!(approvals_of(&Dave), vec![true]); assert_eq!(voters(), vec![Alice.to_raw_public(), Dave.into()]); - public::submit_candidacy(&Bob, 1); - public::submit_candidacy(&Charlie, 2); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Charlie).submit_candidacy(2); - public::set_approvals(&Bob, &vec![false, true, true], 0); - public::set_approvals(&Charlie, &vec![false, true, true], 0); + PublicPass::test(&Bob).set_approvals(vec![false, true, true], 0); + PublicPass::test(&Charlie).set_approvals(vec![false, true, true], 0); assert_eq!(approvals_of(&Alice), vec![true]); assert_eq!(approvals_of(&Dave), vec![true]); @@ -763,8 +779,6 @@ mod tests { assert_eq!(approvals_of(&Charlie), vec![false, true, true]); assert_eq!(voters(), vec![Alice.to_raw_public(), Dave.into(), Bob.into(), Charlie.into()]); - - }); } @@ -773,14 +787,14 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Dave, &vec![true], 0); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Dave).set_approvals(vec![true], 0); assert_eq!(approvals_of(&Dave), vec![true]); - public::submit_candidacy(&Bob, 1); - public::submit_candidacy(&Charlie, 2); - public::set_approvals(&Dave, &vec![true, false, true], 0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Charlie).submit_candidacy(2); + PublicPass::test(&Dave).set_approvals(vec![true, false, true], 0); assert_eq!(approvals_of(&Dave), vec![true, false, true]); }); @@ -791,14 +805,14 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Eve, 0); - public::submit_candidacy(&Bob, 1); - public::submit_candidacy(&Charlie, 2); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Charlie).submit_candidacy(2); - public::set_approvals(&Alice, &vec![true], 0); - public::set_approvals(&Bob, &vec![false, true, true], 0); - public::set_approvals(&Charlie, &vec![false, true, true], 0); - public::set_approvals(&Dave, &vec![true, false, true], 0); + PublicPass::test(&Alice).set_approvals(vec![true], 0); + PublicPass::test(&Bob).set_approvals(vec![false, true, true], 0); + PublicPass::test(&Charlie).set_approvals(vec![false, true, true], 0); + PublicPass::test(&Dave).set_approvals(vec![true, false, true], 0); assert_eq!(voters(), vec![Alice.to_raw_public(), Bob.into(), Charlie.into(), Dave.into()]); assert_eq!(approvals_of(&Alice), vec![true]); @@ -806,7 +820,7 @@ mod tests { assert_eq!(approvals_of(&Charlie), vec![false, true, true]); assert_eq!(approvals_of(&Dave), vec![true, false, true]); - public::retract_voter(&Alice, 0); + PublicPass::test(&Alice).retract_voter(0); assert_eq!(voters(), vec![Dave.to_raw_public(), Bob.into(), Charlie.into()]); assert_eq!(approvals_of(&Alice), Vec::::new()); @@ -814,7 +828,7 @@ mod tests { assert_eq!(approvals_of(&Charlie), vec![false, true, true]); assert_eq!(approvals_of(&Dave), vec![true, false, true]); - public::retract_voter(&Bob, 1); + PublicPass::test(&Bob).retract_voter(1); assert_eq!(voters(), vec![Dave.to_raw_public(), Charlie.into()]); assert_eq!(approvals_of(&Alice), Vec::::new()); @@ -822,7 +836,7 @@ mod tests { assert_eq!(approvals_of(&Charlie), vec![false, true, true]); assert_eq!(approvals_of(&Dave), vec![true, false, true]); - public::retract_voter(&Charlie, 1); + PublicPass::test(&Charlie).retract_voter(1); assert_eq!(voters(), vec![Dave.to_raw_public()]); assert_eq!(approvals_of(&Alice), Vec::::new()); @@ -837,10 +851,10 @@ mod tests { fn invalid_retraction_index_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Charlie, 0); - public::set_approvals(&Alice, &vec![true], 0); - public::set_approvals(&Bob, &vec![true], 0); - public::retract_voter(&Alice, 1); + PublicPass::test(&Charlie).submit_candidacy(0); + PublicPass::test(&Alice).set_approvals(vec![true], 0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); + PublicPass::test(&Alice).retract_voter(1); }); } @@ -849,9 +863,9 @@ mod tests { fn overflow_retraction_index_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Charlie, 0); - public::set_approvals(&Alice, &vec![true], 0); - public::retract_voter(&Alice, 1); + PublicPass::test(&Charlie).submit_candidacy(0); + PublicPass::test(&Alice).set_approvals(vec![true], 0); + PublicPass::test(&Alice).retract_voter(1); }); } @@ -860,9 +874,9 @@ mod tests { fn non_voter_retraction_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::submit_candidacy(&Charlie, 0); - public::set_approvals(&Alice, &vec![true], 0); - public::retract_voter(&Bob, 0); + PublicPass::test(&Charlie).submit_candidacy(0); + PublicPass::test(&Alice).set_approvals(vec![true], 0); + PublicPass::test(&Bob).retract_voter(0); }); } @@ -872,16 +886,16 @@ mod tests { with_env(|e| e.block_number = 4); assert!(!presentation_active()); - public::submit_candidacy(&Bob, 0); - public::submit_candidacy(&Eve, 1); - public::set_approvals(&Bob, &vec![true, false], 0); - public::set_approvals(&Eve, &vec![false, true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Eve).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); assert!(presentation_active()); - public::present_winner(&Dave, &Bob, 11, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); assert_eq!(leaderboard(), Some(vec![(0, AccountId::default()), (0, AccountId::default()), (11, Bob.into()), (41, Eve.into())])); internal::end_block(); @@ -903,16 +917,16 @@ mod tests { assert!(staking::can_slash(&Dave, 10)); with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::submit_candidacy(&Eve, 1); - public::set_approvals(&Bob, &vec![true, false], 0); - public::set_approvals(&Eve, &vec![false, true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Eve).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); - public::present_winner(&Dave, &Eve, 41, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); internal::end_block(); assert_eq!(active_council(), vec![(Eve.to_raw_public(), 11), (Bob.into(), 11)]); @@ -924,26 +938,26 @@ mod tests { fn retracting_inactive_voter_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Eve, &vec![true], 1); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Eve).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Eve, 41, 1); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 1); internal::end_block(); - public::reap_inactive_voter( - &Eve, voters().iter().position(|&i| i == *Eve).unwrap() as u32, - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, + PublicPass::test(&Eve).reap_inactive_voter( + voters().iter().position(|&i| i == *Eve).unwrap() as u32, + Bob.into(), voters().iter().position(|&i| i == *Bob).unwrap() as u32, 2 ); @@ -959,21 +973,21 @@ mod tests { fn presenting_for_double_election_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 1); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Bob, 11, 1); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 1); }); } @@ -981,29 +995,29 @@ mod tests { fn retracting_inactive_voter_with_other_candidates_in_slots_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Eve, &vec![true], 1); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Eve).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Eve, 41, 1); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 1); internal::end_block(); with_env(|e| e.block_number = 11); - public::submit_candidacy(&Alice, 0); + PublicPass::test(&Alice).submit_candidacy(0); - public::reap_inactive_voter( - &Eve, voters().iter().position(|&i| i == *Eve).unwrap() as u32, - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, + PublicPass::test(&Eve).reap_inactive_voter( + voters().iter().position(|&i| i == *Eve).unwrap() as u32, + Bob.into(), voters().iter().position(|&i| i == *Bob).unwrap() as u32, 2 ); @@ -1019,26 +1033,26 @@ mod tests { fn retracting_inactive_voter_with_bad_reporter_index_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 8, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 8, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Eve, &vec![true], 1); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Eve).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Eve, 38, 1); + PublicPass::test(&Dave).present_winner(Eve.into(), 38, 1); internal::end_block(); - public::reap_inactive_voter( - &Bob, 42, - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, + PublicPass::test(&Bob).reap_inactive_voter( + 42, + Bob.into(), voters().iter().position(|&i| i == *Bob).unwrap() as u32, 2 ); }); @@ -1049,26 +1063,26 @@ mod tests { fn retracting_inactive_voter_with_bad_target_index_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 8, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 8, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Eve, &vec![true], 1); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Eve).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Eve, 38, 1); + PublicPass::test(&Dave).present_winner(Eve.into(), 38, 1); internal::end_block(); - public::reap_inactive_voter( - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, - &Bob, 42, + PublicPass::test(&Bob).reap_inactive_voter( + voters().iter().position(|&i| i == *Bob).unwrap() as u32, + Bob.into(), 42, 2 ); }); @@ -1078,35 +1092,35 @@ mod tests { fn attempting_to_retract_active_voter_should_slash_reporter() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::submit_candidacy(&Charlie, 1); - public::submit_candidacy(&Dave, 2); - public::submit_candidacy(&Eve, 3); - public::set_approvals(&Bob, &vec![true, false, false, false], 0); - public::set_approvals(&Charlie, &vec![false, true, false, false], 0); - public::set_approvals(&Dave, &vec![false, false, true, false], 0); - public::set_approvals(&Eve, &vec![false, false, false, true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Charlie).submit_candidacy(1); + PublicPass::test(&Dave).submit_candidacy(2); + PublicPass::test(&Eve).submit_candidacy(3); + PublicPass::test(&Bob).set_approvals(vec![true, false, false, false], 0); + PublicPass::test(&Charlie).set_approvals(vec![false, true, false, false], 0); + PublicPass::test(&Dave).set_approvals(vec![false, false, true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, false, false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); - public::present_winner(&Dave, &Charlie, 21, 0); - public::present_winner(&Dave, &Dave, 31, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 0); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); internal::end_block(); with_env(|e| e.block_number = 8); - privileged::set_desired_seats(3); + PrivPass.set_desired_seats(3); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Bob, 11, 1); - public::present_winner(&Dave, &Charlie, 21, 1); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 1); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 1); internal::end_block(); - public::reap_inactive_voter( - &Dave, voters().iter().position(|&i| i == *Dave).unwrap() as u32, - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, + PublicPass::test(&Dave).reap_inactive_voter( + voters().iter().position(|&i| i == *Dave).unwrap() as u32, + Bob.into(), voters().iter().position(|&i| i == *Bob).unwrap() as u32, 2 ); @@ -1121,26 +1135,26 @@ mod tests { fn attempting_to_retract_inactive_voter_by_nonvoter_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::set_approvals(&Bob, &vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Bob).set_approvals(vec![true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::submit_candidacy(&Eve, 0); - public::set_approvals(&Eve, &vec![true], 1); + PublicPass::test(&Eve).submit_candidacy(0); + PublicPass::test(&Eve).set_approvals(vec![true], 1); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Eve, 41, 1); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 1); internal::end_block(); - public::reap_inactive_voter( - &Dave, 0, - &Bob, voters().iter().position(|&i| i == *Bob).unwrap() as u32, + PublicPass::test(&Dave).reap_inactive_voter( + 0, + Bob.into(), voters().iter().position(|&i| i == *Bob).unwrap() as u32, 2 ); }); @@ -1151,24 +1165,24 @@ mod tests { fn presenting_loser_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Alice, 0); - public::set_approvals(&Ferdie, &vec![true], 0); - public::submit_candidacy(&Bob, 1); - public::set_approvals(&Bob, &vec![false, true], 0); - public::submit_candidacy(&Charlie, 2); - public::set_approvals(&Charlie, &vec![false, false, true], 0); - public::submit_candidacy(&Dave, 3); - public::set_approvals(&Dave, &vec![false, false, false, true], 0); - public::submit_candidacy(&Eve, 4); - public::set_approvals(&Eve, &vec![false, false, false, false, true], 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Ferdie).set_approvals(vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![false, true], 0); + PublicPass::test(&Charlie).submit_candidacy(2); + PublicPass::test(&Charlie).set_approvals(vec![false, false, true], 0); + PublicPass::test(&Dave).submit_candidacy(3); + PublicPass::test(&Dave).set_approvals(vec![false, false, false, true], 0); + PublicPass::test(&Eve).submit_candidacy(4); + PublicPass::test(&Eve).set_approvals(vec![false, false, false, false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Alice, 60, 0); - public::present_winner(&Dave, &Charlie, 21, 0); - public::present_winner(&Dave, &Dave, 31, 0); - public::present_winner(&Dave, &Eve, 41, 0); - public::present_winner(&Dave, &Bob, 11, 0); + PublicPass::test(&Dave).present_winner(Alice.into(), 60, 0); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 0); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); }); } @@ -1176,24 +1190,24 @@ mod tests { fn presenting_loser_first_should_not_matter() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Alice, 0); - public::set_approvals(&Ferdie, &vec![true], 0); - public::submit_candidacy(&Bob, 1); - public::set_approvals(&Bob, &vec![false, true], 0); - public::submit_candidacy(&Charlie, 2); - public::set_approvals(&Charlie, &vec![false, false, true], 0); - public::submit_candidacy(&Dave, 3); - public::set_approvals(&Dave, &vec![false, false, false, true], 0); - public::submit_candidacy(&Eve, 4); - public::set_approvals(&Eve, &vec![false, false, false, false, true], 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Ferdie).set_approvals(vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![false, true], 0); + PublicPass::test(&Charlie).submit_candidacy(2); + PublicPass::test(&Charlie).set_approvals(vec![false, false, true], 0); + PublicPass::test(&Dave).submit_candidacy(3); + PublicPass::test(&Dave).set_approvals(vec![false, false, false, true], 0); + PublicPass::test(&Eve).submit_candidacy(4); + PublicPass::test(&Eve).set_approvals(vec![false, false, false, false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 0); - public::present_winner(&Dave, &Alice, 60, 0); - public::present_winner(&Dave, &Charlie, 21, 0); - public::present_winner(&Dave, &Dave, 31, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 0); + PublicPass::test(&Dave).present_winner(Alice.into(), 60, 0); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 0); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); assert_eq!(leaderboard(), Some(vec![ (21, Charlie.into()), @@ -1210,7 +1224,7 @@ mod tests { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); assert!(!presentation_active()); - public::present_winner(&Eve, &Eve, 1, 0); + PublicPass::test(&Eve).present_winner(Eve.into(), 1, 0); }); } @@ -1219,14 +1233,14 @@ mod tests { fn present_panics_with_invalid_vote_index() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Bob, 0); - public::submit_candidacy(&Eve, 1); - public::set_approvals(&Bob, &vec![true, false], 0); - public::set_approvals(&Eve, &vec![false, true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Eve).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 11, 1); + PublicPass::test(&Dave).present_winner(Bob.into(), 11, 1); }); } @@ -1237,15 +1251,15 @@ mod tests { with_env(|e| e.block_number = 4); assert!(!presentation_active()); - public::submit_candidacy(&Alice, 0); - public::submit_candidacy(&Eve, 1); - public::set_approvals(&Bob, &vec![true, false], 0); - public::set_approvals(&Eve, &vec![false, true], 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Eve).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); assert_eq!(staking::balance(&Alice), 1); - public::present_winner(&Alice, &Alice, 30, 0); + PublicPass::test(&Alice).present_winner(Alice.into(), 30, 0); }); } @@ -1256,14 +1270,14 @@ mod tests { assert!(!presentation_active()); assert_eq!(staking::balance(&Dave), 40); - public::submit_candidacy(&Bob, 0); - public::submit_candidacy(&Eve, 1); - public::set_approvals(&Bob, &vec![true, false], 0); - public::set_approvals(&Eve, &vec![false, true], 0); + PublicPass::test(&Bob).submit_candidacy(0); + PublicPass::test(&Eve).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![true, false], 0); + PublicPass::test(&Eve).set_approvals(vec![false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Bob, 80, 0); + PublicPass::test(&Dave).present_winner(Bob.into(), 80, 0); assert_eq!(staking::balance(&Dave), 38); }); @@ -1275,31 +1289,31 @@ mod tests { with_env(|e| e.block_number = 4); assert!(!presentation_active()); - public::submit_candidacy(&Alice, 0); - public::set_approvals(&Ferdie, &vec![true], 0); - public::submit_candidacy(&Bob, 1); - public::set_approvals(&Bob, &vec![false, true], 0); - public::submit_candidacy(&Charlie, 2); - public::set_approvals(&Charlie, &vec![false, false, true], 0); - public::submit_candidacy(&Dave, 3); - public::set_approvals(&Dave, &vec![false, false, false, true], 0); - public::submit_candidacy(&Eve, 4); - public::set_approvals(&Eve, &vec![false, false, false, false, true], 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Ferdie).set_approvals(vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![false, true], 0); + PublicPass::test(&Charlie).submit_candidacy(2); + PublicPass::test(&Charlie).set_approvals(vec![false, false, true], 0); + PublicPass::test(&Dave).submit_candidacy(3); + PublicPass::test(&Dave).set_approvals(vec![false, false, false, true], 0); + PublicPass::test(&Eve).submit_candidacy(4); + PublicPass::test(&Eve).set_approvals(vec![false, false, false, false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); assert!(presentation_active()); - public::present_winner(&Dave, &Alice, 60, 0); + PublicPass::test(&Dave).present_winner(Alice.into(), 60, 0); assert_eq!(leaderboard(), Some(vec![ (0, AccountId::default()), (0, AccountId::default()), (0, AccountId::default()), (60, Alice.to_raw_public()) ])); - public::present_winner(&Dave, &Charlie, 21, 0); - public::present_winner(&Dave, &Dave, 31, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 0); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); assert_eq!(leaderboard(), Some(vec![ (21, Charlie.into()), (31, Dave.into()), @@ -1332,33 +1346,33 @@ mod tests { fn second_tally_should_use_runners_up() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 4); - public::submit_candidacy(&Alice, 0); - public::set_approvals(&Ferdie, &vec![true], 0); - public::submit_candidacy(&Bob, 1); - public::set_approvals(&Bob, &vec![false, true], 0); - public::submit_candidacy(&Charlie, 2); - public::set_approvals(&Charlie, &vec![false, false, true], 0); - public::submit_candidacy(&Dave, 3); - public::set_approvals(&Dave, &vec![false, false, false, true], 0); - public::submit_candidacy(&Eve, 4); - public::set_approvals(&Eve, &vec![false, false, false, false, true], 0); + PublicPass::test(&Alice).submit_candidacy(0); + PublicPass::test(&Ferdie).set_approvals(vec![true], 0); + PublicPass::test(&Bob).submit_candidacy(1); + PublicPass::test(&Bob).set_approvals(vec![false, true], 0); + PublicPass::test(&Charlie).submit_candidacy(2); + PublicPass::test(&Charlie).set_approvals(vec![false, false, true], 0); + PublicPass::test(&Dave).submit_candidacy(3); + PublicPass::test(&Dave).set_approvals(vec![false, false, false, true], 0); + PublicPass::test(&Eve).submit_candidacy(4); + PublicPass::test(&Eve).set_approvals(vec![false, false, false, false, true], 0); internal::end_block(); with_env(|e| e.block_number = 6); - public::present_winner(&Dave, &Alice, 60, 0); - public::present_winner(&Dave, &Charlie, 21, 0); - public::present_winner(&Dave, &Dave, 31, 0); - public::present_winner(&Dave, &Eve, 41, 0); + PublicPass::test(&Dave).present_winner(Alice.into(), 60, 0); + PublicPass::test(&Dave).present_winner(Charlie.into(), 21, 0); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 0); + PublicPass::test(&Dave).present_winner(Eve.into(), 41, 0); internal::end_block(); with_env(|e| e.block_number = 8); - public::set_approvals(&Ferdie, &vec![false, false, true, false], 1); - privileged::set_desired_seats(3); + PublicPass::test(&Ferdie).set_approvals(vec![false, false, true, false], 1); + PrivPass.set_desired_seats(3); internal::end_block(); with_env(|e| e.block_number = 10); - public::present_winner(&Dave, &Charlie, 81, 1); - public::present_winner(&Dave, &Dave, 31, 1); + PublicPass::test(&Dave).present_winner(Charlie.into(), 81, 1); + PublicPass::test(&Dave).present_winner(Dave.into(), 31, 1); internal::end_block(); assert!(!presentation_active()); diff --git a/demo/runtime/src/runtime/council_vote.rs b/demo/runtime/src/runtime/council_vote.rs index b40c79d79b486..19e3ddae20c70 100644 --- a/demo/runtime/src/runtime/council_vote.rs +++ b/demo/runtime/src/runtime/council_vote.rs @@ -20,9 +20,11 @@ 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 demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{system, democracy, council}; -use runtime::staking::Balance; +use runtime::staking::{PublicPass, Balance}; +use runtime::system::PrivPass; +use dispatch::PrivCall as Proposal; type ProposalHash = [u8; 32]; @@ -119,12 +121,17 @@ fn take_proposal_if_expiring_at(n: BlockNumber) -> Option<(Proposal, ProposalHas } } -pub mod public { - use super::*; +impl_dispatch! { + pub mod public; + fn propose(proposal: Box) = 0; + fn vote(proposal: ProposalHash, approve: bool) = 1; + fn veto(proposal_hash: ProposalHash) = 2; +} - pub fn propose(signed: &AccountId, proposal: &Proposal) { +impl<'a> public::Dispatch for PublicPass<'a> { + fn propose(self, proposal: Box) { let expiry = system::block_number() + voting_period(); - assert!(will_still_be_councillor_at(signed, expiry)); + assert!(will_still_be_councillor_at(&self, expiry)); let proposal_hash = proposal.blake2_256(); @@ -135,65 +142,70 @@ pub mod public { 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); + storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_OF), &proposal); + storage::put(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS), &vec![*self]); + storage::put(&(proposal_hash, *self).to_keyed_vec(COUNCIL_VOTE_OF), &true); } - pub fn vote(signed: &AccountId, proposal: &ProposalHash, approve: bool) { - if vote_of(signed, proposal).is_none() { - let mut voters = proposal_voters(proposal); - voters.push(*signed); + fn vote(self, proposal: ProposalHash, approve: bool) { + if vote_of(&self, &proposal).is_none() { + let mut voters = proposal_voters(&proposal); + voters.push(*self); storage::put(&proposal.to_keyed_vec(PROPOSAL_VOTERS), &voters); } - storage::put(&(*proposal, *signed).to_keyed_vec(COUNCIL_VOTE_OF), &approve); + storage::put(&(proposal, *self).to_keyed_vec(COUNCIL_VOTE_OF), &approve); } - pub fn veto(signed: &AccountId, proposal_hash: &ProposalHash) { - assert!(is_councillor(signed), "only councillors may veto council proposals"); + fn veto(self, proposal_hash: ProposalHash) { + assert!(is_councillor(&self), "only councillors may veto council proposals"); assert!(storage::exists(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS)), "proposal must exist to be vetoed"); let mut existing_vetoers = veto_of(&proposal_hash) .map(|pair| pair.1) .unwrap_or_else(Vec::new); - let insert_position = existing_vetoers.binary_search(signed) + let insert_position = existing_vetoers.binary_search(&self) .expect_err("a councillor may not veto a proposal twice"); - existing_vetoers.insert(insert_position, *signed); + existing_vetoers.insert(insert_position, *self); set_veto_of(&proposal_hash, system::block_number() + cooloff_period(), existing_vetoers); - set_proposals(&proposals().into_iter().filter(|&(_, h)| h != *proposal_hash).collect::>()); + set_proposals(&proposals().into_iter().filter(|&(_, h)| h != proposal_hash).collect::>()); storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_VOTERS)); storage::kill(&proposal_hash.to_keyed_vec(PROPOSAL_OF)); for (c, _) in council::active_council() { - storage::kill(&(*proposal_hash, c).to_keyed_vec(COUNCIL_VOTE_OF)); + storage::kill(&(proposal_hash, c).to_keyed_vec(COUNCIL_VOTE_OF)); } } } -pub mod privileged { - use super::*; +impl_dispatch! { + pub mod privileged; + fn set_cooloff_period(blocks: BlockNumber) = 0; + fn set_voting_period(blocks: BlockNumber) = 1; +} - pub fn set_cooloff_period(blocks: BlockNumber) { +impl privileged::Dispatch for PrivPass { + fn set_cooloff_period(self, blocks: BlockNumber) { storage::put(COOLOFF_PERIOD, &blocks); } - pub fn set_voting_period(blocks: BlockNumber) { + fn set_voting_period(self, blocks: BlockNumber) { storage::put(VOTING_PERIOD, &blocks); } } pub mod internal { use super::*; - use runtime::democracy::privileged::start_referendum; - use demo_primitives::VoteThreshold; + use runtime::democracy::privileged::Dispatch; + use runtime::democracy::VoteThreshold; + use runtime::democracy::internal::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); println!("Executing proposal {:?} {:?}", proposal, tally); - if let &Proposal::DemocracyCancelReferendum(ref_index) = &proposal { + if let &Proposal::Democracy(democracy::privileged::Call::cancel_referendum(ref_index)) = &proposal { if let (_, 0, 0) = tally { - democracy::privileged::cancel_referendum(ref_index); + democracy::privileged::Call::cancel_referendum(ref_index).dispatch(PrivPass); } } else { if tally.0 > tally.1 + tally.2 { @@ -240,7 +252,8 @@ mod tests { use codec::{KeyedVec, Joiner}; use keyring::Keyring::{Alice, Bob, Charlie, Dave}; use environment::with_env; - use demo_primitives::{AccountId, Proposal, VoteThreshold}; + use demo_primitives::AccountId; + use runtime::democracy::VoteThreshold; use runtime::{staking, council, democracy}; fn new_test_ext() -> TestExternalities { @@ -267,11 +280,19 @@ mod tests { }); } + fn sessions_per_era_propsal(value: u64) -> Proposal { + Proposal::Staking(staking::privileged::Call::set_sessions_per_era(value)) + } + + fn bonding_duration_propsal(value: u64) -> Proposal { + Proposal::Staking(staking::privileged::Call::set_bonding_duration(value)) + } + #[test] fn referendum_cancellation_should_work_when_unanimous() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_propsal(42); democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]); diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index 227362818862f..beb184651de53 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -20,13 +20,46 @@ use rstd::prelude::*; use integer_sqrt::IntegerSquareRoot; use codec::{KeyedVec, Slicable, Input, NonTrivialSlicable}; use runtime_support::storage; -use demo_primitives::{Proposal, AccountId, Hash, BlockNumber, VoteThreshold}; +use demo_primitives::{AccountId, Hash, BlockNumber}; +use dispatch::PrivCall as Proposal; use runtime::{staking, system, session}; -use runtime::staking::Balance; +use runtime::system::PrivPass; +use runtime::staking::{PublicPass, Balance}; pub type PropIndex = u32; pub type ReferendumIndex = u32; +#[derive(Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub enum VoteThreshold { + /// A supermajority of approvals is needed to pass this vote. + SuperMajorityApprove, + /// A supermajority of rejects is needed to fail this vote. + SuperMajorityAgainst, + /// A simple majority of approvals is needed to pass this vote. + SimpleMajority, +} + +impl Slicable for VoteThreshold { + fn decode(input: &mut I) -> Option { + u8::decode(input).and_then(|v| match v { + 0 => Some(VoteThreshold::SuperMajorityApprove), + 1 => Some(VoteThreshold::SuperMajorityAgainst), + 2 => Some(VoteThreshold::SimpleMajority), + _ => None, + }) + } + + fn using_encoded R>(&self, f: F) -> R { + match *self { + VoteThreshold::SuperMajorityApprove => 0u8, + VoteThreshold::SuperMajorityAgainst => 1u8, + VoteThreshold::SimpleMajority => 2u8, + }.using_encoded(f) + } +} +impl NonTrivialSlicable for VoteThreshold {} + trait Approved { /// 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 @@ -151,72 +184,87 @@ pub fn next_free_ref_index() -> ReferendumIndex { storage::get_or_default(REFERENDUM_COUNT) } -pub mod public { - use super::*; +pub type BoxedProposal = Box; + +impl_dispatch! { + pub mod public; + fn propose(proposal: Box, value: Balance) = 0; + fn second(proposal: PropIndex) = 1; + fn vote(ref_index: ReferendumIndex, approve_proposal: bool) = 2; +} +impl<'a> public::Dispatch for PublicPass<'a> { /// Propose a sensitive action to be taken. - pub fn propose(signed: &AccountId, proposal: &Proposal, value: Balance) { + fn propose(self, proposal: Box, value: Balance) { assert!(value >= minimum_deposit()); - assert!(staking::internal::deduct_unbonded(signed, value)); + assert!(staking::internal::deduct_unbonded(&self, value)); let index: PropIndex = storage::get_or_default(PUBLIC_PROP_COUNT); storage::put(PUBLIC_PROP_COUNT, &(index + 1)); - storage::put(&index.to_keyed_vec(DEPOSIT_OF), &(value, vec![*signed])); + storage::put(&index.to_keyed_vec(DEPOSIT_OF), &(value, vec![*self])); let mut props = public_props(); - props.push((index, proposal.clone(), *signed)); + props.push((index, (*proposal).clone(), *self)); storage::put(PUBLIC_PROPS, &props); } /// Propose a sensitive action to be taken. - pub fn second(signed: &AccountId, proposal: PropIndex) { + fn second(self, proposal: PropIndex) { let key = proposal.to_keyed_vec(DEPOSIT_OF); let mut deposit: (Balance, Vec) = storage::get(&key).expect("can only second an existing proposal"); - assert!(staking::internal::deduct_unbonded(signed, deposit.0)); + assert!(staking::internal::deduct_unbonded(&self, deposit.0)); - deposit.1.push(*signed); + deposit.1.push(*self); storage::put(&key, &deposit); } /// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal; /// false would be a vote to keep the status quo.. - pub fn vote(signed: &AccountId, ref_index: ReferendumIndex, approve_proposal: bool) { + fn vote(self, ref_index: ReferendumIndex, approve_proposal: bool) { if !is_active_referendum(ref_index) { panic!("vote given for invalid referendum.") } - if staking::balance(signed) == 0 { + if staking::balance(&self) == 0 { panic!("transactor must have balance to signal approval."); } - let key = (*signed, ref_index).to_keyed_vec(VOTE_OF); + let key = (*self, ref_index).to_keyed_vec(VOTE_OF); if !storage::exists(&key) { let mut voters = voters_for(ref_index); - voters.push(signed.clone()); + voters.push(self.clone()); storage::put(&ref_index.to_keyed_vec(VOTERS_FOR), &voters); } storage::put(&key, &approve_proposal); } } -pub mod privileged { - use super::*; +impl_dispatch! { + pub mod privileged; + fn start_referendum(proposal: Box, vote_threshold: VoteThreshold) = 0; + fn cancel_referendum(ref_index: ReferendumIndex) = 1; +} - /// Can be called directly by the council. - pub fn start_referendum(proposal: Proposal, vote_threshold: VoteThreshold) { - inject_referendum(system::block_number() + voting_period(), proposal, vote_threshold); +impl privileged::Dispatch for PrivPass { + /// Start a referendum. + fn start_referendum(self, proposal: Box, vote_threshold: VoteThreshold) { + inject_referendum(system::block_number() + voting_period(), *proposal, vote_threshold); } /// Remove a referendum. - pub fn cancel_referendum(ref_index: ReferendumIndex) { + fn cancel_referendum(self, ref_index: ReferendumIndex) { clear_referendum(ref_index); } } pub mod internal { use super::*; - use demo_primitives::Proposal; use dispatch; + /// Can be called directly by the council. + pub fn start_referendum(proposal: Proposal, vote_threshold: VoteThreshold) { + inject_referendum(system::block_number() + voting_period(), proposal, vote_threshold); + } + /// Current era is ending; we should finish up any proposals. pub fn end_block(now: BlockNumber) { // pick out another public referendum if it's time. @@ -245,7 +293,7 @@ pub mod internal { let total_stake = staking::total_stake(); clear_referendum(index); if vote_threshold.approved(approve, against, total_stake) { - dispatch::proposal(proposal); + proposal.dispatch(PrivPass); } storage::put(NEXT_TALLY, &(index + 1)); } @@ -322,7 +370,11 @@ mod tests { use codec::{KeyedVec, Joiner}; use keyring::Keyring::*; use environment::with_env; - use demo_primitives::{AccountId, Proposal}; + use demo_primitives::AccountId; + use dispatch::PrivCall as Proposal; + use runtime::staking::PublicPass; + use super::public::Dispatch; + use super::privileged::Dispatch as PrivDispatch; use runtime::{staking, session, democracy}; fn new_test_ext() -> TestExternalities { @@ -343,13 +395,18 @@ mod tests { // TODO: test VoteThreshold + fn propose_sessions_per_era(who: &AccountId, value: u64, locked: Balance) { + PublicPass::test(who). + propose(Box::new(Proposal::Staking(staking::privileged::Call::set_sessions_per_era(value))), locked); + } + #[test] fn locked_for_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 2u64); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(4), 4u64); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(3), 3u64); + propose_sessions_per_era(&Alice, 2, 2u64); + propose_sessions_per_era(&Alice, 4, 4u64); + propose_sessions_per_era(&Alice, 3, 3u64); assert_eq!(locked_for(0), Some(2)); assert_eq!(locked_for(1), Some(4)); assert_eq!(locked_for(2), Some(3)); @@ -360,12 +417,12 @@ mod tests { fn single_proposal_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 1u64); + propose_sessions_per_era(&Alice, 2, 1u64); democracy::internal::end_block(system::block_number()); with_env(|e| e.block_number = 2); let r = 0; - public::vote(&Alice, r, true); + PublicPass::test(&Alice).vote(r, true); assert_eq!(next_free_ref_index(), 1); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); @@ -383,11 +440,11 @@ mod tests { fn deposit_for_proposals_should_be_taken() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 5u64); - public::second(&Bob, 0); - public::second(&Eve, 0); - public::second(&Eve, 0); - public::second(&Eve, 0); + propose_sessions_per_era(&Alice, 2, 5u64); + PublicPass::test(&Bob).second(0); + PublicPass::test(&Eve).second(0); + PublicPass::test(&Eve).second(0); + PublicPass::test(&Eve).second(0); assert_eq!(staking::balance(&Alice), 5u64); assert_eq!(staking::balance(&Bob), 15u64); assert_eq!(staking::balance(&Eve), 35u64); @@ -398,11 +455,11 @@ mod tests { fn deposit_for_proposals_should_be_returned() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 5u64); - public::second(&Bob, 0); - public::second(&Eve, 0); - public::second(&Eve, 0); - public::second(&Eve, 0); + propose_sessions_per_era(&Alice, 2, 5u64); + PublicPass::test(&Bob).second(0); + PublicPass::test(&Eve).second(0); + PublicPass::test(&Eve).second(0); + PublicPass::test(&Eve).second(0); democracy::internal::end_block(system::block_number()); assert_eq!(staking::balance(&Alice), 10u64); assert_eq!(staking::balance(&Bob), 20u64); @@ -415,7 +472,7 @@ mod tests { fn proposal_with_deposit_below_minimum_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 0u64); + propose_sessions_per_era(&Alice, 2, 0u64); }); } @@ -424,7 +481,7 @@ mod tests { fn poor_proposer_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetSessionsPerEra(2), 11u64); + propose_sessions_per_era(&Alice, 2, 11u64); }); } @@ -433,46 +490,55 @@ mod tests { fn poor_seconder_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Bob, &Proposal::StakingSetSessionsPerEra(2), 11u64); - public::second(&Alice, 0); + propose_sessions_per_era(&Bob, 2, 11u64); + PublicPass::test(&Alice).second(0); }); } + fn propose_bonding_duration(who: &AccountId, value: u64, locked: Balance) { + PublicPass::test(who). + propose(Box::new(Proposal::Staking(staking::privileged::Call::set_bonding_duration(value))), locked); + } + #[test] fn runners_up_should_come_after() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 0); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(2), 2u64); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(4), 4u64); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(3), 3u64); + propose_bonding_duration(&Alice, 2, 2u64); + propose_bonding_duration(&Alice, 4, 4u64); + propose_bonding_duration(&Alice, 3, 3u64); democracy::internal::end_block(system::block_number()); with_env(|e| e.block_number = 1); - public::vote(&Alice, 0, true); + PublicPass::test(&Alice).vote(0, true); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 4u64); with_env(|e| e.block_number = 2); - public::vote(&Alice, 1, true); + PublicPass::test(&Alice).vote(1, true); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 3u64); with_env(|e| e.block_number = 3); - public::vote(&Alice, 2, true); + PublicPass::test(&Alice).vote(2, true); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); assert_eq!(staking::bonding_duration(), 2u64); }); } + fn sessions_per_era_propsal(value: u64) -> Proposal { + Proposal::Staking(staking::privileged::Call::set_sessions_per_era(value)) + } + #[test] fn simple_passing_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Alice, r, true); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Alice).vote(r, true); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); assert_eq!(vote_of(&Alice, r), Some(true)); @@ -489,9 +555,9 @@ mod tests { fn cancel_referendum_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Alice, r, true); - privileged::cancel_referendum(r); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Alice).vote(r, true); + PrivPass.cancel_referendum(r); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); @@ -504,8 +570,8 @@ mod tests { fn simple_failing_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Alice, r, false); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Alice).vote(r, false); assert_eq!(voters_for(r), vec![Alice.to_raw_public()]); assert_eq!(vote_of(&Alice, r), Some(false)); @@ -522,13 +588,13 @@ mod tests { fn controversial_voting_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Alice, r, true); - public::vote(&Bob, r, false); - public::vote(&Charlie, r, false); - public::vote(&Dave, r, true); - public::vote(&Eve, r, false); - public::vote(&Ferdie, r, true); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Alice).vote(r, true); + PublicPass::test(&Bob).vote(r, false); + PublicPass::test(&Charlie).vote(r, false); + PublicPass::test(&Dave).vote(r, true); + PublicPass::test(&Eve).vote(r, false); + PublicPass::test(&Ferdie).vote(r, true); assert_eq!(tally(r), (110, 100)); @@ -543,9 +609,9 @@ mod tests { fn controversial_low_turnout_voting_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Eve, r, false); - public::vote(&Ferdie, r, true); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Eve).vote(r, false); + PublicPass::test(&Ferdie).vote(r, true); assert_eq!(tally(r), (60, 50)); @@ -563,10 +629,10 @@ mod tests { assert_eq!(staking::total_stake(), 210u64); with_env(|e| e.block_number = 1); - let r = inject_referendum(1, Proposal::StakingSetSessionsPerEra(2), VoteThreshold::SuperMajorityApprove); - public::vote(&Dave, r, true); - public::vote(&Eve, r, false); - public::vote(&Ferdie, r, true); + let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); + PublicPass::test(&Dave).vote(r, true); + PublicPass::test(&Eve).vote(r, false); + PublicPass::test(&Ferdie).vote(r, true); assert_eq!(tally(r), (100, 50)); diff --git a/demo/runtime/src/runtime/staking.rs b/demo/runtime/src/runtime/staking.rs index 6a30a743142a3..8fa92dd76ec16 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -17,11 +17,11 @@ //! Staking manager: Handles balances and periodically determines the best set of validators. use rstd::prelude::*; -use rstd::cmp; +use rstd::{ops, cmp}; use rstd::cell::RefCell; use rstd::collections::btree_map::{BTreeMap, Entry}; use runtime_io::{print, blake2_256}; -use codec::KeyedVec; +use codec::{Slicable, Input, KeyedVec}; use runtime_support::{storage, StorageVec}; use demo_primitives::{BlockNumber, AccountId}; use runtime::{system, session}; @@ -41,6 +41,7 @@ pub const LAST_ERA_LENGTH_CHANGE: &[u8] = b"sta:lec"; pub const TOTAL_STAKE: &[u8] = b"sta:tot"; pub const INTENTION_AT: &[u8] = b"sta:wil:"; pub const INTENTION_COUNT: &[u8] = b"sta:wil:len"; +pub const TRANSACTION_FEE: &[u8] = b"sta:fee"; pub const BALANCE_OF: &[u8] = b"sta:bal:"; pub const RESERVED_BALANCE_OF: &[u8] = b"sta:lbo:"; @@ -54,6 +55,11 @@ impl StorageVec for IntentionStorageVec { const PREFIX: &'static[u8] = INTENTION_AT; } +/// The fee to be paid for making a transaction. +pub fn transaction_fee() -> Balance { + storage::get(TRANSACTION_FEE).expect("All basic parameters should be defined") +} + /// The length of the bonding duration in eras. pub fn bonding_duration() -> BlockNumber { storage::get_or_default(BONDING_DURATION) @@ -133,17 +139,131 @@ pub fn total_stake() -> Balance { storage::get_or(TOTAL_STAKE, 0) } +pub struct PublicPass<'a> (&'a AccountId); + +const NOBODY: AccountId = [0u8; 32]; + +impl<'a> PublicPass<'a> { + pub fn new(transactor: &AccountId) -> PublicPass { + let b = free_balance(&transactor); + let transaction_fee = transaction_fee(); + assert!(b >= transaction_fee, "attempt to transact without enough funds to pay fee"); + internal::set_free_balance(&transactor, b - transaction_fee); + PublicPass(transactor) + } + + #[cfg(test)] + pub fn test(signed: &AccountId) -> PublicPass { + PublicPass(signed) + } + + #[cfg(test)] + pub fn nobody() -> PublicPass<'static> { + PublicPass(&NOBODY) + } + + /// Create a smart-contract account. + pub fn create(self, code: &[u8], value: Balance) { + // commit anything that made it this far to storage + if let Some(commit) = private::effect_create(self.0, code, value, private::DirectExt) { + private::commit_state(commit); + } + } +} + +impl<'a> ops::Deref for PublicPass<'a> { + type Target = AccountId; + fn deref(&self) -> &AccountId { + self.0 + } +} + +impl_dispatch! { + pub mod public; + fn transfer(dest: AccountId, value: Balance) = 0; + fn stake() = 1; + fn unstake() = 2; +} + +impl<'a> public::Dispatch for PublicPass<'a> { + /// Transfer some unlocked staking balance to another staker. + /// TODO: probably want to state gas-limit and gas-price. + fn transfer(self, dest: AccountId, value: Balance) { + // commit anything that made it this far to storage + if let Some(commit) = private::effect_transfer(&self, &dest, value, private::DirectExt) { + private::commit_state(commit); + } + } + + /// Declare the desire to stake for the transactor. + /// + /// Effects will be felt at the beginning of the next era. + fn stake(self) { + let mut intentions = IntentionStorageVec::items(); + // can't be in the list twice. + assert!(intentions.iter().find(|&t| *t == *self).is_none(), "Cannot stake if already staked."); + intentions.push(self.clone()); + IntentionStorageVec::set_items(&intentions); + storage::put(&self.to_keyed_vec(BONDAGE_OF), &u64::max_value()); + } + + /// Retract the desire to stake for the transactor. + /// + /// Effects will be felt at the beginning of the next era. + fn unstake(self) { + let mut intentions = IntentionStorageVec::items(); + if let Some(position) = intentions.iter().position(|&t| t == *self) { + intentions.swap_remove(position); + } else { + panic!("Cannot unstake if not already staked."); + } + IntentionStorageVec::set_items(&intentions); + storage::put(&self.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration())); + } +} + +impl_dispatch! { + pub mod privileged; + fn set_sessions_per_era(new: BlockNumber) = 0; + fn set_bonding_duration(new: BlockNumber) = 1; + fn set_validator_count(new: u32) = 2; + fn force_new_era() = 3; +} + +impl privileged::Dispatch for system::PrivPass { + /// Set the number of sessions in an era. + fn set_sessions_per_era(self, new: BlockNumber) { + storage::put(NEXT_SESSIONS_PER_ERA, &new); + } + + /// The length of the bonding duration in eras. + fn set_bonding_duration(self, new: BlockNumber) { + storage::put(BONDING_DURATION, &new); + } + + /// The length of a staking era in sessions. + fn set_validator_count(self, new: u32) { + storage::put(VALIDATOR_COUNT, &new); + } + + /// Force there to be a new era. This also forces a new session immediately after. + fn force_new_era(self) { + new_era(); + session::privileged::force_new_session(); + } +} + // Each identity's stake may be in one of three bondage states, given by an integer: // - n | n <= current_era(): inactive: free to be transferred. // - ~0: active: currently representing a validator. // - n | n > current_era(): deactivating: recently representing a validator and not yet // ready for transfer. -pub mod public { +mod private { use super::*; #[derive(Default)] - struct ChangeEntry { + pub struct ChangeEntry { balance: Option, code: Option>, storage: BTreeMap, Option>>, @@ -157,7 +277,7 @@ pub mod public { type State = BTreeMap; - trait Externalities { + pub trait Externalities { fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option>; fn get_code(&self, account: &AccountId) -> Vec; fn get_balance(&self, account: &AccountId) -> Balance; @@ -173,7 +293,7 @@ pub mod public { do_get_balance: F5, } - struct DirectExt; + pub struct DirectExt; impl Externalities for DirectExt { fn get_storage(&self, account: &AccountId, location: &[u8]) -> Option> { let mut v = account.to_keyed_vec(STORAGE_OF); @@ -204,7 +324,7 @@ pub mod public { } } - fn commit_state(s: State) { + pub fn commit_state(s: State) { for (address, changed) in s.into_iter() { if let Some(balance) = changed.balance { storage::put(&address.to_keyed_vec(BALANCE_OF), &balance); @@ -245,15 +365,7 @@ pub mod public { } } - /// Create a smart-contract account. - pub fn create(transactor: &AccountId, code: &[u8], value: Balance) { - // commit anything that made it this far to storage - if let Some(commit) = effect_create(transactor, code, value, DirectExt) { - commit_state(commit); - } - } - - fn effect_create( + pub fn effect_create( transactor: &AccountId, code: &[u8], value: Balance, @@ -282,16 +394,7 @@ pub mod public { Some(local) } - /// Transfer some unlocked staking balance to another staker. - /// TODO: probably want to state gas-limit and gas-price. - pub fn transfer(transactor: &AccountId, dest: &AccountId, value: Balance) { - // commit anything that made it this far to storage - if let Some(commit) = effect_transfer(transactor, dest, value, DirectExt) { - commit_state(commit); - } - } - - fn effect_transfer( + pub fn effect_transfer( transactor: &AccountId, dest: &AccountId, value: Balance, @@ -362,57 +465,6 @@ pub mod public { None } } - - /// Declare the desire to stake for the transactor. - /// - /// Effects will be felt at the beginning of the next era. - pub fn stake(transactor: &AccountId) { - let mut intentions = IntentionStorageVec::items(); - // can't be in the list twice. - assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked."); - intentions.push(transactor.clone()); - IntentionStorageVec::set_items(&intentions); - storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value()); - } - - /// Retract the desire to stake for the transactor. - /// - /// Effects will be felt at the beginning of the next era. - pub fn unstake(transactor: &AccountId) { - let mut intentions = IntentionStorageVec::items(); - if let Some(position) = intentions.iter().position(|t| t == transactor) { - intentions.swap_remove(position); - } else { - panic!("Cannot unstake if not already staked."); - } - IntentionStorageVec::set_items(&intentions); - storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration())); - } -} - -pub mod privileged { - use super::*; - - /// Set the number of sessions in an era. - pub fn set_sessions_per_era(new: BlockNumber) { - storage::put(NEXT_SESSIONS_PER_ERA, &new); - } - - /// The length of the bonding duration in eras. - pub fn set_bonding_duration(new: BlockNumber) { - storage::put(BONDING_DURATION, &new); - } - - /// The length of a staking era in sessions. - pub fn set_validator_count(new: u32) { - storage::put(VALIDATOR_COUNT, &new); - } - - /// Force there to be a new era. This also forces a new session immediately after. - pub fn force_new_era() { - new_era(); - session::privileged::force_new_session(); - } } pub mod internal { @@ -540,6 +592,8 @@ pub mod testing { use codec::{Joiner, KeyedVec}; use keyring::Keyring::*; use runtime::session; + use super::public::{Call, Dispatch}; + use super::privileged::{Dispatch as PrivDispatch, Call as PrivCall}; pub fn externalities(session_length: u64, sessions_per_era: u64, current_era: u64) -> TestExternalities { let extras: TestExternalities = map![ @@ -560,7 +614,6 @@ pub mod testing { mod tests { use super::*; use super::internal::*; - use super::public::*; use super::privileged::*; use runtime_io::{with_externalities, twox_128, TestExternalities}; @@ -569,6 +622,9 @@ mod tests { use environment::with_env; use demo_primitives::AccountId; use runtime::{staking, session}; + use runtime::system::PrivPass; + use runtime::staking::public::{Call, Dispatch}; + use runtime::staking::privileged::{Call as PCall, Dispatch as PDispatch}; #[test] fn staking_should_work() { @@ -595,9 +651,9 @@ mod tests { // Block 1: Add three validators. No obvious change. with_env(|e| e.block_number = 1); - stake(&Alice); - stake(&Bob); - stake(&Dave); + public::Call::stake().dispatch(PublicPass::new(&Alice)); + PublicPass::new(&Bob).stake(); + PublicPass::new(&Dave).stake(); check_new_era(); assert_eq!(session::validators(), vec![[10u8; 32], [20u8; 32]]); @@ -608,8 +664,8 @@ mod tests { // Block 3: Unstake highest, introduce another staker. No change yet. with_env(|e| e.block_number = 3); - stake(&Charlie); - unstake(&Dave); + PublicPass::new(&Charlie).stake(); + PublicPass::new(&Dave).unstake(); check_new_era(); // Block 4: New era - validators change. @@ -619,7 +675,7 @@ mod tests { // Block 5: Transfer stake from highest to lowest. No change yet. with_env(|e| e.block_number = 5); - transfer(&Dave, &Alice, 40); + PublicPass::new(&Dave).transfer(Alice.to_raw_public(), 40); check_new_era(); // Block 6: Lowest now validator. @@ -629,7 +685,7 @@ mod tests { // Block 7: Unstake three. No change yet. with_env(|e| e.block_number = 7); - unstake(&Charlie); + PublicPass::new(&Charlie).unstake(); check_new_era(); assert_eq!(session::validators(), vec![Alice.to_raw_public(), Charlie.into()]); @@ -668,7 +724,7 @@ mod tests { // Block 3: Schedule an era length change; no visible changes. with_env(|e| e.block_number = 3); - set_sessions_per_era(3); + PrivPass.set_sessions_per_era(3); check_new_era(); assert_eq!(sessions_per_era(), 2u64); assert_eq!(last_era_length_change(), 0u64); @@ -721,7 +777,7 @@ mod tests { fn staking_balance_transfer_works() { with_externalities(&mut TestExternalities::default(), || { set_free_balance(&Alice, 111); - transfer(&Alice, &Bob, 69); + PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); assert_eq!(balance(&Alice), 42); assert_eq!(balance(&Bob), 69); }); @@ -732,8 +788,8 @@ mod tests { fn staking_balance_transfer_when_bonded_panics() { with_externalities(&mut TestExternalities::default(), || { set_free_balance(&Alice, 111); - stake(&Alice); - transfer(&Alice, &Bob, 69); + PublicPass::new(&Alice).stake(); + PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); }); } @@ -760,7 +816,7 @@ mod tests { with_externalities(&mut TestExternalities::default(), || { set_free_balance(&Alice, 111); reserve_balance(&Alice, 69); - transfer(&Alice, &Bob, 69); + PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); }); } diff --git a/demo/runtime/src/runtime/system.rs b/demo/runtime/src/runtime/system.rs index 4add4dd146403..149a0a89807ee 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -23,8 +23,9 @@ use runtime_io::{print, storage_root, enumerated_trie_root}; use codec::{KeyedVec, Slicable}; use runtime_support::{Hashable, storage}; use environment::with_env; -use demo_primitives::{AccountId, Hash, TxOrder, BlockNumber, Block, Header, - UncheckedTransaction, Function, Log}; +use demo_primitives::{AccountId, Hash, TxOrder, BlockNumber, Header, Log}; +use block::Block; +use transaction::UncheckedTransaction; use runtime::{staking, session}; use dispatch; @@ -32,6 +33,7 @@ pub const NONCE_OF: &[u8] = b"sys:non:"; pub const BLOCK_HASH_AT: &[u8] = b"sys:old:"; pub const CODE: &[u8] = b"sys:cod"; + /// The current block number being processed. Set by `execute_block`. pub fn block_number() -> BlockNumber { with_env(|e| e.block_number) @@ -42,6 +44,8 @@ pub fn block_hash(number: BlockNumber) -> Hash { storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT)) } +pub struct PrivPass; + pub mod privileged { use super::*; @@ -137,16 +141,19 @@ fn execute_transaction(utx: UncheckedTransaction) { Err(_) => panic!("All transactions should be properly signed"), }; - // check nonce - let nonce_key = tx.signed.to_keyed_vec(NONCE_OF); - let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0); - assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); + { + // check nonce + let nonce_key = tx.signed.to_keyed_vec(NONCE_OF); + let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0); + assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); - // increment nonce in storage - storage::put(&nonce_key, &(expected_nonce + 1)); + // increment nonce in storage + storage::put(&nonce_key, &(expected_nonce + 1)); + } // decode parameters and dispatch - dispatch::function(&tx.function, &tx.signed); + let tx = tx.drain().transaction; + tx.function.dispatch(staking::PublicPass::new(&tx.signed)); } fn initial_checks(block: &Block) { @@ -226,8 +233,11 @@ mod tests { use keyring::Keyring::*; use environment::with_env; use primitives::hexdisplay::HexDisplay; - use demo_primitives::{Header, Digest, UncheckedTransaction, Transaction, Function}; + use demo_primitives::{Header, Digest}; + use transaction::{UncheckedTransaction, Transaction}; use runtime::staking; + use dispatch::public::Call as PubCall; + use runtime::staking::public::Call as StakingCall; #[test] fn staking_balance_transfer_dispatch_works() { @@ -239,7 +249,7 @@ mod tests { transaction: Transaction { signed: One.into(), nonce: 0, - function: Function::StakingTransfer(Two.into(), 69), + function: PubCall::Staking(StakingCall::transfer(Two.into(), 69)), }, signature: hex!("5f9832c5a4a39e2dd4a3a0c5b400e9836beb362cb8f7d845a8291a2ae6fe366612e080e4acd0b5a75c3d0b6ee69614a68fb63698c1e76bf1f2dcd8fa617ddf05").into(), }; diff --git a/demo/runtime/src/runtime/timestamp.rs b/demo/runtime/src/runtime/timestamp.rs index 52b6cbe2d7d18..ff2c18b9bd4ba 100644 --- a/demo/runtime/src/runtime/timestamp.rs +++ b/demo/runtime/src/runtime/timestamp.rs @@ -17,6 +17,7 @@ //! Timestamp manager: just handles the current timestamp. use runtime_support::storage; +use runtime::staking::PublicPass; pub type Timestamp = u64; @@ -27,11 +28,14 @@ pub fn get() -> Timestamp { storage::get_or_default(CURRENT_TIMESTAMP) } -pub mod public { - use super::*; +impl_dispatch! { + pub mod public; + fn set(now: Timestamp) = 0; +} +impl<'a> public::Dispatch for PublicPass<'a> { /// Set the current time. - pub fn set(now: Timestamp) { + fn set(self, now: Timestamp) { storage::put(CURRENT_TIMESTAMP, &now); } } @@ -44,6 +48,8 @@ mod tests { use runtime_io::{with_externalities, twox_128, TestExternalities}; use runtime::timestamp; use codec::{Joiner, KeyedVec}; + use demo_primitives::AccountId; + use runtime::staking::PublicPass; #[test] fn timestamp_works() { @@ -53,7 +59,7 @@ mod tests { with_externalities(&mut t, || { assert_eq!(get(), 42); - set(69); + PublicPass::nobody().set(69); assert_eq!(get(), 69); }); } diff --git a/demo/runtime/src/transaction.rs b/demo/runtime/src/transaction.rs new file mode 100644 index 0000000000000..06b95148c805c --- /dev/null +++ b/demo/runtime/src/transaction.rs @@ -0,0 +1,190 @@ +// 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 . + +//! Transaction type. + +use rstd::vec::Vec; +use rstd::ops; +use codec::{Input, Slicable, NonTrivialSlicable}; +use demo_primitives::{AccountId, TxOrder, SessionKey, Signature}; +use dispatch::PubCall; + +#[cfg(feature = "std")] +use std::fmt; + +use block::Number as BlockNumber; + +/// A vetted and verified transaction from the external world. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +pub struct Transaction { + /// Who signed it (note this is not a signature). + pub signed: AccountId, + /// The number of transactions have come before from the same signer. + pub nonce: TxOrder, + /// The function that should be called. + pub function: PubCall, +} + +impl Slicable for Transaction { + fn decode(input: &mut I) -> Option { + Some(Transaction { + signed: try_opt!(Slicable::decode(input)), + nonce: try_opt!(Slicable::decode(input)), + function: try_opt!(Slicable::decode(input)), + }) + } + + fn encode(&self) -> Vec { + let mut v = Vec::new(); + + self.signed.using_encoded(|s| v.extend(s)); + self.nonce.using_encoded(|s| v.extend(s)); + self.function.using_encoded(|s| v.extend(s)); + + v + } +} + +impl ::codec::NonTrivialSlicable for Transaction {} + +/// A transactions right from the external world. Unchecked. +#[derive(Eq, Clone)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct UncheckedTransaction { + /// The actual transaction information. + pub transaction: Transaction, + /// The signature; should be an Ed25519 signature applied to the serialised `transaction` field. + pub signature: Signature, +} + +impl Slicable for UncheckedTransaction { + fn decode(input: &mut I) -> Option { + // This is a little more complicated than usual since the binary format must be compatible + // with substrate's generic `Vec` type. Basically this just means accepting that there + // will be a prefix of u32, which has the total number of bytes following (we don't need + // to use this). + let _length_do_not_remove_me_see_above: u32 = try_opt!(Slicable::decode(input)); + + Some(UncheckedTransaction { + transaction: try_opt!(Slicable::decode(input)), + signature: try_opt!(Slicable::decode(input)), + }) + } + + fn encode(&self) -> Vec { + let mut v = Vec::new(); + + // need to prefix with the total length as u32 to ensure it's binary comptible with + // Vec. we'll make room for it here, then overwrite once we know the length. + v.extend(&[0u8; 4]); + + self.transaction.signed.using_encoded(|s| v.extend(s)); + self.transaction.nonce.using_encoded(|s| v.extend(s)); + self.transaction.function.using_encoded(|s| v.extend(s)); + self.signature.using_encoded(|s| v.extend(s)); + + let length = (v.len() - 4) as u32; + length.using_encoded(|s| v[0..4].copy_from_slice(s)); + + v + } +} + +impl ::codec::NonTrivialSlicable for UncheckedTransaction {} + +impl PartialEq for UncheckedTransaction { + fn eq(&self, other: &Self) -> bool { + self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction + } +} + +#[cfg(feature = "std")] +impl fmt::Debug for UncheckedTransaction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UncheckedTransaction({:?})", self.transaction) + } +} + +/// A type-safe indicator that a transaction has been checked. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct CheckedTransaction(UncheckedTransaction); + +impl CheckedTransaction { + /// Get a reference to the checked signature. + pub fn signature(&self) -> &Signature { + &self.0.signature + } + + /// Get the inner object. + pub fn drain(self) -> UncheckedTransaction { + self.0 + } +} + +impl ops::Deref for CheckedTransaction { + type Target = Transaction; + + fn deref(&self) -> &Transaction { + &self.0.transaction + } +} + +/// Check the signature on a transaction. +/// +/// On failure, return the transaction back. +pub fn check(tx: UncheckedTransaction) -> Result { + let msg = ::codec::Slicable::encode(&tx.transaction); + if ::runtime_io::ed25519_verify(&tx.signature.0, &msg, &tx.transaction.signed) { + Ok(CheckedTransaction(tx)) + } else { + Err(tx) + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use primitives; + use codec::Slicable; + use primitives::hexdisplay::HexDisplay; + use dispatch::public::Call; + use runtime::timestamp::public::Call as TimestampCall; + + #[test] + fn serialize_unchecked() { + let tx = UncheckedTransaction { + transaction: Transaction { + signed: [1; 32], + nonce: 999u64, + function: Call::Timestamp(TimestampCall::set(135135)), + }, + signature: primitives::hash::H512([0; 64]), + }; + // 71000000 + // 0101010101010101010101010101010101010101010101010101010101010101 + // e703000000000000 + // 00 + // df0f0200 + // 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + + let v = Slicable::encode(&tx); + println!("{}", HexDisplay::from(&v)); + assert_eq!(UncheckedTransaction::decode(&mut &v[..]).unwrap(), tx); + } +} diff --git a/substrate/codec/src/slicable.rs b/substrate/codec/src/slicable.rs index eb2b01db52fc8..e473c0bf5e18c 100644 --- a/substrate/codec/src/slicable.rs +++ b/substrate/codec/src/slicable.rs @@ -19,7 +19,6 @@ use rstd::{mem, slice}; use rstd::vec::Vec; use super::joiner::Joiner; -use super::endiansensitive::EndianSensitive; /// Trait that allows reading of data into a slice. pub trait Input { @@ -56,39 +55,6 @@ pub trait Slicable: Sized { // TODO: under specialization, remove this and simply specialize in place serializable types. pub trait NonTrivialSlicable: Slicable {} -impl Slicable for T { - fn decode(input: &mut I) -> Option { - let size = mem::size_of::(); - assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type."); - let mut val: T = unsafe { mem::zeroed() }; - - unsafe { - let raw: &mut [u8] = slice::from_raw_parts_mut( - &mut val as *mut T as *mut u8, - size - ); - if input.read(raw) != size { return None } - } - Some(val.from_le()) - } - - fn using_encoded R>(&self, f: F) -> R { - self.as_le_then(|le| { - let size = mem::size_of::(); - let value_slice = unsafe { - let ptr = le as *const _ as *const u8; - if size != 0 { - slice::from_raw_parts(ptr, size) - } else { - &[] - } - }; - - f(value_slice) - }) - } -} - impl Slicable for Option { fn decode(input: &mut I) -> Option { u8::decode(input).and_then(|v| match v { @@ -109,6 +75,16 @@ impl Slicable for Option { } impl NonTrivialSlicable for Option {} +impl Slicable for Box { + fn decode(input: &mut I) -> Option { + Some(Box::new(T::decode(input)?)) + } + + fn using_encoded R>(&self, f: F) -> R { + (*self).using_encoded(f) + } +} + impl Slicable for Vec { fn decode(input: &mut I) -> Option { u32::decode(input).and_then(move |len| { @@ -173,7 +149,7 @@ macro_rules! impl_vec_simple_array { ($($size:expr),*) => { $( impl Slicable for Vec<[T; $size]> - where [T; $size]: EndianSensitive + where [T; $size]: EndianSensitive + Slicable { fn decode(input: &mut I) -> Option { u32::decode(input).and_then(move |len| { @@ -325,6 +301,108 @@ mod inner_tuple_impl { tuple_impl!(A, B, C, D, E, F, G, H, I, J, K,); } +/// Trait to allow conversion to a know endian representation when sensitive. +/// Types implementing this trait must have a size > 0. +// note: the copy bound and static lifetimes are necessary for safety of `Slicable` blanket +// implementation. +trait EndianSensitive: Copy + 'static { + fn to_le(self) -> Self { self } + fn to_be(self) -> Self { self } + fn from_le(self) -> Self { self } + fn from_be(self) -> Self { self } + fn as_be_then T>(&self, f: F) -> T { f(&self) } + fn as_le_then T>(&self, f: F) -> T { f(&self) } +} + +macro_rules! impl_endians { + ( $( $t:ty ),* ) => { $( + impl EndianSensitive for $t { + fn to_le(self) -> Self { <$t>::to_le(self) } + fn to_be(self) -> Self { <$t>::to_be(self) } + fn from_le(self) -> Self { <$t>::from_le(self) } + fn from_be(self) -> Self { <$t>::from_be(self) } + fn as_be_then T>(&self, f: F) -> T { let d = self.to_be(); f(&d) } + fn as_le_then T>(&self, f: F) -> T { let d = self.to_le(); f(&d) } + } + + impl Slicable for $t { + fn decode(input: &mut I) -> Option { + let size = mem::size_of::<$t>(); + assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type."); + let mut val: $t = unsafe { mem::zeroed() }; + + unsafe { + let raw: &mut [u8] = slice::from_raw_parts_mut( + &mut val as *mut $t as *mut u8, + size + ); + if input.read(raw) != size { return None } + } + Some(val.from_le()) + } + + fn using_encoded R>(&self, f: F) -> R { + self.as_le_then(|le| { + let size = mem::size_of::<$t>(); + let value_slice = unsafe { + let ptr = le as *const _ as *const u8; + if size != 0 { + slice::from_raw_parts(ptr, size) + } else { + &[] + } + }; + + f(value_slice) + }) + } + } + )* } +} +macro_rules! impl_non_endians { + ( $( $t:ty ),* ) => { $( + impl EndianSensitive for $t {} + + impl Slicable for $t { + fn decode(input: &mut I) -> Option { + let size = mem::size_of::<$t>(); + assert!(size > 0, "EndianSensitive can never be implemented for a zero-sized type."); + let mut val: $t = unsafe { mem::zeroed() }; + + unsafe { + let raw: &mut [u8] = slice::from_raw_parts_mut( + &mut val as *mut $t as *mut u8, + size + ); + if input.read(raw) != size { return None } + } + Some(val.from_le()) + } + + fn using_encoded R>(&self, f: F) -> R { + self.as_le_then(|le| { + let size = mem::size_of::<$t>(); + let value_slice = unsafe { + let ptr = le as *const _ as *const u8; + if size != 0 { + slice::from_raw_parts(ptr, size) + } else { + &[] + } + }; + + f(value_slice) + }) + } + } + )* } +} + +impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize); +impl_non_endians!(u8, i8, [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], + [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], + [u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128], bool); + #[cfg(test)] mod tests { From 82a178d4e1e8a0ee9ddfb4056b8b8f9f2bc58bfd Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 13 Mar 2018 12:46:06 +0100 Subject: [PATCH 02/13] Council vote tests. --- demo/runtime/src/runtime/council_vote.rs | 126 ++++++++++++----------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/demo/runtime/src/runtime/council_vote.rs b/demo/runtime/src/runtime/council_vote.rs index 19e3ddae20c70..4f96adbaa1157 100644 --- a/demo/runtime/src/runtime/council_vote.rs +++ b/demo/runtime/src/runtime/council_vote.rs @@ -255,6 +255,8 @@ mod tests { use demo_primitives::AccountId; use runtime::democracy::VoteThreshold; use runtime::{staking, council, democracy}; + use super::public::Dispatch; + use super::privileged::Dispatch as PrivDispatch; fn new_test_ext() -> TestExternalities { testing::externalities() @@ -280,27 +282,31 @@ mod tests { }); } - fn sessions_per_era_propsal(value: u64) -> Proposal { + fn sessions_per_era_proposal(value: u64) -> Proposal { Proposal::Staking(staking::privileged::Call::set_sessions_per_era(value)) } - fn bonding_duration_propsal(value: u64) -> Proposal { + fn bonding_duration_proposal(value: u64) -> Proposal { Proposal::Staking(staking::privileged::Call::set_bonding_duration(value)) } + fn cancel_referendum_proposal(id: u32) -> Proposal { + Proposal::Democracy(democracy::privileged::Call::cancel_referendum(id)) + } + #[test] fn referendum_cancellation_should_work_when_unanimous() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = bonding_duration_propsal(42); - democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + let proposal = bonding_duration_proposal(42); + democracy::internal::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); assert_eq!(democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]); - let cancellation = Proposal::DemocracyCancelReferendum(0); + let cancellation = cancel_referendum_proposal(0); let hash = cancellation.blake2_256(); - public::propose(&Alice, &cancellation); - public::vote(&Bob, &hash, true); - public::vote(&Charlie, &hash, true); + PublicPass::new(&Alice).propose(Box::new(cancellation)); + PublicPass::new(&Bob).vote(hash, true); + PublicPass::new(&Charlie).vote(hash, true); assert_eq!(proposals(), vec![(2, hash)]); internal::end_block(1); @@ -315,14 +321,14 @@ mod tests { fn referendum_cancellation_should_fail_when_not_unanimous() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); - democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + let proposal = bonding_duration_proposal(42); + democracy::internal::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); - let cancellation = Proposal::DemocracyCancelReferendum(0); + let cancellation = cancel_referendum_proposal(0); let hash = cancellation.blake2_256(); - public::propose(&Alice, &cancellation); - public::vote(&Bob, &hash, true); - public::vote(&Charlie, &hash, false); + PublicPass::new(&Alice).propose(Box::new(cancellation)); + PublicPass::new(&Bob).vote(hash, true); + PublicPass::new(&Charlie).vote(hash, false); internal::end_block(1); with_env(|e| e.block_number = 2); @@ -335,13 +341,13 @@ mod tests { fn referendum_cancellation_should_fail_when_abstentions() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); - democracy::privileged::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); + let proposal = bonding_duration_proposal(42); + democracy::internal::start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove); - let cancellation = Proposal::DemocracyCancelReferendum(0); + let cancellation = cancel_referendum_proposal(0); let hash = cancellation.blake2_256(); - public::propose(&Alice, &cancellation); - public::vote(&Bob, &hash, true); + PublicPass::new(&Alice).propose(Box::new(cancellation)); + PublicPass::new(&Bob).vote(hash, true); internal::end_block(1); with_env(|e| e.block_number = 2); @@ -354,10 +360,10 @@ mod tests { fn veto_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); assert_eq!(proposals().len(), 0); assert_eq!(democracy::active_referendums().len(), 0); }); @@ -368,14 +374,14 @@ mod tests { fn double_veto_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); with_env(|e| e.block_number = 3); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); }); } @@ -384,13 +390,13 @@ mod tests { fn retry_in_cooloff_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); with_env(|e| e.block_number = 2); - public::propose(&Alice, &proposal); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); }); } @@ -398,21 +404,21 @@ mod tests { fn retry_after_cooloff_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); with_env(|e| e.block_number = 3); - public::propose(&Alice, &proposal); - public::vote(&Bob, &hash, false); - public::vote(&Charlie, &hash, true); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).vote(hash, false); + PublicPass::new(&Charlie).vote(hash, true); internal::end_block(3); with_env(|e| e.block_number = 4); internal::end_block(4); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 7, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); + assert_eq!(democracy::active_referendums(), vec![(0, 7, bonding_duration_proposal(42), VoteThreshold::SimpleMajority)]); }); } @@ -420,14 +426,14 @@ mod tests { fn alternative_double_veto_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); - public::veto(&Bob, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).veto(hash); with_env(|e| e.block_number = 3); - public::propose(&Alice, &proposal); - public::veto(&Charlie, &hash); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Charlie).veto(hash); assert_eq!(proposals().len(), 0); assert_eq!(democracy::active_referendums().len(), 0); }); @@ -437,9 +443,9 @@ mod tests { fn simple_propose_should_work() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - let proposal = Proposal::StakingSetBondingDuration(42); + let proposal = bonding_duration_proposal(42); let hash = proposal.blake2_256(); - public::propose(&Alice, &proposal); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); assert_eq!(proposals().len(), 1); assert_eq!(proposal_voters(&hash), vec![Alice.to_raw_public()]); assert_eq!(vote_of(&Alice, &hash), Some(true)); @@ -451,8 +457,9 @@ mod tests { fn unvoted_proposal_should_expire_without_action() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(42)); - assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (1, 0, 2)); + let proposal = bonding_duration_proposal(42); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + assert_eq!(tally(&proposal.blake2_256()), (1, 0, 2)); internal::end_block(1); with_env(|e| e.block_number = 2); @@ -466,16 +473,17 @@ mod tests { fn unanimous_proposal_should_expire_with_biased_referendum() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(42)); - public::vote(&Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true); - public::vote(&Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), true); - assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (3, 0, 0)); + let proposal = bonding_duration_proposal(42); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).vote(proposal.blake2_256(), true); + PublicPass::new(&Charlie).vote(proposal.blake2_256(), true); + assert_eq!(tally(&proposal.blake2_256()), (3, 0, 0)); internal::end_block(1); with_env(|e| e.block_number = 2); internal::end_block(2); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SuperMajorityAgainst)]); + assert_eq!(democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SuperMajorityAgainst)]); }); } @@ -483,16 +491,17 @@ mod tests { fn majority_proposal_should_expire_with_unbiased_referendum() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Alice, &Proposal::StakingSetBondingDuration(42)); - public::vote(&Bob, &Proposal::StakingSetBondingDuration(42).blake2_256(), true); - public::vote(&Charlie, &Proposal::StakingSetBondingDuration(42).blake2_256(), false); - assert_eq!(tally(&Proposal::StakingSetBondingDuration(42).blake2_256()), (2, 1, 0)); + let proposal = bonding_duration_proposal(42); + PublicPass::new(&Alice).propose(Box::new(proposal.clone())); + PublicPass::new(&Bob).vote(proposal.blake2_256(), true); + PublicPass::new(&Charlie).vote(proposal.blake2_256(), false); + assert_eq!(tally(&proposal.blake2_256()), (2, 1, 0)); internal::end_block(1); with_env(|e| e.block_number = 2); internal::end_block(2); assert_eq!(proposals().len(), 0); - assert_eq!(democracy::active_referendums(), vec![(0, 5, Proposal::StakingSetBondingDuration(42), VoteThreshold::SimpleMajority)]); + assert_eq!(democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SimpleMajority)]); }); } @@ -501,7 +510,8 @@ mod tests { fn propose_by_public_should_panic() { with_externalities(&mut new_test_ext(), || { with_env(|e| e.block_number = 1); - public::propose(&Dave, &Proposal::StakingSetBondingDuration(42)); + let proposal = bonding_duration_proposal(42); + PublicPass::new(&Dave).propose(Box::new(proposal)); }); } } From 1d28d9a97af09661f9e5c09fbab3d2c2067c7a86 Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 13 Mar 2018 13:05:46 +0100 Subject: [PATCH 03/13] Fix tests. --- demo/runtime/src/dispatch.rs | 9 ++-- demo/runtime/src/runtime/session.rs | 73 ++++++++++++++++------------- demo/runtime/src/runtime/staking.rs | 2 +- demo/runtime/src/runtime/system.rs | 11 +++-- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/demo/runtime/src/dispatch.rs b/demo/runtime/src/dispatch.rs index 93be322e520f4..e5eecee1ca20d 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -224,8 +224,9 @@ impl_meta_dispatch! { pub mod public; path public; trait staking::PublicPass; - Staking(mod staking) = 0; - Timestamp(mod timestamp) = 1; + Session(mod session) = 1; + Staking(mod staking) = 2; + Timestamp(mod timestamp) = 3; Democracy(mod democracy) = 5; Council(mod council) = 6; CouncilVote(mod council) = 7; @@ -235,7 +236,9 @@ impl_meta_dispatch! { pub mod privileged; path privileged; trait system::PrivPass; - Staking(mod staking) = 0; + System(mod system) = 0; + Session(mod session) = 1; + Staking(mod staking) = 2; Democracy(mod democracy) = 5; Council(mod council) = 6; CouncilVote(mod council) = 7; diff --git a/demo/runtime/src/runtime/session.rs b/demo/runtime/src/runtime/session.rs index c5c5387dd9b57..705b08c5ae06a 100644 --- a/demo/runtime/src/runtime/session.rs +++ b/demo/runtime/src/runtime/session.rs @@ -22,6 +22,8 @@ use codec::KeyedVec; use runtime_support::{storage, StorageVec}; use demo_primitives::{AccountId, SessionKey, BlockNumber}; use runtime::{system, staking, consensus}; +use runtime::system::PrivPass; +use runtime::staking::PublicPass; pub const SESSION_LENGTH: &[u8] = b"ses:len"; pub const CURRENT_INDEX: &[u8] = b"ses:ind"; @@ -62,28 +64,35 @@ pub fn last_length_change() -> BlockNumber { storage::get_or(LAST_LENGTH_CHANGE, 0) } -pub mod public { - use super::*; +impl_dispatch! { + pub mod public; + fn set_key(key: SessionKey) = 0; +} +impl<'a> public::Dispatch for PublicPass<'a> { /// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next /// session. - pub fn set_key(validator: &AccountId, key: &SessionKey) { + fn set_key(self, key: SessionKey) { // set new value for next session - storage::put(&validator.to_keyed_vec(NEXT_KEY_FOR), key); + storage::put(&self.to_keyed_vec(NEXT_KEY_FOR), &key); } } -pub mod privileged { - use super::*; +impl_dispatch! { + pub mod privileged; + fn set_length(new: BlockNumber) = 0; + fn force_new_session() = 1; +} +impl privileged::Dispatch for PrivPass { /// Set a new era length. Won't kick in until the next era change (at current length). - pub fn set_length(new: BlockNumber) { + fn set_length(self, new: BlockNumber) { storage::put(NEXT_SESSION_LENGTH, &new); } /// Forces a new session. - pub fn force_new_session() { - rotate_session(); + fn force_new_session(self) { + internal::rotate_session(); } } @@ -110,27 +119,27 @@ pub mod internal { rotate_session(); } } -} -/// Move onto next session: register the new authority set. -fn rotate_session() { - // Increment current session index. - storage::put(CURRENT_INDEX, &(current_index() + 1)); + /// Move onto next session: register the new authority set. + pub fn rotate_session() { + // Increment current session index. + storage::put(CURRENT_INDEX, &(current_index() + 1)); - // Enact era length change. - if let Some(next_len) = storage::get::(NEXT_SESSION_LENGTH) { - storage::put(SESSION_LENGTH, &next_len); - storage::put(LAST_LENGTH_CHANGE, &system::block_number()); - storage::kill(NEXT_SESSION_LENGTH); - } - - // Update any changes in session keys. - validators().iter().enumerate().for_each(|(i, v)| { - let k = v.to_keyed_vec(NEXT_KEY_FOR); - if let Some(n) = storage::take(&k) { - consensus::internal::set_authority(i as u32, &n); + // Enact era length change. + if let Some(next_len) = storage::get::(NEXT_SESSION_LENGTH) { + storage::put(SESSION_LENGTH, &next_len); + storage::put(LAST_LENGTH_CHANGE, &system::block_number()); + storage::kill(NEXT_SESSION_LENGTH); } - }); + + // Update any changes in session keys. + validators().iter().enumerate().for_each(|(i, v)| { + let k = v.to_keyed_vec(NEXT_KEY_FOR); + if let Some(n) = storage::take(&k) { + consensus::internal::set_authority(i as u32, &n); + } + }); + } } #[cfg(any(feature = "std", test))] @@ -161,7 +170,7 @@ pub mod testing { mod tests { use super::*; use super::public::*; - use super::privileged::*; + use super::privileged::Dispatch as PrivDispatch; use super::internal::*; use runtime_io::{with_externalities, twox_128, TestExternalities}; use codec::{KeyedVec, Joiner}; @@ -200,14 +209,14 @@ mod tests { with_externalities(&mut t, || { // Block 1: Change to length 3; no visible change. with_env(|e| e.block_number = 1); - set_length(3); + PrivPass.set_length(3); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 0); // Block 2: Length now changed to 3. Index incremented. with_env(|e| e.block_number = 2); - set_length(3); + PrivPass.set_length(3); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); @@ -220,7 +229,7 @@ mod tests { // Block 4: Change to length 2; no visible change. with_env(|e| e.block_number = 4); - set_length(2); + PrivPass.set_length(2); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); @@ -261,7 +270,7 @@ mod tests { // Block 3: Set new key for validator 2; no visible change. with_env(|e| e.block_number = 3); - set_key(&[20; 32], &[22; 32]); + PublicPass::test(&[20; 32]).set_key([22; 32]); assert_eq!(consensus::authorities(), vec![[11u8; 32], [21u8; 32]]); check_rotate_session(); diff --git a/demo/runtime/src/runtime/staking.rs b/demo/runtime/src/runtime/staking.rs index 8fa92dd76ec16..a3ff490e0e307 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -249,7 +249,7 @@ impl privileged::Dispatch for system::PrivPass { /// Force there to be a new era. This also forces a new session immediately after. fn force_new_era(self) { new_era(); - session::privileged::force_new_session(); + session::internal::rotate_session(); } } diff --git a/demo/runtime/src/runtime/system.rs b/demo/runtime/src/runtime/system.rs index 149a0a89807ee..bbe321feaf704 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -46,12 +46,15 @@ pub fn block_hash(number: BlockNumber) -> Hash { pub struct PrivPass; -pub mod privileged { - use super::*; +impl_dispatch! { + pub mod privileged; + fn set_code(new: Vec) = 0; +} +impl privileged::Dispatch for PrivPass { /// Set the new code. - pub fn set_code(new: &[u8]) { - storage::unhashed::put_raw(b":code", new); + fn set_code(self, new: Vec) { + storage::unhashed::put_raw(b":code", &new); } } From 69c88c3ba97a4b1cd428ab0e48f59dcbbab98c2d Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 13 Mar 2018 13:06:16 +0100 Subject: [PATCH 04/13] whitespace. --- demo/runtime/src/runtime/council.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/demo/runtime/src/runtime/council.rs b/demo/runtime/src/runtime/council.rs index 777144676f426..67ef51d361be7 100644 --- a/demo/runtime/src/runtime/council.rs +++ b/demo/runtime/src/runtime/council.rs @@ -256,7 +256,6 @@ pub fn leaderboard() -> Option> { storage::get(LEADERBOARD) } - impl_dispatch! { pub mod public; fn set_approvals(votes: Vec, index: VoteIndex) = 0; From b12a708dcf525ffd55d27c456b3bc0496bfd74f9 Mon Sep 17 00:00:00 2001 From: Gav Date: Wed, 14 Mar 2018 11:56:55 +0100 Subject: [PATCH 05/13] Fix demo runtime tests. --- demo/runtime/src/runtime/council_vote.rs | 2 +- demo/runtime/src/runtime/democracy.rs | 6 ++++++ demo/runtime/src/runtime/staking.rs | 6 ++++-- demo/runtime/src/runtime/system.rs | 11 +++++++---- substrate/codec/src/slicable.rs | 2 +- substrate/ed25519/src/lib.rs | 2 +- 6 files changed, 20 insertions(+), 9 deletions(-) diff --git a/demo/runtime/src/runtime/council_vote.rs b/demo/runtime/src/runtime/council_vote.rs index 4f96adbaa1157..008214c5879ae 100644 --- a/demo/runtime/src/runtime/council_vote.rs +++ b/demo/runtime/src/runtime/council_vote.rs @@ -205,7 +205,7 @@ pub mod internal { println!("Executing proposal {:?} {:?}", proposal, tally); if let &Proposal::Democracy(democracy::privileged::Call::cancel_referendum(ref_index)) = &proposal { if let (_, 0, 0) = tally { - democracy::privileged::Call::cancel_referendum(ref_index).dispatch(PrivPass); + democracy::internal::cancel_referendum(ref_index); } } else { if tally.0 > tally.1 + tally.2 { diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index beb184651de53..f662e18121cbc 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -265,6 +265,11 @@ pub mod internal { inject_referendum(system::block_number() + voting_period(), proposal, vote_threshold); } + /// Remove a referendum. + pub fn cancel_referendum(ref_index: ReferendumIndex) { + clear_referendum(ref_index); + } + /// Current era is ending; we should finish up any proposals. pub fn end_block(now: BlockNumber) { // pick out another public referendum if it's time. @@ -355,6 +360,7 @@ pub mod testing { twox_128(staking::SESSIONS_PER_ERA).to_vec() => vec![].and(&1u64), twox_128(staking::VALIDATOR_COUNT).to_vec() => vec![].and(&3u64), twox_128(staking::CURRENT_ERA).to_vec() => vec![].and(&1u64), + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![].and(&1u64), twox_128(LAUNCH_PERIOD).to_vec() => vec![].and(&1u64), twox_128(VOTING_PERIOD).to_vec() => vec![].and(&1u64), diff --git a/demo/runtime/src/runtime/staking.rs b/demo/runtime/src/runtime/staking.rs index a3ff490e0e307..1a3f5b0496ba8 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -603,6 +603,7 @@ pub mod testing { twox_128(&2u32.to_keyed_vec(INTENTION_AT)).to_vec() => Charlie.to_raw_public_vec(), twox_128(SESSIONS_PER_ERA).to_vec() => vec![].and(&sessions_per_era), twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&3u64), + twox_128(TRANSACTION_FEE).to_vec() => vec![].and(&1u64), twox_128(CURRENT_ERA).to_vec() => vec![].and(¤t_era), twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ]; @@ -637,6 +638,7 @@ mod tests { twox_128(VALIDATOR_COUNT).to_vec() => vec![].and(&2u32), twox_128(BONDING_DURATION).to_vec() => vec![].and(&3u64), twox_128(TOTAL_STAKE).to_vec() => vec![].and(&100u64), + twox_128(TRANSACTION_FEE).to_vec() => vec![].and(&0u64), twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&10u64), twox_128(&Bob.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&20u64), twox_128(&Charlie.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&30u64), @@ -775,8 +777,8 @@ mod tests { #[test] fn staking_balance_transfer_works() { - with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); + with_externalities(&mut testing::externalities(1, 3, 1), || { + set_free_balance(&Alice, 112); PublicPass::new(&Alice).transfer(Bob.to_raw_public(), 69); assert_eq!(balance(&Alice), 42); assert_eq!(balance(&Bob), 69); diff --git a/demo/runtime/src/runtime/system.rs b/demo/runtime/src/runtime/system.rs index bbe321feaf704..33d48f72beca5 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -245,7 +245,8 @@ mod tests { #[test] fn staking_balance_transfer_dispatch_works() { let mut t: TestExternalities = map![ - twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&One.to_raw_public().to_keyed_vec(staking::BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![10u8, 0, 0, 0, 0, 0, 0, 0] ]; let tx = UncheckedTransaction { @@ -254,12 +255,14 @@ mod tests { nonce: 0, function: PubCall::Staking(StakingCall::transfer(Two.into(), 69)), }, - signature: hex!("5f9832c5a4a39e2dd4a3a0c5b400e9836beb362cb8f7d845a8291a2ae6fe366612e080e4acd0b5a75c3d0b6ee69614a68fb63698c1e76bf1f2dcd8fa617ddf05").into(), + signature: hex!("3a682213cb10e8e375fe0817fe4d220a4622d910088809ed7fc8b4ea3871531dbadb22acfedd28a100a0b7bd2d274e0ff873655b13c88f4640b5569db3222706").into(), }; + println!("TX: {}", HexDisplay::from(&tx.transaction.encode())); + with_externalities(&mut t, || { internal::execute_transaction(tx, Header::from_block_number(1)); - assert_eq!(staking::balance(&One), 42); + assert_eq!(staking::balance(&One), 32); assert_eq!(staking::balance(&Two), 69); }); } @@ -275,7 +278,7 @@ mod tests { let h = Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("f4f6408fe3ce1d78d30bb7ed625b32f91e45b8b566023df309cfd93c6f4af9a4").into(), + state_root: hex!("584e0c1f4d4b96153591e3906d756762493dffeb5fa7159e7107014aec8d9c3d").into(), transaction_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(), digest: Digest { logs: vec![], }, }; diff --git a/substrate/codec/src/slicable.rs b/substrate/codec/src/slicable.rs index e473c0bf5e18c..490dca31a4882 100644 --- a/substrate/codec/src/slicable.rs +++ b/substrate/codec/src/slicable.rs @@ -81,7 +81,7 @@ impl Slicable for Box { } fn using_encoded R>(&self, f: F) -> R { - (*self).using_encoded(f) + self.as_ref().using_encoded(f) } } diff --git a/substrate/ed25519/src/lib.rs b/substrate/ed25519/src/lib.rs index f8a2ec0ce62a0..91f64b5f94262 100644 --- a/substrate/ed25519/src/lib.rs +++ b/substrate/ed25519/src/lib.rs @@ -221,7 +221,7 @@ mod test { let pair = Pair::from_seed(b"12345678901234567890123456789012"); let public = pair.public(); assert_eq!(public, Public::from_raw(hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee"))); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000002228000000d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); println!("Correct signature: {}", HexDisplay::from(&signature.0)); assert!(verify_strong(&signature, &message[..], &public)); From 8e3cc5170a9ab9c00947cacd29cb2b943a44bfc0 Mon Sep 17 00:00:00 2001 From: Gav Date: Wed, 14 Mar 2018 12:37:34 +0100 Subject: [PATCH 06/13] Fix up tests. --- demo/executor/src/lib.rs | 50 ++++++++++-------- .../release/polkadot_runtime.compact.wasm | Bin 92722 -> 134847 bytes .../release/polkadot_runtime.wasm | Bin 92771 -> 134896 bytes .../substrate_test_runtime.compact.wasm | Bin 32002 -> 32002 bytes .../release/substrate_test_runtime.wasm | Bin 32082 -> 32082 bytes 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/demo/executor/src/lib.rs b/demo/executor/src/lib.rs index 1740897add160..6e07f3c5fbf02 100644 --- a/demo/executor/src/lib.rs +++ b/demo/executor/src/lib.rs @@ -41,11 +41,13 @@ mod tests { use codec::{KeyedVec, Slicable, Joiner}; use keyring::Keyring::{self, Alice, Bob}; use runtime_support::Hashable; - use demo_runtime::runtime::staking::{self, balance, BALANCE_OF}; use state_machine::{CodeExecutor, TestExternalities}; use primitives::twox_128; - use demo_primitives::{Hash, Header, BlockNumber, Block, Digest, Transaction, - UncheckedTransaction, Function}; + use demo_primitives::{Hash, Header, BlockNumber, Digest}; + use demo_runtime::transaction::{Transaction, UncheckedTransaction}; + use demo_runtime::block::Block; + use demo_runtime::runtime::staking::{self, balance, BALANCE_OF}; + use demo_runtime::dispatch; use ed25519::{Public, Pair}; const BLOATY_CODE: &[u8] = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm"); @@ -62,7 +64,7 @@ mod tests { let transaction = Transaction { signed: Alice.into(), nonce: 0, - function: Function::StakingTransfer(Bob.into(), 69), + function: dispatch::PubCall::Staking(staking::public::Call::transfer(Bob.into(), 69)), }; let signature = Keyring::from_raw_public(transaction.signed).unwrap() .sign(&transaction.encode()); @@ -73,7 +75,8 @@ mod tests { #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -83,7 +86,8 @@ mod tests { #[test] fn panic_execution_with_native_equivalent_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -93,7 +97,8 @@ mod tests { #[test] fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, COMPACT_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -108,7 +113,8 @@ mod tests { #[test] fn successful_execution_with_foreign_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let r = Executor::new().call(&mut t, BLOATY_CODE, "execute_transaction", &vec![].and(&Header::from_block_number(1u64)).and(&tx())); @@ -152,11 +158,11 @@ mod tests { construct_block( 1, [69u8; 32].into(), - hex!("970ae19447bef129c88ee80c72797fa9dfeda4ca1a26d10102b669d776eb0ccf").into(), + hex!("cfb76a83e40aa6a0d3f92255e6229e74808cae31d9f46053f31129b797540d03").into(), vec![Transaction { signed: Alice.into(), nonce: 0, - function: Function::StakingTransfer(Bob.into(), 69), + function: dispatch::PubCall::Staking(staking::public::Call::transfer(Bob.into(), 69)), }] ) } @@ -165,17 +171,17 @@ mod tests { construct_block( 2, block1().1, - hex!("347ece6ef0d193bd7c2bfbda17706b82eb24c0965f415784a44b138f0df034cd").into(), + hex!("c713bd003e303648e8d904bcfa44084865c9b70c398547e678028cc7cf60907f").into(), vec![ Transaction { signed: Bob.into(), nonce: 0, - function: Function::StakingTransfer(Alice.into(), 5), + function: dispatch::PubCall::Staking(staking::public::Call::transfer(Alice.into(), 5)), }, Transaction { signed: Alice.into(), nonce: 1, - function: Function::StakingTransfer(Bob.into(), 15), + function: dispatch::PubCall::Staking(staking::public::Call::transfer(Bob.into(), 15)), } ] ) @@ -188,15 +194,15 @@ mod tests { Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(balance(&Alice), 42); + assert_eq!(balance(&Alice), 41); assert_eq!(balance(&Bob), 69); }); Executor::new().call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(balance(&Alice), 32); - assert_eq!(balance(&Bob), 79); + assert_eq!(balance(&Alice), 30); + assert_eq!(balance(&Bob), 78); }); } @@ -207,22 +213,23 @@ mod tests { WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block1().0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(balance(&Alice), 42); + assert_eq!(balance(&Alice), 41); assert_eq!(balance(&Bob), 69); }); WasmExecutor.call(&mut t, COMPACT_CODE, "execute_block", &block2().0).unwrap(); runtime_io::with_externalities(&mut t, || { - assert_eq!(balance(&Alice), 32); - assert_eq!(balance(&Bob), 79); + assert_eq!(balance(&Alice), 30); + assert_eq!(balance(&Bob), 78); }); } #[test] fn panic_execution_gives_error() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm"); @@ -233,7 +240,8 @@ mod tests { #[test] fn successful_execution_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] + twox_128(&Alice.to_raw_public().to_keyed_vec(BALANCE_OF)).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(staking::TRANSACTION_FEE).to_vec() => vec![0u8; 8] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm"); diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 1a7785d62623f53de0c64cb75a2aff30a273585f..51ece299b15ec748063864dc451c20c50d4cf996 100644 GIT binary patch literal 134847 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 z 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 diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 7528a02d42f7c13ae4826476215bacb482f7c9c3..3e5dfa7600fae96f03b20b50aaa683e48cc12b51 100644 GIT binary patch literal 134896 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%0DF5bXGn{tm&%! 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 HsLB5ewi~hB diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index fc34a3fd55082e7011646e99b1fc54c7d4fda632..9271aa6501f18138d17de1c52306644ac3ebd646 100644 GIT binary patch delta 2117 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 L;MiYJcKQDWpAz}+ diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index c27b24b0c21ae7094dd821cf5309d28a5a547c52..ac8ce9ca407f3841cf11d0ab3c698409487b6a17 100644 GIT binary patch delta 2187 zcmaJ?T}&KB9G}_UyW6|taL*ne-a(mL4!ENr*AlK@z%eaNW7`;8><5t8P5w!p!T7uwLupXO>At8NinI7tq=C0iNui97;8#mBI%3%XZCgvit!$1 zXMXeh|NbBIpSgQa@VzH^{xe*K;OB8+j1k7Ff>lX%sjAi!!cZ^N~xq z#(c4&SW;_v2p$OG^yaVRXbe_=$XuR2kcpQ_8b=D#F}4ybVO@F;h+Nm-0g)Zm2@H!z zv0io~)+A;#0H3ev!$FWCMZ~AY;p-!cR%iZR`>hn*Mzpx3>N5Xmx~es?8;L9J0xj1) z93{Gk1Is@vz7d# zLD>n4ONbAOR>}U{oyJ?)-QE!EXw}$}*6p!Sm^@2YB?HDemqC}2CJ>ba01JS9+FB0> zaKH6^oMdO(HrEIW(1A0n7<3j}M!#WOh9k^uYm5IU^BID{CcBPY-u_ZfkU?;b>o6(a z7m%&s^4{zaHwJC_x1;8XSuq0cBxcF4O?65(h&Kf_Vh`IJamXx5ce>yRdpetVPtNS8 zfZg67lVGv(!ZujM4tylxdh^zyw_Le8D7ltz5~0oyVcU-w9IPGYx@?1BUJbfuf2cnY2K7%(n+?R*tF4M!{R zdj#dv!RxNoA6dpS(JK6z_b>e7*KPD5$_U5)q9mE}% zCgptrMBMZ-#ON0HaaCMUH@yOt7C5yLNM67Wz%Pg!YT^Ks0^s+4wV?_Hx5jxGCnvWD&nGA2c6;#lz-bl}K5b zl+qkrF0JVfd!?#DN+Ljk`;IXfxrdsAWIekfjd@~ z&Kd+XpVHy66nw>mdqIK?M`#HWE;wTgJJXp^m>&l}3K18if(6~NnX_!xs90$M?r<#U zfESQ;zS)Ug3sAqn?(fS(;UerOXb;*h!*jyDF1d`9q_91`uR(DadMkLP@4j*Y7Kcv8 zdG*hpN^$I3<_8!r40Pf$_RT;QZ2U4%EQjE~0N#xC4-@-G?Zz#v+gkw^=e&nuzUaNB k@aKnN<4pi_MhpD=eql^H^X$;uFz0{Z>)tq1&nAQa0v6y4Q2+n{ delta 2193 zcmZuyT})g>6rQ>F?%m~YxeF{^cNaRl{Ou1bKTWswr_w19ZAny&p{?2|(rw_vLIpHN zW0nV^V2qMX8=snBLsHTj(t0te#s^}WSRaZFYT`p5s3FD&P1|-G{j| z-+bqMXU;h@yKx_H+{c%%V63q#IG}sV;pbsD@nbo^p3P*3vZqn48z$L_w=!rKho&;q zD4=Ht$Hpdx&?DNZ$xH?XD>83qhTfdcy!twzqv+9Udp$ilI6gHvG(9pgj@rDZM#cxn zMy709dx;k#ipo4`65ibqs%tI1_#*U-vYZaf@r%XhCI&WrvT~R}-D+F(nXn5!Fm9 z0pj9I!z2n(4L{o&?#If!_C&$L9gOz=0Uq5=$qlM)cPh^{h{)J=q;6$ z5XIn#J!KcjBv=O{^I*LciDOu-M?Vzf%WSow4dAVYLF@y2Qcg;ZIDAWqX2h(4rf(Hr z4KZShC#v#~5%m}yEFN2aN}z$Lo1-ME866QHL2(rk-#~>z3>q^DqU|P~tD_!6kYkV^ zAh$no-Xl9A3hHYw5^EsEqa8v*o-%uk;^* z#fAP~wNM~PYU!qC5|yqYq7jXD^+jEwr~+wU8c5~*e18%4fu)+jF(jgL1n>f)2&9O! zDG{ZJBmER1;PXFzcq|32MjKO4cN38Mgw86H z`x+r*RdgG&QAHPBCfyP_tfC$c04xAzCKKTKZ1Pi_VyV{pCSe40;4DBq3z#RqivA9# zkZw4_PPZPY{vRe=YpnrqKes;53n)CmXln(Dx3@x-ZsevD)5B3p!Gfs}2P?oGD+o|} zbC6j`TS*$akS(QB&}$p19v57aU3=Pi|2>_ifX$~H6UJ8{6`;D%p9XMq%Ul+_8yJ*@|0H za|)ZMk3$8o(Jr1mjV`)P7_XPu=hf&O)KcL2^V%GbX{4YFwYa+IK7?O@UexGSD6>YF z-F69uCyD2as?i1AR*+@Z=r5%l$$^j~0RaF6RLAUd=ng@3I8uybUf5tm{yK|lV<%lUWDt|q6dIw_E z#bwzRH&v(0kZ6HZ8-cS6*a7&((IF)cFe3ndZ)_Xs7jOqbX=M%*>#yFp!f&xo=OD=i zzpU+njWDgFoWM(&P t^kuwi4g4uUYwx^244dx(H)rm}E$mBk#+i?eegJd+&%WcnS<$g}-@l(%4k!Qs From 5eca74a3b39ccb0d9cccf78fef2b23e457b3eb62 Mon Sep 17 00:00:00 2001 From: Gav Date: Wed, 14 Mar 2018 13:02:48 +0100 Subject: [PATCH 07/13] Remove dead code. --- substrate/codec/src/endiansensitive.rs | 81 -------------------------- substrate/codec/src/lib.rs | 2 - 2 files changed, 83 deletions(-) delete mode 100644 substrate/codec/src/endiansensitive.rs diff --git a/substrate/codec/src/endiansensitive.rs b/substrate/codec/src/endiansensitive.rs deleted file mode 100644 index 00ff9a775fe71..0000000000000 --- a/substrate/codec/src/endiansensitive.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate 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 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. If not, see . - -//! Endian manager. - -/// Trait to allow conversion to a know endian representation when sensitive. -/// Types implementing this trait must have a size > 0. -// note: the copy bound and static lifetimes are necessary for safety of `Slicable` blanket -// implementation. -pub trait EndianSensitive: Copy + 'static { - fn to_le(self) -> Self { self } - fn to_be(self) -> Self { self } - fn from_le(self) -> Self { self } - fn from_be(self) -> Self { self } - fn as_be_then T>(&self, f: F) -> T { f(&self) } - fn as_le_then T>(&self, f: F) -> T { f(&self) } -} - -macro_rules! impl_endians { - ( $( $t:ty ),* ) => { $( - impl EndianSensitive for $t { - fn to_le(self) -> Self { <$t>::to_le(self) } - fn to_be(self) -> Self { <$t>::to_be(self) } - fn from_le(self) -> Self { <$t>::from_le(self) } - fn from_be(self) -> Self { <$t>::from_be(self) } - fn as_be_then T>(&self, f: F) -> T { let d = self.to_be(); f(&d) } - fn as_le_then T>(&self, f: F) -> T { let d = self.to_le(); f(&d) } - } - )* } -} -macro_rules! impl_non_endians { - ( $( $t:ty ),* ) => { $( - impl EndianSensitive for $t {} - )* } -} - -// NOTE: See test to ensure correctness. -impl EndianSensitive for bool {} - -impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize); -impl_non_endians!(u8, i8, [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], - [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], - [u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]); - -#[cfg(test)] -mod tests { - use super::EndianSensitive; - - #[test] - fn endian_sensitive_is_copy() { - fn _takes_copy() { } - fn _takes_endian_sensitive() { _takes_copy::() } - } - - #[test] - fn endian_sensitive_outlives_static() { - fn _takes_static() { } - fn _takes_endian_sensitive() { _takes_static::() } - } - - #[test] - fn bool_is_not_endian_sensitive() { - let b = true; - assert_eq!(b.to_be(), b.to_le()); - let b = false; - assert_eq!(b.to_be(), b.to_le()); - } -} diff --git a/substrate/codec/src/lib.rs b/substrate/codec/src/lib.rs index 92df92d44927e..15ff92b4f6694 100644 --- a/substrate/codec/src/lib.rs +++ b/substrate/codec/src/lib.rs @@ -23,12 +23,10 @@ #[cfg_attr(not(feature = "std"), macro_use)] extern crate substrate_runtime_std as rstd; -mod endiansensitive; mod slicable; mod joiner; mod keyedvec; -pub use self::endiansensitive::EndianSensitive; pub use self::slicable::{Input, Slicable, NonTrivialSlicable}; pub use self::joiner::Joiner; pub use self::keyedvec::KeyedVec; From faa0a44bfdb89049ed13e251ccf8e758bcf01b75 Mon Sep 17 00:00:00 2001 From: Gav Date: Fri, 16 Mar 2018 15:30:41 +0100 Subject: [PATCH 08/13] Use match for Id --- demo/runtime/src/dispatch.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/demo/runtime/src/dispatch.rs b/demo/runtime/src/dispatch.rs index 263b9fe725009..ab9231333813f 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -50,11 +50,12 @@ macro_rules! impl_dispatch { impl Id { /// Derive `Some` value from a `u8`, or `None` if it's invalid. fn from_u8(value: u8) -> Option { - use self::*; - let functions = [ - $( Id::$fn_name ),* - ]; - functions.iter().map(|&f| f).find(|&f| value == f as u8) + match value { + $( + $id => Some(Id::$fn_name), + )* + _ => None, + } } } @@ -154,11 +155,12 @@ macro_rules! impl_meta_dispatch { impl Id { /// Derive `Some` value from a `u8`, or `None` if it's invalid. fn from_u8(value: u8) -> Option { - use self::*; - let functions = [ - $( Id::$camelcase ),* - ]; - functions.iter().map(|&f| f).find(|&f| value == f as u8) + match value { + $( + $id => Some(Id::$camelcase), + )* + _ => None, + } } } From 7912de1d4bdaf5fa0e703fe0b31d7cc3e8e1e422 Mon Sep 17 00:00:00 2001 From: Gav Date: Mon, 19 Mar 2018 10:02:02 +0800 Subject: [PATCH 09/13] Make PrivPass better protected. --- demo/runtime/src/dispatch.rs | 4 ++-- demo/runtime/src/runtime/council.rs | 2 +- demo/runtime/src/runtime/council_vote.rs | 2 +- demo/runtime/src/runtime/democracy.rs | 15 ++++++++++++--- demo/runtime/src/runtime/session.rs | 2 +- demo/runtime/src/runtime/staking.rs | 6 +++--- demo/runtime/src/runtime/system.rs | 3 +-- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/demo/runtime/src/dispatch.rs b/demo/runtime/src/dispatch.rs index ab9231333813f..55064d2f36325 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -16,7 +16,7 @@ //! Dispatch system. Just dispatches calls. -use runtime::{staking, system}; +use runtime::{staking, democracy}; pub use rstd::prelude::Vec; pub use codec::{Slicable, Input, NonTrivialSlicable}; @@ -232,7 +232,7 @@ impl_meta_dispatch! { impl_meta_dispatch! { pub mod privileged; path privileged; - trait system::PrivPass; + trait democracy::PrivPass; System(mod system) = 0; Session(mod session) = 1; Staking(mod staking) = 2; diff --git a/demo/runtime/src/runtime/council.rs b/demo/runtime/src/runtime/council.rs index ecdc3ea8dba27..bdc965523c5f1 100644 --- a/demo/runtime/src/runtime/council.rs +++ b/demo/runtime/src/runtime/council.rs @@ -21,7 +21,7 @@ use codec::KeyedVec; use runtime_support::storage; use demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{staking, system, session}; -use runtime::system::PrivPass; +use runtime::democracy::PrivPass; use runtime::staking::{PublicPass, Balance}; // no polynomial attacks: diff --git a/demo/runtime/src/runtime/council_vote.rs b/demo/runtime/src/runtime/council_vote.rs index fbcf2d59c1558..9b58c7eeb4f9a 100644 --- a/demo/runtime/src/runtime/council_vote.rs +++ b/demo/runtime/src/runtime/council_vote.rs @@ -23,7 +23,7 @@ use runtime_support::storage; use demo_primitives::{AccountId, Hash, BlockNumber}; use runtime::{system, democracy, council}; use runtime::staking::{PublicPass, Balance}; -use runtime::system::PrivPass; +use runtime::democracy::PrivPass; use dispatch::PrivCall as Proposal; type ProposalHash = [u8; 32]; diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index f662e18121cbc..668c16d292277 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -23,12 +23,21 @@ use runtime_support::storage; use demo_primitives::{AccountId, Hash, BlockNumber}; use dispatch::PrivCall as Proposal; use runtime::{staking, system, session}; -use runtime::system::PrivPass; use runtime::staking::{PublicPass, Balance}; +/// A token for privileged dispatch. Can only be created in this module. +pub struct PrivPass; + +impl PrivPass { + fn new() -> PrivPass { PrivPass } +} + +/// A proposal index. pub type PropIndex = u32; +/// A referendum index. pub type ReferendumIndex = u32; +/// A means of determining if a vote is past pass threshold. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] pub enum VoteThreshold { @@ -298,7 +307,7 @@ pub mod internal { let total_stake = staking::total_stake(); clear_referendum(index); if vote_threshold.approved(approve, against, total_stake) { - proposal.dispatch(PrivPass); + proposal.dispatch(PrivPass::new()); } storage::put(NEXT_TALLY, &(index + 1)); } @@ -563,7 +572,7 @@ mod tests { with_env(|e| e.block_number = 1); let r = inject_referendum(1, sessions_per_era_propsal(2), VoteThreshold::SuperMajorityApprove); PublicPass::test(&Alice).vote(r, true); - PrivPass.cancel_referendum(r); + PrivPass::new().cancel_referendum(r); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); diff --git a/demo/runtime/src/runtime/session.rs b/demo/runtime/src/runtime/session.rs index 705b08c5ae06a..72956dc6f5617 100644 --- a/demo/runtime/src/runtime/session.rs +++ b/demo/runtime/src/runtime/session.rs @@ -22,7 +22,7 @@ use codec::KeyedVec; use runtime_support::{storage, StorageVec}; use demo_primitives::{AccountId, SessionKey, BlockNumber}; use runtime::{system, staking, consensus}; -use runtime::system::PrivPass; +use runtime::democracy::PrivPass; use runtime::staking::PublicPass; pub const SESSION_LENGTH: &[u8] = b"ses:len"; diff --git a/demo/runtime/src/runtime/staking.rs b/demo/runtime/src/runtime/staking.rs index 1a3f5b0496ba8..c57c2f5178ea3 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -24,7 +24,7 @@ use runtime_io::{print, blake2_256}; use codec::{Slicable, Input, KeyedVec}; use runtime_support::{storage, StorageVec}; use demo_primitives::{BlockNumber, AccountId}; -use runtime::{system, session}; +use runtime::{system, session, democracy}; /// The balance of an account. pub type Balance = u64; @@ -230,7 +230,7 @@ impl_dispatch! { fn force_new_era() = 3; } -impl privileged::Dispatch for system::PrivPass { +impl privileged::Dispatch for democracy::PrivPass { /// Set the number of sessions in an era. fn set_sessions_per_era(self, new: BlockNumber) { storage::put(NEXT_SESSIONS_PER_ERA, &new); @@ -623,7 +623,7 @@ mod tests { use environment::with_env; use demo_primitives::AccountId; use runtime::{staking, session}; - use runtime::system::PrivPass; + use runtime::democracy::PrivPass; use runtime::staking::public::{Call, Dispatch}; use runtime::staking::privileged::{Call as PCall, Dispatch as PDispatch}; diff --git a/demo/runtime/src/runtime/system.rs b/demo/runtime/src/runtime/system.rs index 33d48f72beca5..d7990331ad5be 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -27,6 +27,7 @@ use demo_primitives::{AccountId, Hash, TxOrder, BlockNumber, Header, Log}; use block::Block; use transaction::UncheckedTransaction; use runtime::{staking, session}; +use runtime::democracy::PrivPass; use dispatch; pub const NONCE_OF: &[u8] = b"sys:non:"; @@ -44,8 +45,6 @@ pub fn block_hash(number: BlockNumber) -> Hash { storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT)) } -pub struct PrivPass; - impl_dispatch! { pub mod privileged; fn set_code(new: Vec) = 0; From aac3899fa8c635a536292d6b77ae2ba889d3782a Mon Sep 17 00:00:00 2001 From: Gav Date: Mon, 19 Mar 2018 10:15:49 +0800 Subject: [PATCH 10/13] Address other grumbles. --- demo/runtime/src/lib.rs | 2 +- demo/runtime/src/runtime/democracy.rs | 2 -- demo/runtime/src/runtime/system.rs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/demo/runtime/src/lib.rs b/demo/runtime/src/lib.rs index b9d0b32912691..1df77cc8cb925 100644 --- a/demo/runtime/src/lib.rs +++ b/demo/runtime/src/lib.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate Demo. If not, see . -//! The Substrate Demo runtime. This can be compiled with #[no_std], ready for Wasm. +//! The Substrate Demo runtime. This can be compiled with ``#[no_std]`, ready for Wasm. #![cfg_attr(not(feature = "std"), no_std)] diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index 668c16d292277..862d192406c9c 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -193,8 +193,6 @@ pub fn next_free_ref_index() -> ReferendumIndex { storage::get_or_default(REFERENDUM_COUNT) } -pub type BoxedProposal = Box; - impl_dispatch! { pub mod public; fn propose(proposal: Box, value: Balance) = 0; diff --git a/demo/runtime/src/runtime/system.rs b/demo/runtime/src/runtime/system.rs index d7990331ad5be..e3a6e19ef51f0 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -257,8 +257,6 @@ mod tests { signature: hex!("3a682213cb10e8e375fe0817fe4d220a4622d910088809ed7fc8b4ea3871531dbadb22acfedd28a100a0b7bd2d274e0ff873655b13c88f4640b5569db3222706").into(), }; - println!("TX: {}", HexDisplay::from(&tx.transaction.encode())); - with_externalities(&mut t, || { internal::execute_transaction(tx, Header::from_block_number(1)); assert_eq!(staking::balance(&One), 32); From 26519c68456ed4d7df7dbdc8801ab2772365767d Mon Sep 17 00:00:00 2001 From: Gav Date: Mon, 19 Mar 2018 10:21:25 +0800 Subject: [PATCH 11/13] Give PrivPass a private member. --- demo/runtime/src/runtime/democracy.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index 862d192406c9c..9ffcec4cfeaa7 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -26,10 +26,10 @@ use runtime::{staking, system, session}; use runtime::staking::{PublicPass, Balance}; /// A token for privileged dispatch. Can only be created in this module. -pub struct PrivPass; +pub struct PrivPass((),); impl PrivPass { - fn new() -> PrivPass { PrivPass } + fn new() -> PrivPass { PrivPass((),) } } /// A proposal index. From 9f32ea7dec3d1bc25aa62d425da974dd891a8734 Mon Sep 17 00:00:00 2001 From: Gav Date: Mon, 19 Mar 2018 10:23:34 +0800 Subject: [PATCH 12/13] Testing PrivPass. --- demo/runtime/src/runtime/council.rs | 4 ++-- demo/runtime/src/runtime/democracy.rs | 3 +++ demo/runtime/src/runtime/session.rs | 6 +++--- demo/runtime/src/runtime/staking.rs | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/demo/runtime/src/runtime/council.rs b/demo/runtime/src/runtime/council.rs index bdc965523c5f1..504461cf19add 100644 --- a/demo/runtime/src/runtime/council.rs +++ b/demo/runtime/src/runtime/council.rs @@ -1105,7 +1105,7 @@ mod tests { internal::end_block(); with_env(|e| e.block_number = 8); - PrivPass.set_desired_seats(3); + PrivPass::test().set_desired_seats(3); internal::end_block(); with_env(|e| e.block_number = 10); @@ -1362,7 +1362,7 @@ mod tests { with_env(|e| e.block_number = 8); PublicPass::test(&Ferdie).set_approvals(vec![false, false, true, false], 1); - PrivPass.set_desired_seats(3); + PrivPass::test().set_desired_seats(3); internal::end_block(); with_env(|e| e.block_number = 10); diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index 9ffcec4cfeaa7..ea945245e70e4 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -30,6 +30,9 @@ pub struct PrivPass((),); impl PrivPass { fn new() -> PrivPass { PrivPass((),) } + + #[cfg(test)] + pub fn test() -> PrivPass { PrivPass((),) } } /// A proposal index. diff --git a/demo/runtime/src/runtime/session.rs b/demo/runtime/src/runtime/session.rs index 72956dc6f5617..a0983c160801b 100644 --- a/demo/runtime/src/runtime/session.rs +++ b/demo/runtime/src/runtime/session.rs @@ -209,14 +209,14 @@ mod tests { with_externalities(&mut t, || { // Block 1: Change to length 3; no visible change. with_env(|e| e.block_number = 1); - PrivPass.set_length(3); + PrivPass::test().set_length(3); check_rotate_session(); assert_eq!(length(), 2); assert_eq!(current_index(), 0); // Block 2: Length now changed to 3. Index incremented. with_env(|e| e.block_number = 2); - PrivPass.set_length(3); + PrivPass::test().set_length(3); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); @@ -229,7 +229,7 @@ mod tests { // Block 4: Change to length 2; no visible change. with_env(|e| e.block_number = 4); - PrivPass.set_length(2); + PrivPass::test().set_length(2); check_rotate_session(); assert_eq!(length(), 3); assert_eq!(current_index(), 1); diff --git a/demo/runtime/src/runtime/staking.rs b/demo/runtime/src/runtime/staking.rs index c57c2f5178ea3..629700503f993 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -726,7 +726,7 @@ mod tests { // Block 3: Schedule an era length change; no visible changes. with_env(|e| e.block_number = 3); - PrivPass.set_sessions_per_era(3); + PrivPass::test().set_sessions_per_era(3); check_new_era(); assert_eq!(sessions_per_era(), 2u64); assert_eq!(last_era_length_change(), 0u64); From 8966951023fdb5825b94aa79b75a1fb8123bb0fb Mon Sep 17 00:00:00 2001 From: Gav Date: Mon, 19 Mar 2018 10:29:38 +0800 Subject: [PATCH 13/13] Add docs. --- demo/runtime/src/dispatch.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/runtime/src/dispatch.rs b/demo/runtime/src/dispatch.rs index 55064d2f36325..8290d071aa0b1 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -20,6 +20,7 @@ use runtime::{staking, democracy}; pub use rstd::prelude::Vec; pub use codec::{Slicable, Input, NonTrivialSlicable}; +/// Implement a dispatch module to create a pairing of a dispatch trait and enum. #[macro_export] macro_rules! impl_dispatch { (