diff --git a/Cargo.lock b/Cargo.lock index d270ab4d0c558..79952497a7737 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/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/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 8f0027459a6b4..0000000000000 --- a/demo/primitives/src/transaction.rs +++ /dev/null @@ -1,495 +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::prelude::*; -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) - } -} - -/// A means of determining whether a referendum has gone through or not. -#[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..182f9ca89b67e --- /dev/null +++ b/demo/runtime/src/block.rs @@ -0,0 +1,52 @@ +// 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. + +use rstd::prelude::*; +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) = 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 ee5c03d9520fe..8290d071aa0b1 100644 --- a/demo/runtime/src/dispatch.rs +++ b/demo/runtime/src/dispatch.rs @@ -16,79 +16,231 @@ //! 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::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 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 { + ( + 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 { + match value { + $( + $id => Some(Id::$fn_name), + )* + _ => None, + } + } + } + + #[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) -> $crate::dispatch::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 { + match value { + $( + $id => Some(Id::$camelcase), + )* + _ => None, + } + } + } + + #[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; + Session(mod session) = 1; + Staking(mod staking) = 2; + Timestamp(mod timestamp) = 3; + Democracy(mod democracy) = 5; + Council(mod council) = 6; + CouncilVote(mod council) = 7; +} + +impl_meta_dispatch! { + pub mod privileged; + path privileged; + trait democracy::PrivPass; + System(mod system) = 0; + Session(mod session) = 1; + Staking(mod staking) = 2; + 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..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)] @@ -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 fc93748ac1bcd..504461cf19add 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::democracy::PrivPass; +use runtime::staking::{PublicPass, Balance}; // no polynomial attacks: // @@ -255,25 +256,32 @@ 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 +289,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 +312,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 +353,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 +393,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() { @@ -574,8 +587,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() @@ -624,14 +639,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))); @@ -656,10 +671,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()]); }); } @@ -672,10 +687,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()]); }); } @@ -687,7 +702,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); }); } @@ -697,7 +712,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); }); } @@ -707,8 +722,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); }); } @@ -718,8 +733,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); }); } @@ -729,7 +744,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); }); } @@ -738,20 +753,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]); @@ -759,8 +774,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()]); - - }); } @@ -769,14 +782,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]); }); @@ -787,14 +800,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]); @@ -802,7 +815,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()); @@ -810,7 +823,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()); @@ -818,7 +831,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()); @@ -833,10 +846,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); }); } @@ -845,9 +858,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); }); } @@ -856,9 +869,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); }); } @@ -868,16 +881,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(); @@ -899,16 +912,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)]); @@ -920,26 +933,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 ); @@ -955,21 +968,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); }); } @@ -977,29 +990,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 ); @@ -1015,26 +1028,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 ); }); @@ -1045,26 +1058,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 ); }); @@ -1074,35 +1087,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::test().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 ); @@ -1117,26 +1130,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 ); }); @@ -1147,24 +1160,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); }); } @@ -1172,24 +1185,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()), @@ -1206,7 +1219,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); }); } @@ -1215,14 +1228,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); }); } @@ -1233,15 +1246,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); }); } @@ -1252,14 +1265,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); }); @@ -1271,31 +1284,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()), @@ -1328,33 +1341,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::test().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 9887d14cae293..9b58c7eeb4f9a 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::democracy::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,64 +142,69 @@ 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); - 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::internal::cancel_referendum(ref_index); } } else { if tally.0 > tally.1 + tally.2 { @@ -239,8 +251,11 @@ 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}; + use super::public::Dispatch; + use super::privileged::Dispatch as PrivDispatch; fn new_test_ext() -> TestExternalities { testing::externalities() @@ -266,19 +281,31 @@ mod tests { }); } + fn sessions_per_era_proposal(value: u64) -> Proposal { + Proposal::Staking(staking::privileged::Call::set_sessions_per_era(value)) + } + + 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 = 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); 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); @@ -293,14 +320,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); @@ -313,13 +340,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); @@ -332,10 +359,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); }); @@ -346,14 +373,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); }); } @@ -362,13 +389,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())); }); } @@ -376,21 +403,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)]); }); } @@ -398,14 +425,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); }); @@ -415,9 +442,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)); @@ -429,8 +456,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); @@ -444,16 +472,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)]); }); } @@ -461,16 +490,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)]); }); } @@ -479,7 +509,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)); }); } } diff --git a/demo/runtime/src/runtime/democracy.rs b/demo/runtime/src/runtime/democracy.rs index 227362818862f..ea945245e70e4 100644 --- a/demo/runtime/src/runtime/democracy.rs +++ b/demo/runtime/src/runtime/democracy.rs @@ -20,13 +20,58 @@ 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::staking::{PublicPass, Balance}; +/// A token for privileged dispatch. Can only be created in this module. +pub struct PrivPass((),); + +impl PrivPass { + fn new() -> PrivPass { PrivPass((),) } + + #[cfg(test)] + pub fn test() -> 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 { + /// 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 +196,90 @@ pub fn next_free_ref_index() -> ReferendumIndex { storage::get_or_default(REFERENDUM_COUNT) } -pub mod public { - use super::*; +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); + } + + /// 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. @@ -245,7 +308,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::new()); } storage::put(NEXT_TALLY, &(index + 1)); } @@ -307,6 +370,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), @@ -322,7 +386,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 +411,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 +433,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 +456,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 +471,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 +488,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 +497,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 +506,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 +571,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::new().cancel_referendum(r); democracy::internal::end_block(system::block_number()); staking::internal::check_new_era(); @@ -504,8 +586,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 +604,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 +625,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 +645,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/session.rs b/demo/runtime/src/runtime/session.rs index c5c5387dd9b57..a0983c160801b 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::democracy::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::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); - set_length(3); + PrivPass::test().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::test().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 6a30a743142a3..629700503f993 100644 --- a/demo/runtime/src/runtime/staking.rs +++ b/demo/runtime/src/runtime/staking.rs @@ -17,14 +17,14 @@ //! 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}; +use runtime::{system, session, democracy}; /// The balance of an account. pub type Balance = u64; @@ -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 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); + } + + /// 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::internal::rotate_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![ @@ -549,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] ]; @@ -560,7 +615,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 +623,9 @@ mod tests { use environment::with_env; use demo_primitives::AccountId; use runtime::{staking, session}; + use runtime::democracy::PrivPass; + use runtime::staking::public::{Call, Dispatch}; + use runtime::staking::privileged::{Call as PCall, Dispatch as PDispatch}; #[test] fn staking_should_work() { @@ -581,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), @@ -595,9 +653,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 +666,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 +677,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 +687,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 +726,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::test().set_sessions_per_era(3); check_new_era(); assert_eq!(sessions_per_era(), 2u64); assert_eq!(last_era_length_change(), 0u64); @@ -719,9 +777,9 @@ mod tests { #[test] fn staking_balance_transfer_works() { - with_externalities(&mut TestExternalities::default(), || { - set_free_balance(&Alice, 111); - transfer(&Alice, &Bob, 69); + 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); }); @@ -732,8 +790,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 +818,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..e3a6e19ef51f0 100644 --- a/demo/runtime/src/runtime/system.rs +++ b/demo/runtime/src/runtime/system.rs @@ -23,15 +23,18 @@ 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 runtime::democracy::PrivPass; use dispatch; 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,12 +45,15 @@ pub fn block_hash(number: BlockNumber) -> Hash { storage::get_or_default(&number.to_keyed_vec(BLOCK_HASH_AT)) } -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); } } @@ -137,16 +143,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,27 +235,31 @@ 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() { 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 { 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(), + signature: hex!("3a682213cb10e8e375fe0817fe4d220a4622d910088809ed7fc8b4ea3871531dbadb22acfedd28a100a0b7bd2d274e0ff873655b13c88f4640b5569db3222706").into(), }; 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); }); } @@ -262,7 +275,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/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..de769b5a16cef --- /dev/null +++ b/demo/runtime/src/transaction.rs @@ -0,0 +1,188 @@ +// 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::prelude::*; +use rstd::ops; +use codec::{Input, Slicable}; +use demo_primitives::{AccountId, TxOrder, Signature}; +use dispatch::PubCall; + +#[cfg(feature = "std")] +use std::fmt; + +/// 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: Slicable::decode(input)?, + nonce: Slicable::decode(input)?, + function: 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 = Slicable::decode(input)?; + + Some(UncheckedTransaction { + transaction: Slicable::decode(input)?, + signature: 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/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 71363e96d9632..8d4177558c879 100644 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 77c937bf318bb..43f146e82f7b5 100644 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ 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 e33dc4212228e..68f8fe0114541 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ 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 b29f06b3b6d28..06caf6119bea6 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ 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; diff --git a/substrate/codec/src/slicable.rs b/substrate/codec/src/slicable.rs index eb2b01db52fc8..3a312df9ce4a3 100644 --- a/substrate/codec/src/slicable.rs +++ b/substrate/codec/src/slicable.rs @@ -16,10 +16,9 @@ //! Serialisation. +use rstd::prelude::*; 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.as_ref().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]: 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 { 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)); 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 e97060c601271..b7150f9c4c350 100644 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ 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 96bd1a82b292b..e7533bbd880e2 100644 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ