diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 406c57a4fd..d607ec0e86 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -446,6 +446,7 @@ dependencies = [ "substrate-runtime-staking 0.1.0", "substrate-runtime-support 0.1.0", "substrate-runtime-system 0.1.0", + "substrate-runtime-treasury 0.1.0", "substrate-state-machine 0.1.0", "triehash 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -492,6 +493,7 @@ dependencies = [ "substrate-runtime-support 0.1.0", "substrate-runtime-system 0.1.0", "substrate-runtime-timestamp 0.1.0", + "substrate-runtime-treasury 0.1.0", "substrate-runtime-version 0.1.0", ] @@ -2708,6 +2710,7 @@ dependencies = [ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", + "substrate-codec-derive 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-balances 0.1.0", diff --git a/substrate/demo/cli/src/lib.rs b/substrate/demo/cli/src/lib.rs index 3ab2701c8c..f416a0122f 100644 --- a/substrate/demo/cli/src/lib.rs +++ b/substrate/demo/cli/src/lib.rs @@ -51,7 +51,7 @@ use std::sync::Arc; use demo_primitives::{AccountId, Hash}; use demo_runtime::{Block, BlockId, GenesisConfig, BalancesConfig, ConsensusConfig, CouncilConfig, DemocracyConfig, SessionConfig, - StakingConfig, TimestampConfig}; + StakingConfig, TimestampConfig, TreasuryConfig, Permill}; use futures::{Future, Sink, Stream}; use tokio::runtime::Runtime; use demo_executor::NativeExecutor; @@ -211,6 +211,12 @@ pub fn run(args: I) -> error::Result<()> where timestamp: Some(TimestampConfig { period: 5, // 5 second block time. }), + treasury: Some(TreasuryConfig { + proposal_bond: Permill::from_percent(5), + proposal_bond_minimum: 1_000_000, + spend_period: 12 * 60 * 24, + burn: Permill::from_percent(50), + }), }; let client = Arc::new(client::new_in_mem::, Block, _>(executor, genesis_config)?); diff --git a/substrate/demo/executor/Cargo.toml b/substrate/demo/executor/Cargo.toml index 1645e731a6..fd3de56684 100644 --- a/substrate/demo/executor/Cargo.toml +++ b/substrate/demo/executor/Cargo.toml @@ -25,3 +25,4 @@ substrate-runtime-session = { path = "../../substrate/runtime/session" } substrate-runtime-staking = { path = "../../substrate/runtime/staking" } substrate-runtime-system = { path = "../../substrate/runtime/system" } substrate-runtime-consensus = { path = "../../substrate/runtime/consensus" } +substrate-runtime-treasury = { path = "../../substrate/runtime/treasury" } diff --git a/substrate/demo/executor/src/lib.rs b/substrate/demo/executor/src/lib.rs index ce864d7592..8c7941f3fc 100644 --- a/substrate/demo/executor/src/lib.rs +++ b/substrate/demo/executor/src/lib.rs @@ -35,6 +35,7 @@ extern crate triehash; #[cfg(test)] extern crate substrate_runtime_staking as staking; #[cfg(test)] extern crate substrate_runtime_system as system; #[cfg(test)] extern crate substrate_runtime_consensus as consensus; +#[cfg(test)] extern crate substrate_runtime_treasury as treasury; #[cfg(test)] #[macro_use] extern crate hex_literal; pub use substrate_executor::NativeExecutor; @@ -53,7 +54,7 @@ mod tests { use demo_primitives::{Hash, BlockNumber, AccountId}; use runtime_primitives::traits::Header as HeaderT; use runtime_primitives::{ApplyOutcome, ApplyError, ApplyResult}; - use {balances, staking, session, system, consensus}; + use {balances, staking, session, system, consensus, treasury}; use system::{EventRecord, Phase}; use demo_runtime::{Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, Event}; @@ -234,6 +235,7 @@ mod tests { democracy: Some(Default::default()), council: Some(Default::default()), timestamp: Some(Default::default()), + treasury: Some(Default::default()), }.build_storage().unwrap().into() } @@ -260,7 +262,7 @@ mod tests { construct_block( 1, [69u8; 32].into(), - hex!("ddfc4d60889b25215f4fe6ead4e38b7522fa20809a793476eae3ad5ab2d9c399").into(), + hex!("1e930ccf2a39029931fcb9173637ab99a7de9d0364e7bf57cfbcb3eb4619e0d4").into(), vec![CheckedExtrinsic { signed: Some(alice()), index: 0, @@ -273,7 +275,7 @@ mod tests { construct_block( 2, block1().1, - hex!("2b4464c7e0d51325505663ae2ebd2246fcefc5cb998e9c29d8030c559cbbf27f").into(), + hex!("80e45869c9a9f513695b94baf479913ddf0bc9653f1be63baa383be8553a9e13").into(), vec![ CheckedExtrinsic { signed: Some(bob()), @@ -293,7 +295,7 @@ mod tests { construct_block( 1, [69u8; 32].into(), - hex!("e45221804da3a3609454d4e09debe6364cc6af63c2ff067d802d1af62fea32ae").into(), + hex!("58bf7cd5a908de7296bfc0524d89086384df3e8010ab83c8599be036445d6c79").into(), vec![CheckedExtrinsic { signed: Some(alice()), index: 0, @@ -328,6 +330,18 @@ mod tests { EventRecord { phase: Phase::ApplyExtrinsic(0), event: Event::system(system::Event::ExtrinsicSuccess) + }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Spending(0)) + }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Burnt(0)) + }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Rollover(0)) } ]); }); @@ -368,6 +382,18 @@ mod tests { phase: Phase::ApplyExtrinsic(1), event: Event::system(system::Event::ExtrinsicSuccess) }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Spending(0)) + }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Burnt(0)) + }, + EventRecord { + phase: Phase::Finalization, + event: Event::treasury(treasury::RawEvent::Rollover(0)) + }, EventRecord { phase: Phase::Finalization, event: Event::session(session::RawEvent::NewSession(1)) diff --git a/substrate/demo/runtime/Cargo.toml b/substrate/demo/runtime/Cargo.toml index 105c505e8d..cb263af8b1 100644 --- a/substrate/demo/runtime/Cargo.toml +++ b/substrate/demo/runtime/Cargo.toml @@ -27,6 +27,7 @@ substrate-runtime-session = { path = "../../substrate/runtime/session" } substrate-runtime-staking = { path = "../../substrate/runtime/staking" } substrate-runtime-system = { path = "../../substrate/runtime/system" } substrate-runtime-timestamp = { path = "../../substrate/runtime/timestamp" } +substrate-runtime-treasury = { path = "../../substrate/runtime/treasury" } substrate-runtime-version = { path = "../../substrate/runtime/version" } demo-primitives = { path = "../primitives" } @@ -48,6 +49,7 @@ std = [ "substrate-runtime-staking/std", "substrate-runtime-system/std", "substrate-runtime-timestamp/std", + "substrate-runtime-treasury/std", "substrate-runtime-version/std", "demo-primitives/std", "serde_derive", diff --git a/substrate/demo/runtime/src/lib.rs b/substrate/demo/runtime/src/lib.rs index 114351b91d..c07e510476 100644 --- a/substrate/demo/runtime/src/lib.rs +++ b/substrate/demo/runtime/src/lib.rs @@ -35,6 +35,7 @@ extern crate serde_derive; extern crate serde; extern crate substrate_codec as codec; +extern crate substrate_primitives; #[macro_use] extern crate substrate_codec_derive; @@ -49,6 +50,7 @@ extern crate substrate_runtime_session as session; extern crate substrate_runtime_staking as staking; extern crate substrate_runtime_system as system; extern crate substrate_runtime_timestamp as timestamp; +extern crate substrate_runtime_treasury as treasury; #[macro_use] extern crate substrate_runtime_version as version; extern crate demo_primitives; @@ -57,9 +59,11 @@ use demo_primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index use runtime_primitives::generic; use runtime_primitives::traits::{Convert, BlakeTwo256, DigestItem}; use version::RuntimeVersion; +use council::motions as council_motions; +use substrate_primitives::u32_trait::{_2, _4}; #[cfg(any(feature = "std", test))] -pub use runtime_primitives::BuildStorage; +pub use runtime_primitives::{BuildStorage, Permill}; // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] @@ -161,9 +165,27 @@ pub type Council = council::Module; /// Council voting module for this concrete runtime. pub type CouncilVoting = council::voting::Module; +impl council::motions::Trait for Runtime { + type Origin = Origin; + type Proposal = Call; + type Event = Event; +} + +/// Council motions module for this concrete runtime. +pub type CouncilMotions = council_motions::Module; + +impl treasury::Trait for Runtime { + type ApproveOrigin = council_motions::EnsureMembers<_4>; + type RejectOrigin = council_motions::EnsureMembers<_2>; + type Event = Event; +} + +/// Treasury module for this concrete runtime. +pub type Treasury = treasury::Module; + impl_outer_event! { pub enum Event for Runtime { - balances, session, staking, democracy + balances, session, staking, democracy, treasury, council_motions } } @@ -175,6 +197,7 @@ impl_outer_log! { impl_outer_origin! { pub enum Origin for Runtime { + council_motions } } @@ -188,6 +211,8 @@ impl_outer_dispatch! { Democracy, Council, CouncilVoting, + CouncilMotions, + Treasury, } } @@ -201,6 +226,7 @@ impl_outer_config! { DemocracyConfig => democracy, CouncilConfig => council, TimestampConfig => timestamp, + TreasuryConfig => treasury, } } @@ -228,7 +254,7 @@ pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = executive::Executive; + ((((((), Treasury), Council), Democracy), Staking), Session)>; pub mod api { impl_stubs!( diff --git a/substrate/demo/runtime/wasm/Cargo.lock b/substrate/demo/runtime/wasm/Cargo.lock index 8cda9a3bf4..56c05ce783 100644 --- a/substrate/demo/runtime/wasm/Cargo.lock +++ b/substrate/demo/runtime/wasm/Cargo.lock @@ -111,6 +111,7 @@ dependencies = [ "substrate-runtime-support 0.1.0", "substrate-runtime-system 0.1.0", "substrate-runtime-timestamp 0.1.0", + "substrate-runtime-treasury 0.1.0", "substrate-runtime-version 0.1.0", ] @@ -648,6 +649,7 @@ dependencies = [ "serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", "substrate-codec 0.1.0", + "substrate-codec-derive 0.1.0", "substrate-keyring 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-balances 0.1.0", @@ -842,6 +844,24 @@ dependencies = [ "substrate-runtime-system 0.1.0", ] +[[package]] +name = "substrate-runtime-treasury" +version = "0.1.0" +dependencies = [ + "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.64 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-codec 0.1.0", + "substrate-codec-derive 0.1.0", + "substrate-primitives 0.1.0", + "substrate-runtime-balances 0.1.0", + "substrate-runtime-io 0.1.0", + "substrate-runtime-primitives 0.1.0", + "substrate-runtime-std 0.1.0", + "substrate-runtime-support 0.1.0", + "substrate-runtime-system 0.1.0", +] + [[package]] name = "substrate-runtime-version" version = "0.1.0" diff --git a/substrate/demo/runtime/wasm/Cargo.toml b/substrate/demo/runtime/wasm/Cargo.toml index 59cb7b4f72..18285b648f 100644 --- a/substrate/demo/runtime/wasm/Cargo.toml +++ b/substrate/demo/runtime/wasm/Cargo.toml @@ -25,6 +25,7 @@ substrate-runtime-session = { path = "../../../substrate/runtime/session", defau substrate-runtime-staking = { path = "../../../substrate/runtime/staking", default-features = false } substrate-runtime-system = { path = "../../../substrate/runtime/system", default-features = false } substrate-runtime-timestamp = { path = "../../../substrate/runtime/timestamp", default-features = false } +substrate-runtime-treasury = { path = "../../../substrate/runtime/treasury", default-features = false } substrate-runtime-version = { path = "../../../substrate/runtime/version", default-features = false } demo-primitives = { path = "../../primitives", default-features = false } @@ -47,6 +48,7 @@ std = [ "substrate-runtime-staking/std", "substrate-runtime-system/std", "substrate-runtime-timestamp/std", + "substrate-runtime-treasury/std", "substrate-runtime-version/std", "demo-primitives/std", ] diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index c9521e1aae..15128a6727 100644 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 4da0e20cc2..190dc49be1 100755 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ diff --git a/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm index 4206e8627c..c1f5e2bf53 100644 Binary files a/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm and b/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm differ diff --git a/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm b/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm index a8c597e6f0..b5943d520b 100755 Binary files a/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm and b/substrate/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm differ diff --git a/substrate/substrate/primitives/src/lib.rs b/substrate/substrate/primitives/src/lib.rs index 668cca6b7a..820935227c 100644 --- a/substrate/substrate/primitives/src/lib.rs +++ b/substrate/substrate/primitives/src/lib.rs @@ -92,6 +92,8 @@ pub use hashing::{blake2_256, twox_128, twox_256}; #[cfg(feature = "std")] pub mod hexdisplay; +pub mod u32_trait; + pub mod hash; mod hasher; pub mod sandbox; diff --git a/substrate/substrate/primitives/src/u32_trait.rs b/substrate/substrate/primitives/src/u32_trait.rs new file mode 100644 index 0000000000..5fba6f8e04 --- /dev/null +++ b/substrate/substrate/primitives/src/u32_trait.rs @@ -0,0 +1,89 @@ +// 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 . + +//! An u32 trait with "values" as impl'd types. + +/// A u32 value, wrapped in a trait because we don't yet have const generics. +pub trait Value { + /// The actual value represented by the impl'ing type. + const VALUE: u32; +} +/// Type representing the value 0 for the `Value` trait. +pub struct _0; impl Value for _0 { const VALUE: u32 = 0; } +/// Type representing the value 1 for the `Value` trait. +pub struct _1; impl Value for _1 { const VALUE: u32 = 1; } +/// Type representing the value 2 for the `Value` trait. +pub struct _2; impl Value for _2 { const VALUE: u32 = 2; } +/// Type representing the value 3 for the `Value` trait. +pub struct _3; impl Value for _3 { const VALUE: u32 = 3; } +/// Type representing the value 4 for the `Value` trait. +pub struct _4; impl Value for _4 { const VALUE: u32 = 4; } +/// Type representing the value 5 for the `Value` trait. +pub struct _5; impl Value for _5 { const VALUE: u32 = 5; } +/// Type representing the value 6 for the `Value` trait. +pub struct _6; impl Value for _6 { const VALUE: u32 = 6; } +/// Type representing the value 7 for the `Value` trait. +pub struct _7; impl Value for _7 { const VALUE: u32 = 7; } +/// Type representing the value 8 for the `Value` trait. +pub struct _8; impl Value for _8 { const VALUE: u32 = 8; } +/// Type representing the value 9 for the `Value` trait. +pub struct _9; impl Value for _9 { const VALUE: u32 = 9; } +/// Type representing the value 10 for the `Value` trait. +pub struct _10; impl Value for _10 { const VALUE: u32 = 10; } +/// Type representing the value 11 for the `Value` trait. +pub struct _11; impl Value for _11 { const VALUE: u32 = 11; } +/// Type representing the value 12 for the `Value` trait. +pub struct _12; impl Value for _12 { const VALUE: u32 = 12; } +/// Type representing the value 13 for the `Value` trait. +pub struct _13; impl Value for _13 { const VALUE: u32 = 13; } +/// Type representing the value 14 for the `Value` trait. +pub struct _14; impl Value for _14 { const VALUE: u32 = 14; } +/// Type representing the value 15 for the `Value` trait. +pub struct _15; impl Value for _15 { const VALUE: u32 = 15; } +/// Type representing the value 16 for the `Value` trait. +pub struct _16; impl Value for _16 { const VALUE: u32 = 16; } +/// Type representing the value 24 for the `Value` trait. +pub struct _24; impl Value for _24 { const VALUE: u32 = 24; } +/// Type representing the value 32 for the `Value` trait. +pub struct _32; impl Value for _32 { const VALUE: u32 = 32; } +/// Type representing the value 40 for the `Value` trait. +pub struct _40; impl Value for _40 { const VALUE: u32 = 40; } +/// Type representing the value 48 for the `Value` trait. +pub struct _48; impl Value for _48 { const VALUE: u32 = 48; } +/// Type representing the value 56 for the `Value` trait. +pub struct _56; impl Value for _56 { const VALUE: u32 = 56; } +/// Type representing the value 64 for the `Value` trait. +pub struct _64; impl Value for _64 { const VALUE: u32 = 64; } +/// Type representing the value 80 for the `Value` trait. +pub struct _80; impl Value for _80 { const VALUE: u32 = 80; } +/// Type representing the value 96 for the `Value` trait. +pub struct _96; impl Value for _96 { const VALUE: u32 = 96; } +/// Type representing the value 112 for the `Value` trait. +pub struct _112; impl Value for _112 { const VALUE: u32 = 112; } +/// Type representing the value 128 for the `Value` trait. +pub struct _128; impl Value for _128 { const VALUE: u32 = 128; } +/// Type representing the value 160 for the `Value` trait. +pub struct _160; impl Value for _160 { const VALUE: u32 = 160; } +/// Type representing the value 192 for the `Value` trait. +pub struct _192; impl Value for _192 { const VALUE: u32 = 192; } +/// Type representing the value 224 for the `Value` trait. +pub struct _224; impl Value for _224 { const VALUE: u32 = 224; } +/// Type representing the value 256 for the `Value` trait. +pub struct _256; impl Value for _256 { const VALUE: u32 = 256; } +/// Type representing the value 384 for the `Value` trait. +pub struct _384; impl Value for _384 { const VALUE: u32 = 384; } +/// Type representing the value 512 for the `Value` trait. +pub struct _512; impl Value for _512 { const VALUE: u32 = 512; } diff --git a/substrate/substrate/runtime-support/src/event.rs b/substrate/substrate/runtime-support/src/event.rs index 9d73ef966e..bb999f83ea 100644 --- a/substrate/substrate/runtime-support/src/event.rs +++ b/substrate/substrate/runtime-support/src/event.rs @@ -37,6 +37,7 @@ macro_rules! __impl_outer_event_json_metadata { $( $module:ident )* ) => { impl $runtime { + #[allow(dead_code)] pub fn outer_event_json_metadata() -> &'static str { concat!(r#"{ "name": ""#, stringify!($event_name), r#"", "items": { "#, r#""system": "system::Event""#, diff --git a/substrate/substrate/runtime-support/src/lib.rs b/substrate/substrate/runtime-support/src/lib.rs index 21823b383f..57c8662882 100644 --- a/substrate/substrate/runtime-support/src/lib.rs +++ b/substrate/substrate/runtime-support/src/lib.rs @@ -116,7 +116,7 @@ macro_rules! impl_outer_origin { pub enum $name { system($system::Origin<$trait>), $( - $module($module::Origin<$trait>), + $module($module::Origin), )* #[allow(dead_code)] Void($crate::Void) @@ -149,13 +149,13 @@ macro_rules! impl_outer_origin { } } $( - impl From<$module::Origin<$trait>> for $name { - fn from(x: $module::Origin<$trait>) -> Self { + impl From<$module::Origin> for $name { + fn from(x: $module::Origin) -> Self { $name::$module(x) } } - impl Into>> for $name { - fn into(self) -> Option<$module::Origin> { + impl Into> for $name { + fn into(self) -> Option<$module::Origin> { if let $name::$module(l) = self { Some(l) } else { diff --git a/substrate/substrate/runtime/council/Cargo.toml b/substrate/substrate/runtime/council/Cargo.toml index 7b420a7b29..aa1bbd0bdf 100644 --- a/substrate/substrate/runtime/council/Cargo.toml +++ b/substrate/substrate/runtime/council/Cargo.toml @@ -11,6 +11,7 @@ serde_derive = { version = "1.0", optional = true } safe-mix = { version = "1.0", default_features = false} substrate-keyring = { path = "../../keyring", optional = true } substrate-codec = { path = "../../codec", default_features = false } +substrate-codec-derive = { path = "../../codec/derive", default_features = false } substrate-primitives = { path = "../../primitives", default_features = false } substrate-runtime-std = { path = "../../runtime-std", default_features = false } substrate-runtime-io = { path = "../../runtime-io", default_features = false } @@ -29,6 +30,7 @@ std = [ "safe-mix/std", "substrate-keyring", "substrate-codec/std", + "substrate-codec-derive/std", "substrate-primitives/std", "substrate-runtime-std/std", "substrate-runtime-io/std", diff --git a/substrate/substrate/runtime/council/src/lib.rs b/substrate/substrate/runtime/council/src/lib.rs index 483c07c79d..a27beff522 100644 --- a/substrate/substrate/runtime/council/src/lib.rs +++ b/substrate/substrate/runtime/council/src/lib.rs @@ -25,8 +25,13 @@ extern crate serde; #[macro_use] extern crate serde_derive; +#[cfg(test)] +#[macro_use] +extern crate hex_literal; + extern crate integer_sqrt; extern crate substrate_codec as codec; +#[macro_use] extern crate substrate_codec_derive; extern crate substrate_primitives; #[cfg(feature = "std")] extern crate substrate_keyring as keyring; #[macro_use] extern crate substrate_runtime_std as rstd; @@ -47,6 +52,7 @@ use balances::address::Address; use system::{ensure_signed, ensure_root}; pub mod voting; +pub mod motions; // no polynomial attacks: // @@ -630,9 +636,18 @@ mod tests { use primitives::traits::{BlakeTwo256}; use primitives::testing::{Digest, Header}; use substrate_primitives::KeccakHasher; + use motions as council_motions; impl_outer_origin! { - pub enum Origin for Test {} + pub enum Origin for Test { + council_motions + } + } + + impl_outer_event! { + pub enum Event for Test { + balances, democracy, council_motions + } } impl_outer_dispatch! { @@ -654,20 +669,26 @@ mod tests { type Digest = Digest; type AccountId = u64; type Header = Header; - type Event = (); + type Event = Event; } impl balances::Trait for Test { type Balance = u64; type AccountIndex = u64; type OnFreeBalanceZero = (); type EnsureAccountLiquid = (); - type Event = (); + type Event = Event; } impl democracy::Trait for Test { type Proposal = Call; - type Event = (); + type Event = Event; + } + impl Trait for Test { + } + impl council_motions::Trait for Test { + type Origin = Origin; + type Proposal = Call; + type Event = Event; } - impl Trait for Test {} pub fn new_test_ext(with_council: bool) -> runtime_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/substrate/substrate/runtime/council/src/motions.rs b/substrate/substrate/runtime/council/src/motions.rs new file mode 100644 index 0000000000..4238fb2a47 --- /dev/null +++ b/substrate/substrate/runtime/council/src/motions.rs @@ -0,0 +1,373 @@ +// 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 . + +//! Council voting system. + +use rstd::prelude::*; +use rstd::result; +use substrate_primitives::u32_trait::Value as U32; +use primitives::traits::{Hash, EnsureOrigin, MaybeSerializeDebug}; +use substrate_runtime_support::dispatch::{Result, Dispatchable, Parameter}; +use substrate_runtime_support::{StorageValue, StorageMap}; +use super::{Trait as CouncilTrait, Module as Council}; +use system::{self, ensure_signed}; + +/// Simple index type for proposal counting. +pub type ProposalIndex = u32; + +pub trait Trait: CouncilTrait + MaybeSerializeDebug { + /// The outer origin type. + type Origin: From; + + /// The outer call dispatch type. + type Proposal: Parameter + Dispatchable::Origin> + MaybeSerializeDebug; + + /// The outer event type. + type Event: From> + Into<::Event>; +} + +/// Origin for the council module. +#[derive(PartialEq, Eq, Clone)] +#[cfg_attr(feature = "std", derive(Debug))] +pub enum Origin { + /// It has been condoned by a given number of council members. + Members(u32), +} + +/// Outwardly visible event. +pub type Event = RawEvent<::Hash, ::AccountId>; + +/// Event for this module. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, PartialEq, Eq, Clone)] +pub enum RawEvent { + /// A motion (given hash) has been proposed (by given account) with a threshold (given u32). + Proposed(AccountId, ProposalIndex, Hash, u32), + /// A motion (given hash) has been voted on by given account, leaving + /// a tally (yes votes and no votes given as u32s respectively). + Voted(AccountId, Hash, bool, u32, u32), + /// A motion was approved by the required threshold. + Approved(Hash), + /// A motion was not approved by the required threshold. + Disapproved(Hash), + /// A motion was executed; `bool` is true if returned without error. + Executed(Hash, bool), +} + +impl From> for () { + fn from(_: RawEvent) -> () { () } +} + +decl_module! { + #[cfg_attr(feature = "std", serde(bound(deserialize = "::Proposal: ::serde::de::DeserializeOwned")))] + pub struct Module for enum Call where origin: ::Origin { + fn propose(origin, threshold: u32, proposal: Box<::Proposal>) -> Result; + fn vote(origin, proposal: T::Hash, index: ProposalIndex, approve: bool) -> Result; + } +} + +decl_storage! { + trait Store for Module as CouncilMotions { + /// The (hashes of) the active proposals. + pub Proposals get(proposals): default Vec; + /// Actual proposal for a given hash, if it's current. + pub ProposalOf get(proposal_of): map [ T::Hash => ::Proposal ]; + /// Votes for a given proposal: (required_yes_votes, yes_voters, no_voters). + pub Voting get(voting): map [ T::Hash => (ProposalIndex, u32, Vec, Vec) ]; + /// Proposals so far. + pub ProposalCount get(proposal_count): default u32; + } +} + +impl Module { + + /// Deposit one of this module's events. + fn deposit_event(event: Event) { + >::deposit_event(::Event::from(event).into()); + } + + pub fn is_councillor(who: &T::AccountId) -> bool { + >::active_council().iter() + .any(|&(ref a, _)| a == who) + } + + // Dispatch + fn propose(origin: ::Origin, threshold: u32, proposal: Box<::Proposal>) -> Result { + let who = ensure_signed(origin)?; + + ensure!(Self::is_councillor(&who), "proposer not on council"); + + let proposal_hash = T::Hashing::hash_of(&proposal); + + ensure!(!>::exists(proposal_hash), "duplicate proposals not allowed"); + + if threshold < 2 { + let ok = proposal.dispatch(Origin::Members(1).into()).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal_hash, ok)); + } else { + let index = Self::proposal_count(); + >::mutate(|i| *i += 1); + >::mutate(|proposals| proposals.push(proposal_hash)); + >::insert(proposal_hash, *proposal); + >::insert(proposal_hash, (index, threshold, vec![who.clone()], vec![])); + + Self::deposit_event(RawEvent::Proposed(who, index, proposal_hash, threshold)); + } + Ok(()) + } + + fn vote(origin: ::Origin, proposal: T::Hash, index: ProposalIndex, approve: bool) -> Result { + let who = ensure_signed(origin)?; + + ensure!(Self::is_councillor(&who), "voter not on council"); + + let mut voting = Self::voting(&proposal).ok_or("proposal must exist")?; + ensure!(voting.0 == index, "mismatched index"); + + let position_yes = voting.2.iter().position(|a| a == &who); + let position_no = voting.3.iter().position(|a| a == &who); + + if approve { + if position_yes.is_none() { + voting.2.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_no { + voting.3.swap_remove(pos); + } + } else { + if position_no.is_none() { + voting.3.push(who.clone()); + } else { + return Err("duplicate vote ignored") + } + if let Some(pos) = position_yes { + voting.2.swap_remove(pos); + } + } + + let yes_votes = voting.2.len() as u32; + let no_votes = voting.3.len() as u32; + Self::deposit_event(RawEvent::Voted(who, proposal, approve, yes_votes, no_votes)); + + let threshold = voting.1; + let potential_votes = >::active_council().len() as u32; + let approved = yes_votes >= threshold; + let disapproved = potential_votes - no_votes < threshold; + if approved || disapproved { + if approved { + Self::deposit_event(RawEvent::Approved(proposal)); + + // execute motion, assuming it exists. + if let Some(p) = >::take(&proposal) { + let ok = p.dispatch(Origin::Members(threshold).into()).is_ok(); + Self::deposit_event(RawEvent::Executed(proposal, ok)); + } + } else { + // disapproved + Self::deposit_event(RawEvent::Disapproved(proposal)); + } + + // remove vote + >::remove(&proposal); + >::mutate(|proposals| proposals.retain(|h| h != &proposal)); + } else { + // update voting + >::insert(&proposal, voting); + } + + Ok(()) + } +} + +/// Ensure that the origin `o` represents at least `n` council members. Returns +/// `Ok` or an `Err` otherwise. +pub fn ensure_council_members(o: OuterOrigin, n: u32) -> result::Result + where OuterOrigin: Into> +{ + match o.into() { + Some(Origin::Members(x)) if x >= n => Ok(n), + _ => Err("bad origin: expected to be a threshold number of council members"), + } +} + +pub struct EnsureMembers(::rstd::marker::PhantomData); +impl EnsureOrigin for EnsureMembers + where O: Into> +{ + type Success = u32; + fn ensure_origin(o: O) -> result::Result { + ensure_council_members(o, N::VALUE) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ::tests::*; + use ::tests::{Call, Origin, Event as OuterEvent}; + use substrate_runtime_support::Hashable; + use system::{EventRecord, Phase}; + + type CouncilMotions = super::Module; + + #[test] + fn motions_basic_environment_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + assert_eq!(Balances::free_balance(&42), 0); + assert_eq!(CouncilMotions::proposals(), Vec::::new()); + }); + } + + fn set_balance_proposal(value: u64) -> Call { + Call::Balances(balances::Call::set_balance(balances::address::Address::Id(42), value, 0)) + } + + #[test] + fn motions_propose_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + let hash = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_eq!(CouncilMotions::proposals(), vec![hash]); + assert_eq!(CouncilMotions::proposal_of(&hash), Some(proposal)); + assert_eq!(CouncilMotions::voting(&hash), Some((0, 3, vec![1], Vec::::new()))); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3)) + } + ]); + }); + } + + #[test] + fn motions_ignoring_non_council_proposals_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + assert_noop!(CouncilMotions::propose(Origin::signed(42), 3, Box::new(proposal.clone())), "proposer not on council"); + }); + } + + #[test] + fn motions_ignoring_non_council_votes_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_noop!(CouncilMotions::vote(Origin::signed(42), hash.clone(), 0, true), "voter not on council"); + }); + } + + #[test] + fn motions_ignoring_bad_index_council_vote_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(3); + let proposal = set_balance_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_noop!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 1, true), "mismatched index"); + }); + } + + #[test] + fn motions_revoting_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); + assert_eq!(CouncilMotions::voting(&hash), Some((0, 2, vec![1], Vec::::new()))); + assert_noop!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, true), "duplicate vote ignored"); + assert_ok!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, false)); + assert_eq!(CouncilMotions::voting(&hash), Some((0, 2, Vec::::new(), vec![1]))); + assert_noop!(CouncilMotions::vote(Origin::signed(1), hash.clone(), 0, false), "duplicate vote ignored"); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2)) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Voted(1, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 0, 1)) + } + ]); + }); + } + + #[test] + fn motions_disapproval_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 3, Box::new(proposal.clone()))); + assert_ok!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 0, false)); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 3)) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false, 1, 1)) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Disapproved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into())) + } + ]); + }); + } + + #[test] + fn motions_approval_works() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + let hash: H256 = proposal.blake2_256().into(); + assert_ok!(CouncilMotions::propose(Origin::signed(1), 2, Box::new(proposal.clone()))); + assert_ok!(CouncilMotions::vote(Origin::signed(2), hash.clone(), 0, true)); + + assert_eq!(System::events(), vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Proposed(1, 0, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), 2)) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Voted(2, hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), true, 2, 0)) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Approved(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into())) + }, + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: OuterEvent::council_motions(RawEvent::Executed(hex!["a900ca23832b1f42a5d4af5d0ece88da63fbb4049cc00bac3f741eabb5a79c45"].into(), false)) + } + ]); + }); + } +} diff --git a/substrate/substrate/runtime/council/src/voting.rs b/substrate/substrate/runtime/council/src/voting.rs index 5d14f68c9d..9fa6bdc39c 100644 --- a/substrate/substrate/runtime/council/src/voting.rs +++ b/substrate/substrate/runtime/council/src/voting.rs @@ -98,6 +98,8 @@ impl Module { fn vote(origin: T::Origin, proposal: T::Hash, approve: bool) -> Result { let who = ensure_signed(origin)?; + ensure!(Self::is_councillor(&who), "only councillors may vote on council proposals"); + if Self::vote_of((proposal, who.clone())).is_none() { let mut voters = Self::proposal_voters(&proposal); voters.push(who.clone()); @@ -220,7 +222,7 @@ impl OnFinalise for Council { mod tests { use super::*; use ::tests::*; - use ::tests::Call; + use ::tests::{Call, Origin}; use substrate_runtime_support::Hashable; use democracy::VoteThreshold; @@ -471,4 +473,14 @@ mod tests { assert_noop!(CouncilVoting::propose(Origin::signed(4), Box::new(proposal)), "proposer would not be on council"); }); } + + #[test] + fn vote_by_public_should_not_work() { + with_externalities(&mut new_test_ext(true), || { + System::set_block_number(1); + let proposal = set_balance_proposal(42); + assert_ok!(CouncilVoting::propose(Origin::signed(1), Box::new(proposal.clone()))); + assert_noop!(CouncilVoting::vote(Origin::signed(4), proposal.blake2_256().into(), true), "only councillors may vote on council proposals"); + }); + } } diff --git a/substrate/substrate/runtime/primitives/src/lib.rs b/substrate/substrate/runtime/primitives/src/lib.rs index 6bea27f4d6..fd0420dc60 100644 --- a/substrate/substrate/runtime/primitives/src/lib.rs +++ b/substrate/substrate/runtime/primitives/src/lib.rs @@ -87,6 +87,40 @@ impl BuildStorage for StorageMap { } } +/// Permill is parts-per-million (i.e. after multiplying by this, divide by 1000000). +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] +pub struct Permill(u32); + +// TODO: impl Mul for N where N: As +impl Permill { + pub fn times + ::rstd::ops::Mul + ::rstd::ops::Div>(self, b: N) -> N { + // TODO: handle overflows + b * >::sa(self.0 as usize) / >::sa(1000000) + } + + pub fn from_millionths(x: u32) -> Permill { Permill(x) } + + pub fn from_percent(x: u32) -> Permill { Permill(x * 10_000) } + + #[cfg(feature = "std")] + pub fn from_fraction(x: f64) -> Permill { Permill((x * 1_000_000.0) as u32) } +} + +#[cfg(feature = "std")] +impl From for Permill { + fn from(x: f64) -> Permill { + Permill::from_fraction(x) + } +} + +#[cfg(feature = "std")] +impl From for Permill { + fn from(x: f32) -> Permill { + Permill::from_fraction(x as f64) + } +} + /// Ed25519 signature verify. #[derive(Eq, PartialEq, Clone, Default, Encode, Decode)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] diff --git a/substrate/substrate/runtime/primitives/src/traits.rs b/substrate/substrate/runtime/primitives/src/traits.rs index f9d258df24..5ec2879ad4 100644 --- a/substrate/substrate/runtime/primitives/src/traits.rs +++ b/substrate/substrate/runtime/primitives/src/traits.rs @@ -47,6 +47,12 @@ pub trait Verify { fn verify>(&self, msg: L, signer: &Self::Signer) -> bool; } +/// Some sort of check on the origin is performed by this object. +pub trait EnsureOrigin { + type Success; + fn ensure_origin(o: OuterOrigin) -> Result; +} + /// Means of changing one type into another in a manner dependent on the source type. pub trait Lookup { /// Type to lookup from. diff --git a/substrate/substrate/runtime/system/src/lib.rs b/substrate/substrate/runtime/system/src/lib.rs index cd83ce0f09..7053bfcdf2 100644 --- a/substrate/substrate/runtime/system/src/lib.rs +++ b/substrate/substrate/runtime/system/src/lib.rs @@ -45,7 +45,7 @@ extern crate safe_mix; use rstd::prelude::*; use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, One, Bounded, - Hash, Member, MaybeDisplay}; + Hash, Member, MaybeDisplay, EnsureOrigin}; use runtime_support::{StorageValue, StorageMap, Parameter}; use safe_mix::TripletMix; @@ -168,6 +168,14 @@ decl_storage! { } } +pub struct EnsureRoot(::rstd::marker::PhantomData); +impl>>, AccountId> EnsureOrigin for EnsureRoot { + type Success = (); + fn ensure_origin(o: O) -> Result { + ensure_root(o) + } +} + /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed(o: OuterOrigin) -> Result diff --git a/substrate/substrate/runtime/treasury/src/lib.rs b/substrate/substrate/runtime/treasury/src/lib.rs index 01d4142dd9..7d533fa46a 100644 --- a/substrate/substrate/runtime/treasury/src/lib.rs +++ b/substrate/substrate/runtime/treasury/src/lib.rs @@ -18,13 +18,13 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg_attr(any(feature = "std", test), macro_use)] +#[cfg_attr(feature = "std", macro_use)] extern crate substrate_runtime_std as rstd; #[macro_use] extern crate substrate_runtime_support as runtime_support; -#[cfg(any(feature = "std", test))] +#[cfg(feature = "std")] extern crate substrate_runtime_io as runtime_io; #[cfg(feature = "std")] @@ -41,10 +41,10 @@ extern crate substrate_runtime_primitives as runtime_primitives; extern crate substrate_runtime_system as system; extern crate substrate_runtime_balances as balances; -use rstd::ops::{Mul, Div}; +use rstd::prelude::*; use runtime_support::{StorageValue, StorageMap}; use runtime_support::dispatch::Result; -use runtime_primitives::traits::{As, OnFinalise, Zero}; +use runtime_primitives::{Permill, traits::{OnFinalise, Zero, EnsureOrigin}}; use balances::OnMinted; use system::{ensure_signed, ensure_root}; @@ -54,6 +54,12 @@ use system::{ensure_signed, ensure_root}; /// /// `system::Trait` should always be included in our implied traits. pub trait Trait: balances::Trait { + /// Origin from which approvals must come. + type ApproveOrigin: EnsureOrigin; + + /// Origin from which rejections must come. + type RejectOrigin: EnsureOrigin; + /// The overarching event type. type Event: From> + Into<::Event>; } @@ -95,19 +101,6 @@ pub struct Proposal { bond: Balance, } -/// Permill is parts-per-million (i.e. after multiplying by this, divide by `PERMILL`). -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq)] -pub struct Permill(u32); - -// TODO: impl Mul for N where N: As -impl Permill { - fn times + Mul + Div>(self, b: N) -> N { - // TODO: handle overflows - b * >::sa(self.0 as usize) / >::sa(1000000) - } -} - decl_storage! { trait Store for Module as Treasury { // Config... @@ -192,7 +185,8 @@ impl Module { } fn reject_proposal(origin: T::Origin, proposal_id: ProposalIndex) -> Result { - ensure_root(origin)?; + T::RejectOrigin::ensure_origin(origin)?; + let proposal = >::take(proposal_id).ok_or("No proposal at that index")?; let value = proposal.bond; @@ -202,7 +196,8 @@ impl Module { } fn approve_proposal(origin: T::Origin, proposal_id: ProposalIndex) -> Result { - ensure_root(origin)?; + T::ApproveOrigin::ensure_origin(origin)?; + ensure!(>::exists(proposal_id), "No proposal at that index"); >::mutate(|v| v.push(proposal_id)); @@ -298,7 +293,7 @@ impl OnFinalise for Module { } } -#[cfg(any(feature = "std", test))] +#[cfg(feature = "std")] #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] @@ -311,19 +306,19 @@ pub struct GenesisConfig { pub burn: Permill, } -#[cfg(any(feature = "std", test))] +#[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { proposal_bond: Default::default(), proposal_bond_minimum: Default::default(), - spend_period: Default::default(), + spend_period: runtime_primitives::traits::One::one(), burn: Default::default(), } } } -#[cfg(any(feature = "std", test))] +#[cfg(feature = "std")] impl runtime_primitives::BuildStorage for GenesisConfig { fn build_storage(self) -> ::std::result::Result { @@ -372,6 +367,8 @@ mod tests { type Event = (); } impl Trait for Test { + type ApproveOrigin = system::EnsureRoot; + type RejectOrigin = system::EnsureRoot; type Event = (); } type Balances = balances::Module; @@ -389,10 +386,10 @@ mod tests { reclaim_rebate: 0, }.build_storage().unwrap()); t.extend(GenesisConfig::{ - proposal_bond: Permill(50_000), // 5% + proposal_bond: Permill::from_percent(5), proposal_bond_minimum: 1, spend_period: 2, - burn: Permill(500_000), // 50% + burn: Permill::from_percent(50), }.build_storage().unwrap()); t.into() } @@ -400,10 +397,10 @@ mod tests { #[test] fn genesis_config_works() { with_externalities(&mut new_test_ext(), || { - assert_eq!(Treasury::proposal_bond(), Permill(50_000)); + assert_eq!(Treasury::proposal_bond(), Permill::from_percent(5)); assert_eq!(Treasury::proposal_bond_minimum(), 1); assert_eq!(Treasury::spend_period(), 2); - assert_eq!(Treasury::burn(), Permill(500_000)); + assert_eq!(Treasury::burn(), Permill::from_percent(50)); assert_eq!(Treasury::pot(), 0); assert_eq!(Treasury::proposal_count(), 0); }); diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 78677fe859..cf8f849411 100644 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index 92496dc471..077f3a0387 100755 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ