diff --git a/Cargo.lock b/Cargo.lock index 02f1425afe834..85c6ed256e098 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2824,6 +2824,24 @@ dependencies = [ "substrate-runtime-system 0.1.0", ] +[[package]] +name = "substrate-runtime-example" +version = "0.1.0" +dependencies = [ + "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "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-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-executive" version = "0.1.0" @@ -2996,6 +3014,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.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-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/Cargo.toml b/Cargo.toml index d853608a8f99d..fd43193e9c58e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,12 +24,14 @@ members = [ "substrate/runtime/contract", "substrate/runtime/council", "substrate/runtime/democracy", + "substrate/runtime/example", "substrate/runtime/executive", "substrate/runtime/primitives", "substrate/runtime/session", "substrate/runtime/staking", "substrate/runtime/system", "substrate/runtime/timestamp", + "substrate/runtime/treasury", "substrate/runtime/version", "substrate/serializer", "substrate/service", diff --git a/demo/executor/src/lib.rs b/demo/executor/src/lib.rs index be80893f01cdf..38fe909ba2698 100644 --- a/demo/executor/src/lib.rs +++ b/demo/executor/src/lib.rs @@ -55,7 +55,7 @@ mod tests { use runtime_primitives::{ApplyOutcome, ApplyError, ApplyResult, MaybeUnsigned}; use {balances, staking, session, system, consensus}; use system::{EventRecord, Phase}; - use demo_runtime::{Header, Block, UncheckedExtrinsic, Extrinsic, Call, Concrete, Balances, + use demo_runtime::{Header, Block, UncheckedExtrinsic, Extrinsic, Call, Runtime, Balances, BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, BareExtrinsic, System, Event}; use ed25519::{Public, Pair}; @@ -81,7 +81,7 @@ mod tests { let extrinsic = BareExtrinsic { signed: alice(), index: 0, - function: Call::Balances(balances::Call::transfer::(bob().into(), 69)), + function: Call::Balances(balances::Call::transfer::(bob().into(), 69)), }; let signature = MaybeUnsigned(Keyring::from_raw_public(extrinsic.signed.0.clone()).unwrap() .sign(&extrinsic.encode()).into()); @@ -104,14 +104,14 @@ mod tests { #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![70u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![70u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let r = executor().call(&mut t, 8, BLOATY_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; @@ -124,14 +124,14 @@ mod tests { #[test] fn bad_extrinsic_with_native_equivalent_code_gives_error() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![70u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![70u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let r = executor().call(&mut t, 8, COMPACT_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; @@ -144,14 +144,14 @@ mod tests { #[test] fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let r = executor().call(&mut t, 8, COMPACT_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; @@ -168,14 +168,14 @@ mod tests { #[test] fn successful_execution_with_foreign_code_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let r = executor().call(&mut t, 8, BLOATY_CODE, "initialise_block", &vec![].and(&from_block_number(1u64)), true).0; @@ -401,14 +401,14 @@ mod tests { #[test] fn panic_execution_gives_error() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![70u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![70u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm"); @@ -422,14 +422,14 @@ mod tests { #[test] fn successful_execution_gives_ok() { let mut t: TestExternalities = map![ - twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(>::key()).to_vec() => vec![0u8; 8], - twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] + twox_128(&>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(>::key()).to_vec() => vec![0u8; 8], + twox_128(&>::key_for(0)).to_vec() => vec![0u8; 32] ]; let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm"); diff --git a/demo/runtime/src/lib.rs b/demo/runtime/src/lib.rs index f0c39af85d198..69cf3536335b0 100644 --- a/demo/runtime/src/lib.rs +++ b/demo/runtime/src/lib.rs @@ -56,7 +56,7 @@ extern crate demo_primitives; use rstd::prelude::*; use demo_primitives::{AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, SessionKey, Signature}; use runtime_primitives::generic; -use runtime_primitives::traits::{Convert, HasPublicAux, BlakeTwo256}; +use runtime_primitives::traits::{Convert, BlakeTwo256}; use version::RuntimeVersion; #[cfg(any(feature = "std", test))] @@ -65,8 +65,8 @@ pub use runtime_primitives::BuildStorage; // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -/// Concrete runtime type used to parameterize the various modules. -pub struct Concrete; +/// Runtime runtime type used to parameterize the various modules. +pub struct Runtime; /// Runtime version. pub const VERSION: RuntimeVersion = RuntimeVersion { @@ -78,18 +78,14 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { }; /// Version module for this concrete runtime. -pub type Version = version::Module; +pub type Version = version::Module; -impl version::Trait for Concrete { +impl version::Trait for Runtime { const VERSION: RuntimeVersion = VERSION; } -impl HasPublicAux for Concrete { - type PublicAux = AccountId; -} - -impl system::Trait for Concrete { - type PublicAux = ::PublicAux; +impl system::Trait for Runtime { + type PublicAux = Self::AccountId; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -101,9 +97,9 @@ impl system::Trait for Concrete { } /// System module for this concrete runtime. -pub type System = system::Module; +pub type System = system::Module; -impl balances::Trait for Concrete { +impl balances::Trait for Runtime { type Balance = Balance; type AccountIndex = AccountIndex; type OnFreeBalanceZero = Staking; @@ -112,25 +108,25 @@ impl balances::Trait for Concrete { } /// Staking module for this concrete runtime. -pub type Balances = balances::Module; +pub type Balances = balances::Module; -impl consensus::Trait for Concrete { +impl consensus::Trait for Runtime { const NOTE_OFFLINE_POSITION: u32 = 1; type SessionKey = SessionKey; type OnOfflineValidator = Staking; } /// Consensus module for this concrete runtime. -pub type Consensus = consensus::Module; +pub type Consensus = consensus::Module; -impl timestamp::Trait for Concrete { +impl timestamp::Trait for Runtime { const TIMESTAMP_SET_POSITION: u32 = 0; type Moment = u64; } /// Timestamp module for this concrete runtime. -pub type Timestamp = timestamp::Module; +pub type Timestamp = timestamp::Module; /// Session key conversion. pub struct SessionKeyConversion; @@ -140,38 +136,39 @@ impl Convert for SessionKeyConversion { } } -impl session::Trait for Concrete { +impl session::Trait for Runtime { type ConvertAccountIdToSessionKey = SessionKeyConversion; type OnSessionChange = Staking; type Event = Event; } /// Session module for this concrete runtime. -pub type Session = session::Module; +pub type Session = session::Module; -impl staking::Trait for Concrete { +impl staking::Trait for Runtime { + type OnRewardMinted = (); type Event = Event; } /// Staking module for this concrete runtime. -pub type Staking = staking::Module; +pub type Staking = staking::Module; -impl democracy::Trait for Concrete { +impl democracy::Trait for Runtime { type Proposal = PrivCall; } /// Democracy module for this concrete runtime. -pub type Democracy = democracy::Module; +pub type Democracy = democracy::Module; -impl council::Trait for Concrete {} +impl council::Trait for Runtime {} /// Council module for this concrete runtime. -pub type Council = council::Module; +pub type Council = council::Module; /// Council voting module for this concrete runtime. -pub type CouncilVoting = council::voting::Module; +pub type CouncilVoting = council::voting::Module; impl_outer_event! { - pub enum Event for Concrete { + pub enum Event for Runtime { balances, session, staking } } @@ -179,7 +176,7 @@ impl_outer_event! { impl_outer_dispatch! { #[derive(Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] - pub enum Call where aux: ::PublicAux { + pub enum Call where aux: ::PublicAux { Consensus = 0, Balances = 1, Session = 2, @@ -204,7 +201,7 @@ impl_outer_dispatch! { } /// The address format for describing accounts. -pub type Address = balances::Address; +pub type Address = balances::Address; /// Block header type as expected by this runtime. pub type Header = generic::Header>; /// Block type as expected by this runtime. @@ -218,11 +215,11 @@ pub type Extrinsic = generic::Extrinsic; /// Extrinsic type that is signed. pub type BareExtrinsic = generic::Extrinsic; /// Executive: handles dispatch to the various modules. -pub type Executive = executive::Executive; impl_outer_config! { - pub struct GenesisConfig for Concrete { + pub struct GenesisConfig for Runtime { ConsensusConfig => consensus, SystemConfig => system, BalancesConfig => balances, diff --git a/polkadot/parachain/test-chains/basic_add/Cargo.lock b/polkadot/parachain/test-chains/basic_add/Cargo.lock new file mode 100644 index 0000000000000..9c9bce1dee48a --- /dev/null +++ b/polkadot/parachain/test-chains/basic_add/Cargo.lock @@ -0,0 +1,224 @@ +[[package]] +name = "arrayvec" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "basic_add" +version = "0.1.0" +dependencies = [ + "polkadot-parachain 0.1.0", + "pwasm-libc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wee_alloc 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crunchy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "error-chain" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.43" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memory_units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nan-preserving-float" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nodrop" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "parity-wasm" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "polkadot-parachain" +version = "0.1.0" +dependencies = [ + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-codec 0.1.0", + "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pwasm-libc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-demangle" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "substrate-codec" +version = "0.1.0" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tiny-keccak" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasmi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wee_alloc" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" +"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" +"checksum cc 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "c37f0efaa4b9b001fa6f02d4b644dee4af97d3414df07c51e3e4f015f3a3e131" +"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" +"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum memory_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +"checksum memory_units 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" +"checksum nan-preserving-float 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34d4f00fcc2f4c9efa8cc971db0da9e28290e28e97af47585e48691ef10ff31f" +"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" +"checksum parity-wasm 0.31.3 (registry+https://github.com/rust-lang/crates.io-index)" = "511379a8194230c2395d2f5fa627a5a7e108a9f976656ce723ae68fca4097bfc" +"checksum pwasm-libc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "027307d6d2086ffb7f399227d42593c5341e8869a55ac8dd7c79d7ca04ec00e2" +"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" +"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" +"checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3" +"checksum wee_alloc 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "27875be1daf838fa18f3e94fd19fd12638e34615b42f56da2610c8f46be80cc6" +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index 54a551addf848..42ed93f8cafd3 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -787,7 +787,7 @@ macro_rules! __impl_store_fns { }; ($traitinstance:ident $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => { - __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $gettype $ty); + __impl_store_fn!($traitinstance $name $getfn (Option<$ty>) $ty); __impl_store_fns!($traitinstance $($t)*); }; ($traitinstance:ident pub $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => { diff --git a/substrate/runtime/balances/src/lib.rs b/substrate/runtime/balances/src/lib.rs index 00c4fd04c320c..225b8bdbf0347 100644 --- a/substrate/runtime/balances/src/lib.rs +++ b/substrate/runtime/balances/src/lib.rs @@ -45,7 +45,7 @@ use rstd::{cmp, result}; use codec::{Encode, Decode, Codec, Input, Output}; use runtime_support::{StorageValue, StorageMap, Parameter}; use runtime_support::dispatch::Result; -use primitives::traits::{Zero, One, RefInto, SimpleArithmetic, Executable, MakePayment, +use primitives::traits::{Zero, One, RefInto, SimpleArithmetic, OnFinalise, MakePayment, As, AuxLookup, Member, CheckedAdd, CheckedSub}; use address::Address as RawAddress; @@ -91,6 +91,16 @@ impl< } } +/// Trait for a hook to get called when some balance has been minted. +pub trait OnMinted { + /// Some balance `b` was minted. + fn on_minted(b: Balance); +} + +impl OnMinted for () { + fn on_minted(_b: Balance) {} +} + /// Determinator for whether a given account is able to transfer balance. pub trait EnsureAccountLiquid { /// Returns `Ok` iff the account is able to transfer funds normally. `Err(...)` @@ -400,6 +410,17 @@ impl Module { } } + /// Adds up to `value` to the free balance of `who`. If `who` doesn't exist, it is created. + /// + /// This is a sensitive function since it circumvents any fees associated with account + /// setup. Ensure it is only called by trusted code. + /// + /// NOTE: This assumes that the total stake remains unchanged after this operation. If + /// you mean to actually mint value into existence, then use `reward` instead. + pub fn increase_free_balance_creating(who: &T::AccountId, value: T::Balance) -> UpdateBalanceOutcome { + Self::set_free_balance_creating(who, Self::free_balance(who) + value) + } + /// Deducts up to `value` from the combined balance of `who`, preferring to deduct from the /// free balance. This function cannot fail. /// @@ -621,8 +642,8 @@ impl Module { } } -impl Executable for Module { - fn execute() { +impl OnFinalise for Module { + fn on_finalise(_n: T::BlockNumber) { } } diff --git a/substrate/runtime/balances/src/mock.rs b/substrate/runtime/balances/src/mock.rs index b7066a704fa16..803cd995649eb 100644 --- a/substrate/runtime/balances/src/mock.rs +++ b/substrate/runtime/balances/src/mock.rs @@ -19,7 +19,6 @@ #![cfg(test)] use primitives::BuildStorage; -use primitives::traits::HasPublicAux; use primitives::testing::{Digest, Header}; use substrate_primitives::{H256, KeccakHasher}; use runtime_io; @@ -28,11 +27,8 @@ use {GenesisConfig, Module, Trait, system}; // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub struct Test; -impl HasPublicAux for Test { - type PublicAux = u64; -} impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/runtime/contract/src/lib.rs b/substrate/runtime/contract/src/lib.rs index ec78584f2b12a..1749a4543c3cc 100644 --- a/substrate/runtime/contract/src/lib.rs +++ b/substrate/runtime/contract/src/lib.rs @@ -48,7 +48,7 @@ //! exsistential deposit) then it reaps the account. That will lead to deletion of the associated //! code and storage of the account. //! -//! [`Module::execute`]: struct.Module.html#impl-Executable +//! [`Module::execute`]: struct.Module.html#impl-OnFinalise #![cfg_attr(not(feature = "std"), no_std)] @@ -101,7 +101,7 @@ use account_db::{AccountDb, OverlayAccountDb}; use double_map::StorageDoubleMap; use codec::Codec; -use runtime_primitives::traits::{As, RefInto, SimpleArithmetic, Executable}; +use runtime_primitives::traits::{As, RefInto, SimpleArithmetic, OnFinalise}; use runtime_support::dispatch::Result; use runtime_support::{Parameter, StorageMap, StorageValue}; @@ -270,8 +270,8 @@ impl balances::OnFreeBalanceZero for Module { } /// Finalization hook for the smart-contract module. -impl Executable for Module { - fn execute() { +impl OnFinalise for Module { + fn on_finalise(_n: T::BlockNumber) { >::kill(); } } diff --git a/substrate/runtime/contract/src/tests.rs b/substrate/runtime/contract/src/tests.rs index 191536cba8027..f96a6fd2c5133 100644 --- a/substrate/runtime/contract/src/tests.rs +++ b/substrate/runtime/contract/src/tests.rs @@ -17,7 +17,7 @@ use double_map::StorageDoubleMap; use runtime_io::with_externalities; use runtime_primitives::testing::{Digest, H256, Header}; -use runtime_primitives::traits::{BlakeTwo256, HasPublicAux}; +use runtime_primitives::traits::{BlakeTwo256}; use runtime_primitives::BuildStorage; use runtime_support::StorageMap; use substrate_primitives::KeccakHasher; @@ -29,11 +29,8 @@ use { #[derive(Clone, Eq, PartialEq)] pub struct Test; -impl HasPublicAux for Test { - type PublicAux = u64; -} impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/runtime/council/Cargo.toml b/substrate/runtime/council/Cargo.toml index 1f85d467d4863..7b420a7b2949d 100644 --- a/substrate/runtime/council/Cargo.toml +++ b/substrate/runtime/council/Cargo.toml @@ -34,6 +34,7 @@ std = [ "substrate-runtime-io/std", "substrate-runtime-support/std", "substrate-runtime-primitives/std", + "substrate-runtime-consensus/std", "substrate-runtime-balances/std", "substrate-runtime-democracy/std", "substrate-runtime-system/std", diff --git a/substrate/runtime/council/src/lib.rs b/substrate/runtime/council/src/lib.rs index f13f637b3a259..a6e941079b71d 100644 --- a/substrate/runtime/council/src/lib.rs +++ b/substrate/runtime/council/src/lib.rs @@ -618,7 +618,7 @@ mod tests { pub use runtime_io::with_externalities; pub use substrate_primitives::H256; use primitives::BuildStorage; - use primitives::traits::{HasPublicAux, BlakeTwo256}; + use primitives::traits::{BlakeTwo256}; use primitives::testing::{Digest, Header}; use substrate_primitives::KeccakHasher; @@ -633,11 +633,8 @@ mod tests { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub struct Test; - impl HasPublicAux for Test { - type PublicAux = u64; - } impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/runtime/council/src/voting.rs b/substrate/runtime/council/src/voting.rs index 5569adc9e4faf..4b38d97dc48b1 100644 --- a/substrate/runtime/council/src/voting.rs +++ b/substrate/runtime/council/src/voting.rs @@ -18,7 +18,7 @@ use rstd::prelude::*; use rstd::borrow::Borrow; -use primitives::traits::{Executable, RefInto, Hash}; +use primitives::traits::{OnFinalise, RefInto, Hash}; use runtime_io::print; use substrate_runtime_support::dispatch::Result; use substrate_runtime_support::{StorageValue, StorageMap, IsSubType}; @@ -200,9 +200,8 @@ impl Module { } } -impl Executable for Council { - fn execute() { - let n = >::block_number(); +impl OnFinalise for Council { + fn on_finalise(n: T::BlockNumber) { if let Err(e) = Self::end_block(n) { print("Guru meditation"); print(e); diff --git a/substrate/runtime/democracy/src/lib.rs b/substrate/runtime/democracy/src/lib.rs index 7f3846ad9755f..473a02318bd3b 100644 --- a/substrate/runtime/democracy/src/lib.rs +++ b/substrate/runtime/democracy/src/lib.rs @@ -43,7 +43,7 @@ extern crate substrate_runtime_system as system; use rstd::prelude::*; use rstd::result; -use primitives::traits::{Zero, Executable, RefInto, As, MaybeSerializeDebug}; +use primitives::traits::{Zero, OnFinalise, RefInto, As, MaybeSerializeDebug}; use substrate_runtime_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType}; use substrate_runtime_support::dispatch::Result; @@ -288,9 +288,9 @@ impl Module { } } -impl Executable for Module { - fn execute() { - if let Err(e) = Self::end_block(>::block_number()) { +impl OnFinalise for Module { + fn on_finalise(n: T::BlockNumber) { + if let Err(e) = Self::end_block(n) { runtime_io::print(e); } } @@ -351,7 +351,7 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, KeccakHasher}; use primitives::BuildStorage; - use primitives::traits::{HasPublicAux, BlakeTwo256}; + use primitives::traits::{BlakeTwo256}; use primitives::testing::{Digest, Header}; impl_outer_dispatch! { @@ -365,11 +365,8 @@ mod tests { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub struct Test; - impl HasPublicAux for Test { - type PublicAux = u64; - } impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/runtime/example/Cargo.toml b/substrate/runtime/example/Cargo.toml new file mode 100644 index 0000000000000..92c0d887e7f3a --- /dev/null +++ b/substrate/runtime/example/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "substrate-runtime-example" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +hex-literal = "0.1.0" +serde = { version = "1.0", default_features = false } +serde_derive = { version = "1.0", optional = true } +substrate-runtime-std = { path = "../../runtime-std", default_features = false } +substrate-runtime-io = { path = "../../runtime-io", default_features = false } +substrate-runtime-support = { path = "../../runtime-support", default_features = false } +substrate-runtime-primitives = { path = "../primitives", default_features = false } +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-system = { path = "../system", default_features = false } +substrate-runtime-balances = { path = "../balances", default_features = false } + +[features] +default = ["std"] +std = [ + "substrate-runtime-std/std", + "substrate-runtime-io/std", + "substrate-runtime-support/std", + "substrate-runtime-primitives/std", + "substrate-runtime-balances/std", + "serde/std", + "serde_derive", + "substrate-codec/std", + "substrate-codec-derive/std", + "substrate-primitives/std", + "substrate-runtime-system/std", +] diff --git a/substrate/runtime/example/src/lib.rs b/substrate/runtime/example/src/lib.rs new file mode 100644 index 0000000000000..df172d5e01d00 --- /dev/null +++ b/substrate/runtime/example/src/lib.rs @@ -0,0 +1,385 @@ +// 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 . + +//! The Example: A simple example of a runtime module demonstrating +//! concepts, APIs and structures common to most runtime modules. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +// Assert macros used in tests. +#[cfg_attr(feature = "std", macro_use)] +extern crate substrate_runtime_std; + +// Needed for tests (`with_externalities`). +#[cfg(test)] +extern crate substrate_runtime_io as runtime_io; + +// Needed for the set of mock primatives used in our tests. +#[cfg(test)] +extern crate substrate_primitives; + +// Needed for deriving `Serialize` and `Deserialize` for various types. +// We only implement the serde traits for std builds - they're unneeded +// in the wasm runtime. +#[cfg(feature = "std")] +#[macro_use] +extern crate serde_derive; + +// Needed for deriving `Encode` and `Decode` for `RawEvent`. +#[macro_use] +extern crate substrate_codec_derive; +extern crate substrate_codec as codec; + +// Needed for type-safe access to storage DB. +#[macro_use] +extern crate substrate_runtime_support as runtime_support; + +// Needed for various traits. In our case, `OnFinalise`. +extern crate substrate_runtime_primitives as runtime_primitives; +// `system` module provides us with all sorts of useful stuff and macros +// depend on it being around. +extern crate substrate_runtime_system as system; +// `balances` module is needed for our little example. It's not required in +// general (though if you want your module to be able to work with tokens, then you +// might find it useful). +extern crate substrate_runtime_balances as balances; + +use runtime_primitives::traits::OnFinalise; +use runtime_support::{StorageValue, dispatch::Result}; + +/// Our module's configuration trait. All our types and consts go in here. If the +/// module is dependent on specific other modules, then their configuration traits +/// should be added to our implied traits list. +/// +/// `system::Trait` should always be included in our implied traits. +pub trait Trait: balances::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; +} + +// The module declaration. This states the entry points that we handle. The +// macro takes care of the marshalling of arguments and dispatch. +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what its working on. + pub struct Module; + + // The unpriviledged entry points. Any account can call into these by signing and submitting + // an extrinsic. Ensure that calls into each of these execute in a time, memory and + // using storage space proportional to any costs paid for by the caller. + // + // The account that is calling this (i.e. the one that signed the extrinsic) is provided + // via the `aux` argument, always first in each function call. As such functions must + // always look like: + // + // `fn foo(aux, bar: Bar, baz: Baz) -> Result = 0;` + // + // The `Result` is required as part of the syntax (and expands to the conventional dispatch + // result of `Result<(), &'static str>`). The index after `=` must be unique within this + // enum (the `PrivCall` enum is allowed to reuse indexes). + // + // When you come to `impl` them later in the module, you must specify the full type for `aux`: + // + // `fn foo(aux: T::PublicAux, bar: Bar, baz: Baz) { ... }` + // + // This is your public interface. Be extremely careful. + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + pub enum Call where aux: T::PublicAux { + // This is just a simple example of how to interact with the module from the external + // world. + fn accumulate_dummy(aux, increase_by: T::Balance) -> Result = 0; + } + + // The priviledged entry points. These are provided to allow any governance modules in + // the runtime to be able to execute common functions. Unlike for `Call` there is no + // auxilliary data to encode the sender (since there is no sender). Though still important + // to ensure that these execute in reasonable time and space, they can do what would + // otherwise be costly or unsafe operations. + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + pub enum PrivCall { + // A priviledged call; in this case it resets our dummy value to something new. + fn set_dummy(new_dummy: T::Balance) -> Result = 0; + } +} + +/// Exported Event type that's generic over the configuration trait. +// NOTE: External macro-fu expects this type to exist and be generic over +// the configuration trait. +pub type Event = RawEvent< + ::Balance, +>; + +/// An event in this module. Events are simple means of reporting specific conditions and +/// circumstances that have happened that users, Dapps and/or chain explorers would find +/// interesting and otherwise difficult to detect. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, PartialEq, Eq, Clone)] +pub enum RawEvent { + // Just a normal `enum`, here's a dummy event to ensure it compiles. + /// Dummy event, just here so there's a generic type that's used. + Dummy(B), +} + +// By convention we implement any trait for which a "null implemntation" makes sense +// for `()`. This is the case for conversion of module `Event` types and hook traits. It +// is helpful for test code and production configurations where no eventing is necessary +// or the hook is unused. +impl From> for () { + fn from(_: RawEvent) -> () { () } +} + +decl_storage! { + // A macro for the Storage trait, and its implementation, for this module. + // This allows for type-safe usage of the Substrate storage database, so you can + // keep things around between blocks. + trait Store for Module as Example { + // Any storage declarations of the form: + // `pub? Name get(getter_name)? : [required | default]? ;` + // where `` is either: + // - `Type` (a basic value item); or + // - `map [ KeyType => ValueType ]` (a map item). + // + // Note that there are two optional modifiers for the storage type declaration. + // - `Foo: u32`: + // - `Foo::put(1); Foo::get()` returns `Some(1)`; + // - `Foo::kill(); Foo::get()` returns `None`. + // - `Foo: required u32`: + // - `Foo::put(1); Foo::get()` returns `1`; + // - `Foo::kill(); Foo::get()` panics. + // - `Foo: default u32`: + // - `Foo::put(1); Foo::get()` returns `1`; + // - `Foo::kill(); Foo::get()` returns `0` (u32::default()). + // e.g. Foo: u32; + // e.g. pub Bar get(bar): default map [ T::AccountId => Vec<(T::Balance, u64)> ]; + // + // For basic value items, you'll get a type which implements + // `runtime_support::StorageValue`. For map items, you'll get a type which + // implements `runtime_support::StorageMap`. + // + // If they have a getter (`get(getter_name)`), then your module will come + // equiped with `fn getter_name() -> Type` for basic value items or + // `fn getter_name(key: KeyType) -> ValueType` for map items. + Dummy get(dummy): T::Balance; + } +} + +// The main implementation block for the module. Functions here fall into three broad +// categories: +// - Implementations of dispatch functions. The dispatch code generated by the module macro +// expects each of its functions to be implemented. +// - Public interface. These are functions that are `pub` and generally fall into inspector +// functions that do not write to storage and operation functions that do. +// - Private functions. These are your usual private utilities unavailable to other modules. +impl Module { + /// Deposit one of this module's events. + // TODO: move into `decl_module` macro. + fn deposit_event(event: Event) { + >::deposit_event(::Event::from(event).into()); + } + + // Implement Calls/PrivCalls and add public immutables and private mutables. + + // Implement dispatched function `accumulate_dummy`. This just increases the value + // of `Dummy` by `increase_by`. + // + // Since this is a dispatched function there are two extremely important things to + // remember: + // + // - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an + // irreparably damaged state) must this function panic. + // - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return + // `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`. + // + // The first is relatively easy to audit for - just ensure all panickers are removed from + // logic that executes in production (which you do anyway, right?!). To ensure the second + // is followed, you should do all tests for validity at the top of your function. This + // is stuff like checking the sender (`aux`) or that state is such that the operation + // makes sense. + // + // Once you've determined that it's all good, then enact the operation and change storage. + // If you can't be certain that the operation will succeed without substantial computation + // then you have a classic blockchain attack scenario. The normal way of managing this is + // to attach a bond to the operation. As the first major alteration of storage, reserve + // some value from the sender's account (`Balances` module has a `reserve` function for + // exactly this scenario). This amount should be enough to cover any costs of the + // substantial execution in case it turns out that you can't proceed with the operation. + // + // If it eventually transpires that the operation is fine and, therefore, that the + // expense of the checks should be borne by the network, then you can refund the reserved + // deposit. If, however, the operation turns out to be invalid and the computation is + // wasted, then you can burn it or repatriate elsewhere. + // + // Security bonds ensure that attackers can't game it by ensuring that anyone interacting + // with the system either progresses it or pays for the trouble of faffing around with + // no progress. + // + // If you don't respect these rules, it is likely that your chain will be attackable. + fn accumulate_dummy(_aux: &T::PublicAux, increase_by: T::Balance) -> Result { + // Read the value of dummy from storage. + let dummy = Self::dummy(); + // Will also work using the `::get` on the storage item type iself: + // let dummy = >::get(); + + // Calculate the new value. + let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); + + // Put the new value into storage. + >::put(new_dummy); + // Will also work with a reference: + // >::put(&new_dummy); + + // Let's deposit an event to let the outside world know this happened. + Self::deposit_event(RawEvent::Dummy(increase_by)); + + // All good. + Ok(()) + } + + // Implementation of a priviledged call. This doesn't have an `aux` parameter because + // it's not (directly) from an extrinsic, but rather the system as a whole has decided + // to execute it. Different runtimes have different reasons for allow priviledged + // calls to be executed - we don't need to care why. Because it's priviledged, we can + // assume it's a one-off operation and substantial processing/storage/memory can be used + // without worrying about gameability or attack scenarios. + fn set_dummy(new_value: T::Balance) -> Result { + // Put the new value into storage. + >::put(new_value); + + // All good. + Ok(()) + } +} + +// This trait expresses what should happen when the block is finalised. +impl OnFinalise for Module { + fn on_finalise(_: T::BlockNumber) { + // Anything that needs to be done at the end of the block. + // We just kill our dummy storage item. + >::kill(); + } +} + +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +/// The genesis block configuration type. This is a simple default-capable struct that +/// contains any fields with which this module can be configured at genesis time. +pub struct GenesisConfig { + /// A value with which to initialise the Dummy storage item. + pub dummy: T::Balance, +} + +#[cfg(feature = "std")] +impl Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { + dummy: Default::default(), + } + } +} + +// This expresses the specific key/value pairs that must be placed in storage in order +// to initialise the module and properly reflect the configuration. +// +// Ideally this would re-use the `::put` logic in the storage item type for introducing +// the values into the `StorageMap` (which is just a `HashMap, Vec>`). That +// is not yet in place, though, so for now we do everything "manually", using `hash`, +// `::key()` and `.to_vec()` for the key and `.encode()` for the value. +#[cfg(feature = "std")] +impl runtime_primitives::BuildStorage for GenesisConfig +{ + fn build_storage(self) -> ::std::result::Result { + use codec::Encode; + Ok(map![ + Self::hash(>::key()).to_vec() => self.dummy.encode() + ]) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use runtime_io::with_externalities; + use substrate_primitives::{H256, KeccakHasher}; + use runtime_primitives::BuildStorage; + use runtime_primitives::traits::{BlakeTwo256}; + + // The testing primitives are very useful for avoiding having to work with signatures + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. + use runtime_primitives::testing::{Digest, Header}; + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + impl system::Trait for Test { + type PublicAux = Self::AccountId; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type Digest = Digest; + type AccountId = u64; + type Header = Header; + type Event = (); + } + impl balances::Trait for Test { + type Balance = u64; + type AccountIndex = u64; + type OnFreeBalanceZero = (); + type EnsureAccountLiquid = (); + type Event = (); + } + impl Trait for Test { + type Event = (); + } + type Example = Module; + + // This function basically just builds a genesis storage key/value store according to + // our desired mockup. + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::::default().build_storage().unwrap(); + // We use default for brevity, but you can configure as desired if needed. + t.extend(balances::GenesisConfig::::default().build_storage().unwrap()); + t.extend(GenesisConfig::{ + dummy: 42, + }.build_storage().unwrap()); + t.into() + } + + #[test] + fn it_works() { + with_externalities(&mut new_test_ext(), || { + // Check that GenesisBuilder works properly. + assert_eq!(Example::dummy(), Some(42)); + + // Check that accumulate works when we have Some value in Dummy already. + assert_ok!(Example::accumulate_dummy(&0, 27)); + assert_eq!(Example::dummy(), Some(69)); + + // Check that finalising the block removes Dummy from storage. + >::on_finalise(1); + assert_eq!(Example::dummy(), None); + + // Check that accumulate works when we Dummy has None in it. + assert_ok!(Example::accumulate_dummy(&0, 42)); + assert_eq!(Example::dummy(), Some(42)); + }); + } +} diff --git a/substrate/runtime/executive/src/lib.rs b/substrate/runtime/executive/src/lib.rs index 6068c61361360..caaf91a75617d 100644 --- a/substrate/runtime/executive/src/lib.rs +++ b/substrate/runtime/executive/src/lib.rs @@ -62,7 +62,7 @@ extern crate substrate_runtime_staking as staking; use rstd::prelude::*; use rstd::marker::PhantomData; use rstd::result; -use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, Executable, +use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, OnFinalise, MakePayment, Hash, AuxLookup}; use codec::{Codec, Encode}; use system::extrinsics_root; @@ -96,7 +96,7 @@ impl< Block: traits::Block, Lookup: AuxLookup, Payment: MakePayment, - Finalisation: Executable, + Finalisation: OnFinalise, > Executive where Block::Extrinsic: Checkable Result> + Codec, Result>>::Checked: Applyable @@ -135,7 +135,7 @@ impl< // post-transactional book-keeping. >::note_finished_extrinsics(); - Finalisation::execute(); + Finalisation::on_finalise(*header.number()); // any final checks Self::final_checks(&header); @@ -145,7 +145,7 @@ impl< /// except state-root. pub fn finalise_block() -> System::Header { >::note_finished_extrinsics(); - Finalisation::execute(); + Finalisation::on_finalise(>::block_number()); // setup extrinsics >::derive_extrinsics(); @@ -231,7 +231,7 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, KeccakHasher}; use primitives::BuildStorage; - use primitives::traits::{HasPublicAux, Identity, Header as HeaderT, BlakeTwo256, AuxLookup}; + use primitives::traits::{Identity, Header as HeaderT, BlakeTwo256, AuxLookup}; use primitives::testing::{Digest, Header, Block}; use system; @@ -253,9 +253,6 @@ mod tests { // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub struct Test; - impl HasPublicAux for Test { - type PublicAux = u64; - } impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; type SessionKey = u64; @@ -269,7 +266,7 @@ mod tests { type Event = MetaEvent; } impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = substrate_primitives::H256; @@ -285,6 +282,7 @@ mod tests { type Event = MetaEvent; } impl staking::Trait for Test { + type OnRewardMinted = (); type Event = MetaEvent; } impl timestamp::Trait for Test { diff --git a/substrate/runtime/primitives/src/traits.rs b/substrate/runtime/primitives/src/traits.rs index e544bca32db96..848d7bcc35293 100644 --- a/substrate/runtime/primitives/src/traits.rs +++ b/substrate/runtime/primitives/src/traits.rs @@ -118,10 +118,6 @@ impl MaybeEmpty for T { } } -pub trait HasPublicAux { - type PublicAux: MaybeEmpty; -} - pub trait RefInto { fn ref_into(&self) -> &T; } @@ -184,18 +180,18 @@ impl > SimpleBitOps for T {} -/// Something that can be executed. -pub trait Executable { - fn execute(); +/// The block finalisation trait. Implementing this lets you express what should happen +/// for your module when the block is ending. +pub trait OnFinalise { + /// The block is being finalised. Implement to have something happen. + fn on_finalise(_n: BlockNumber) {} } -impl Executable for () { - fn execute() {} -} -impl Executable for (A, B) { - fn execute() { - A::execute(); - B::execute(); +impl OnFinalise for () {} +impl, B: OnFinalise> OnFinalise for (A, B) { + fn on_finalise(n: N) { + A::on_finalise(n); + B::on_finalise(n); } } diff --git a/substrate/runtime/session/src/lib.rs b/substrate/runtime/session/src/lib.rs index 75dad0adae76d..1e4ac22e78197 100644 --- a/substrate/runtime/session/src/lib.rs +++ b/substrate/runtime/session/src/lib.rs @@ -49,7 +49,7 @@ extern crate substrate_runtime_system as system; extern crate substrate_runtime_timestamp as timestamp; use rstd::prelude::*; -use primitives::traits::{Zero, One, RefInto, Executable, Convert, As}; +use primitives::traits::{Zero, One, RefInto, OnFinalise, Convert, As}; use runtime_support::{StorageValue, StorageMap}; use runtime_support::dispatch::Result; @@ -114,10 +114,6 @@ decl_storage! { // Timestamp when current session started. pub CurrentStart get(current_start): required T::Moment; - // Opinions of the current validator set about the activeness of their peers. - // Gets cleared when the validator set changes. - pub BadValidators get(bad_validators): Vec; - // New session is being forced is this entry exists; in which case, the boolean value is whether // the new session should be considered a normal rotation (rewardable) or exceptional (slashable). pub ForcingNewSession get(forcing_new_session): bool; @@ -175,11 +171,10 @@ impl Module { } /// Hook to be called after transaction processing. - pub fn check_rotate_session() { + pub fn check_rotate_session(block_number: T::BlockNumber) { // do this last, after the staking system has had chance to switch out the authorities for the // new set. // check block number and call next_session if necessary. - let block_number = >::block_number(); let is_final_block = ((block_number - Self::last_length_change()) % Self::length()).is_zero(); let (should_end_session, apply_rewards) = >::take() .map_or((is_final_block, is_final_block), |apply_rewards| (true, apply_rewards)); @@ -245,9 +240,9 @@ impl Module { } } -impl Executable for Module { - fn execute() { - Self::check_rotate_session(); +impl OnFinalise for Module { + fn on_finalise(n: T::BlockNumber) { + Self::check_rotate_session(n); } } @@ -293,21 +288,18 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::{H256, KeccakHasher}; use primitives::BuildStorage; - use primitives::traits::{HasPublicAux, Identity, BlakeTwo256}; + use primitives::traits::{Identity, BlakeTwo256}; use primitives::testing::{Digest, Header}; #[derive(Clone, Eq, PartialEq)] pub struct Test; - impl HasPublicAux for Test { - type PublicAux = u64; - } impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; type SessionKey = u64; type OnOfflineValidator = (); } impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -362,28 +354,28 @@ mod tests { System::set_block_number(1); assert_ok!(Session::set_length(10)); assert_eq!(Session::blocks_remaining(), 1); - Session::check_rotate_session(); + Session::check_rotate_session(1); System::set_block_number(2); assert_eq!(Session::blocks_remaining(), 0); - Session::check_rotate_session(); + Session::check_rotate_session(2); assert_eq!(Session::length(), 10); System::set_block_number(7); assert_eq!(Session::current_index(), 1); assert_eq!(Session::blocks_remaining(), 5); assert_ok!(Session::force_new_session(false)); - Session::check_rotate_session(); + Session::check_rotate_session(7); System::set_block_number(8); assert_eq!(Session::current_index(), 2); assert_eq!(Session::blocks_remaining(), 9); - Session::check_rotate_session(); + Session::check_rotate_session(8); System::set_block_number(17); assert_eq!(Session::current_index(), 2); assert_eq!(Session::blocks_remaining(), 0); - Session::check_rotate_session(); + Session::check_rotate_session(17); System::set_block_number(18); assert_eq!(Session::current_index(), 3); @@ -396,45 +388,45 @@ mod tests { // Block 1: Change to length 3; no visible change. System::set_block_number(1); assert_ok!(Session::set_length(3)); - Session::check_rotate_session(); + Session::check_rotate_session(1); assert_eq!(Session::length(), 2); assert_eq!(Session::current_index(), 0); // Block 2: Length now changed to 3. Index incremented. System::set_block_number(2); assert_ok!(Session::set_length(3)); - Session::check_rotate_session(); + Session::check_rotate_session(2); assert_eq!(Session::length(), 3); assert_eq!(Session::current_index(), 1); // Block 3: Length now changed to 3. Index incremented. System::set_block_number(3); - Session::check_rotate_session(); + Session::check_rotate_session(3); assert_eq!(Session::length(), 3); assert_eq!(Session::current_index(), 1); // Block 4: Change to length 2; no visible change. System::set_block_number(4); assert_ok!(Session::set_length(2)); - Session::check_rotate_session(); + Session::check_rotate_session(4); assert_eq!(Session::length(), 3); assert_eq!(Session::current_index(), 1); // Block 5: Length now changed to 2. Index incremented. System::set_block_number(5); - Session::check_rotate_session(); + Session::check_rotate_session(5); assert_eq!(Session::length(), 2); assert_eq!(Session::current_index(), 2); // Block 6: No change. System::set_block_number(6); - Session::check_rotate_session(); + Session::check_rotate_session(6); assert_eq!(Session::length(), 2); assert_eq!(Session::current_index(), 2); // Block 7: Next index. System::set_block_number(7); - Session::check_rotate_session(); + Session::check_rotate_session(7); assert_eq!(Session::length(), 2); assert_eq!(Session::current_index(), 3); }); @@ -445,12 +437,12 @@ mod tests { with_externalities(&mut new_test_ext(), || { // Block 1: No change System::set_block_number(1); - Session::check_rotate_session(); + Session::check_rotate_session(1); assert_eq!(Consensus::authorities(), vec![1, 2, 3]); // Block 2: Session rollover, but no change. System::set_block_number(2); - Session::check_rotate_session(); + Session::check_rotate_session(2); assert_eq!(Consensus::authorities(), vec![1, 2, 3]); // Block 3: Set new key for validator 2; no visible change. @@ -458,12 +450,12 @@ mod tests { assert_ok!(Session::set_key(&2, 5)); assert_eq!(Consensus::authorities(), vec![1, 2, 3]); - Session::check_rotate_session(); + Session::check_rotate_session(3); assert_eq!(Consensus::authorities(), vec![1, 2, 3]); // Block 4: Session rollover, authority 2 changes. System::set_block_number(4); - Session::check_rotate_session(); + Session::check_rotate_session(4); assert_eq!(Consensus::authorities(), vec![1, 5, 3]); }); } diff --git a/substrate/runtime/staking/src/lib.rs b/substrate/runtime/staking/src/lib.rs index 52135db63947e..18fea81cf5a99 100644 --- a/substrate/runtime/staking/src/lib.rs +++ b/substrate/runtime/staking/src/lib.rs @@ -49,9 +49,9 @@ use rstd::prelude::*; use runtime_support::{Parameter, StorageValue, StorageMap}; use runtime_support::dispatch::Result; use session::OnSessionChange; -use primitives::traits::{Zero, One, Bounded, RefInto, Executable, +use primitives::traits::{Zero, One, Bounded, RefInto, OnFinalise, As, AuxLookup}; -use balances::address::Address; +use balances::{address::Address, OnMinted}; mod mock; @@ -96,6 +96,9 @@ impl Default for ValidatorPrefs { } */ pub trait Trait: balances::Trait + session::Trait { + /// Some tokens minted. + type OnRewardMinted: OnMinted<::Balance>; + /// The overarching event type. type Event: From> + Into<::Event>; } @@ -435,10 +438,12 @@ impl Module { if should_reward { // apply good session reward let reward = Self::this_session_reward(actual_elapsed); - for v in >::validators().iter() { + let validators = >::validators(); + for v in validators.iter() { Self::reward_validator(v, reward); } Self::deposit_event(RawEvent::Reward(reward)); + T::OnRewardMinted::on_minted(reward * >::sa(validators.len())); } let session_index = >::current_index(); @@ -507,8 +512,8 @@ impl Module { } } -impl Executable for Module { - fn execute() { +impl OnFinalise for Module { + fn on_finalise(_n: T::BlockNumber) { } } diff --git a/substrate/runtime/staking/src/mock.rs b/substrate/runtime/staking/src/mock.rs index 25447c39cbe23..1f8cc8e02129f 100644 --- a/substrate/runtime/staking/src/mock.rs +++ b/substrate/runtime/staking/src/mock.rs @@ -19,7 +19,7 @@ #![cfg(test)] use primitives::BuildStorage; -use primitives::traits::{HasPublicAux, Identity}; +use primitives::traits::{Identity}; use primitives::testing::{Digest, Header}; use substrate_primitives::{H256, KeccakHasher}; use runtime_io; @@ -28,16 +28,13 @@ use {GenesisConfig, Module, Trait, consensus, session, system, timestamp, balanc // Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub struct Test; -impl HasPublicAux for Test { - type PublicAux = u64; -} impl consensus::Trait for Test { const NOTE_OFFLINE_POSITION: u32 = 1; type SessionKey = u64; type OnOfflineValidator = (); } impl system::Trait for Test { - type PublicAux = ::PublicAux; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -64,6 +61,7 @@ impl timestamp::Trait for Test { type Moment = u64; } impl Trait for Test { + type OnRewardMinted = (); type Event = (); } diff --git a/substrate/runtime/staking/src/tests.rs b/substrate/runtime/staking/src/tests.rs index 8c22ef9977a83..35f203b078535 100644 --- a/substrate/runtime/staking/src/tests.rs +++ b/substrate/runtime/staking/src/tests.rs @@ -177,19 +177,19 @@ fn rewards_should_work() { System::set_block_number(3); Timestamp::set_timestamp(15); // on time. - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); assert_eq!(Balances::total_balance(&10), 11); System::set_block_number(6); Timestamp::set_timestamp(31); // a little late - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 2); assert_eq!(Balances::total_balance(&10), 20); // less reward System::set_block_number(9); Timestamp::set_timestamp(50); // very late - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::current_index(), 3); assert_eq!(Balances::total_balance(&10), 27); // much less reward @@ -207,13 +207,13 @@ fn slashing_should_work() { assert_eq!(Balances::total_balance(&10), 1); System::set_block_number(3); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 1); assert_eq!(Balances::total_balance(&10), 11); System::set_block_number(6); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::current_index(), 2); assert_eq!(Balances::total_balance(&10), 21); @@ -244,13 +244,13 @@ fn staking_should_work() { assert_ok!(Staking::stake(&1)); assert_ok!(Staking::stake(&2)); assert_ok!(Staking::stake(&4)); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 0); assert_eq!(Session::validators(), vec![10, 20]); // Block 2: New validator set now. System::set_block_number(2); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::validators(), vec![4, 2]); @@ -259,33 +259,33 @@ fn staking_should_work() { assert_ok!(Staking::stake(&3)); assert_ok!(Staking::unstake(&4, Staking::intentions().iter().position(|&x| x == 4).unwrap() as u32)); assert_eq!(Staking::current_era(), 1); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); // Block 4: New era - validators change. System::set_block_number(4); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 2); assert_eq!(Session::validators(), vec![3, 2]); // Block 5: Transfer stake from highest to lowest. No change yet. System::set_block_number(5); assert_ok!(Balances::transfer(&4, 1.into(), 40)); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); // Block 6: Lowest now validator. System::set_block_number(6); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::validators(), vec![1, 3]); // Block 7: Unstake three. No change yet. System::set_block_number(7); assert_ok!(Staking::unstake(&3, Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32)); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::validators(), vec![1, 3]); // Block 8: Back to one and two. System::set_block_number(8); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::validators(), vec![1, 2]); }); } @@ -303,7 +303,7 @@ fn nominating_and_rewards_should_work() { assert_ok!(Staking::stake(&2)); assert_ok!(Staking::stake(&3)); assert_ok!(Staking::nominate(&4, 1.into())); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::validators(), vec![1, 3]); // 4 + 1, 3 assert_eq!(Balances::total_balance(&1), 10); @@ -313,7 +313,7 @@ fn nominating_and_rewards_should_work() { System::set_block_number(2); assert_ok!(Staking::unnominate(&4, 0)); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 2); assert_eq!(Session::validators(), vec![3, 2]); assert_eq!(Balances::total_balance(&1), 12); @@ -325,7 +325,7 @@ fn nominating_and_rewards_should_work() { assert_ok!(Staking::stake(&4)); assert_ok!(Staking::unstake(&3, Staking::intentions().iter().position(|&x| x == 3).unwrap() as u32)); assert_ok!(Staking::nominate(&3, 1.into())); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::validators(), vec![1, 4]); assert_eq!(Balances::total_balance(&1), 12); assert_eq!(Balances::total_balance(&2), 30); @@ -333,7 +333,7 @@ fn nominating_and_rewards_should_work() { assert_eq!(Balances::total_balance(&4), 48); System::set_block_number(4); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Balances::total_balance(&1), 13); assert_eq!(Balances::total_balance(&2), 30); assert_eq!(Balances::total_balance(&3), 58); @@ -372,7 +372,7 @@ fn nominating_slashes_should_work() { assert_eq!(Session::validators(), vec![10, 20]); System::set_block_number(2); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); Timestamp::set_timestamp(15); System::set_block_number(4); @@ -380,7 +380,7 @@ fn nominating_slashes_should_work() { assert_ok!(Staking::stake(&3)); assert_ok!(Staking::nominate(&2, 3.into())); assert_ok!(Staking::nominate(&4, 1.into())); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Staking::current_era(), 1); assert_eq!(Session::validators(), vec![1, 3]); // 1 + 4, 3 + 2 @@ -424,7 +424,7 @@ fn staking_eras_work() { // Block 1: No change. System::set_block_number(1); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 1); assert_eq!(Staking::sessions_per_era(), 2); assert_eq!(Staking::last_era_length_change(), 0); @@ -432,7 +432,7 @@ fn staking_eras_work() { // Block 2: Simple era change. System::set_block_number(2); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 2); assert_eq!(Staking::sessions_per_era(), 2); assert_eq!(Staking::last_era_length_change(), 0); @@ -441,7 +441,7 @@ fn staking_eras_work() { // Block 3: Schedule an era length change; no visible changes. System::set_block_number(3); assert_ok!(Staking::set_sessions_per_era(3)); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 3); assert_eq!(Staking::sessions_per_era(), 2); assert_eq!(Staking::last_era_length_change(), 0); @@ -449,7 +449,7 @@ fn staking_eras_work() { // Block 4: Era change kicks in. System::set_block_number(4); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 4); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 4); @@ -457,7 +457,7 @@ fn staking_eras_work() { // Block 5: No change. System::set_block_number(5); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 5); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 4); @@ -465,7 +465,7 @@ fn staking_eras_work() { // Block 6: No change. System::set_block_number(6); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 6); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 4); @@ -473,7 +473,7 @@ fn staking_eras_work() { // Block 7: Era increment. System::set_block_number(7); - Session::check_rotate_session(); + Session::check_rotate_session(System::block_number()); assert_eq!(Session::current_index(), 7); assert_eq!(Staking::sessions_per_era(), 3); assert_eq!(Staking::last_era_length_change(), 4); diff --git a/substrate/runtime/timestamp/src/lib.rs b/substrate/runtime/timestamp/src/lib.rs index 80781ab075b64..5d9fdad118eb5 100644 --- a/substrate/runtime/timestamp/src/lib.rs +++ b/substrate/runtime/timestamp/src/lib.rs @@ -40,7 +40,7 @@ extern crate substrate_codec as codec; use runtime_support::{StorageValue, Parameter}; use runtime_support::dispatch::Result; -use runtime_primitives::traits::{Executable, MaybeEmpty, SimpleArithmetic, As, Zero}; +use runtime_primitives::traits::{OnFinalise, MaybeEmpty, SimpleArithmetic, As, Zero}; pub trait Trait: consensus::Trait where ::PublicAux: MaybeEmpty @@ -101,8 +101,8 @@ impl Module { } } -impl Executable for Module { - fn execute() { +impl OnFinalise for Module { + fn on_finalise(_n: T::BlockNumber) { assert!(::DidUpdate::take(), "Timestamp must be updated once in the block"); } } @@ -143,16 +143,13 @@ mod tests { use runtime_io::with_externalities; use substrate_primitives::H256; use runtime_primitives::BuildStorage; - use runtime_primitives::traits::{HasPublicAux, BlakeTwo256}; + use runtime_primitives::traits::{BlakeTwo256}; use runtime_primitives::testing::{Digest, Header}; #[derive(Clone, Eq, PartialEq)] pub struct Test; - impl HasPublicAux for Test { - type PublicAux = u64; - } impl system::Trait for Test { - type PublicAux = u64; + type PublicAux = Self::AccountId; type Index = u64; type BlockNumber = u64; type Hash = H256; diff --git a/substrate/runtime/treasury/Cargo.toml b/substrate/runtime/treasury/Cargo.toml new file mode 100644 index 0000000000000..0c76961434c2c --- /dev/null +++ b/substrate/runtime/treasury/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "substrate-runtime-treasury" +version = "0.1.0" +authors = ["Parity Technologies "] + +[dependencies] +hex-literal = "0.1.0" +serde = { version = "1.0", default_features = false } +serde_derive = { version = "1.0", optional = true } +substrate-runtime-std = { path = "../../runtime-std", default_features = false } +substrate-runtime-io = { path = "../../runtime-io", default_features = false } +substrate-runtime-support = { path = "../../runtime-support", default_features = false } +substrate-runtime-primitives = { path = "../primitives", default_features = false } +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-system = { path = "../system", default_features = false } +substrate-runtime-balances = { path = "../balances", default_features = false } + +[features] +default = ["std"] +std = [ + "substrate-runtime-std/std", + "substrate-runtime-io/std", + "substrate-runtime-support/std", + "substrate-runtime-primitives/std", + "substrate-runtime-balances/std", + "serde/std", + "serde_derive", + "substrate-codec/std", + "substrate-codec-derive/std", + "substrate-primitives/std", + "substrate-runtime-system/std", +] diff --git a/substrate/runtime/treasury/src/lib.rs b/substrate/runtime/treasury/src/lib.rs new file mode 100644 index 0000000000000..9ecff48f38cc4 --- /dev/null +++ b/substrate/runtime/treasury/src/lib.rs @@ -0,0 +1,558 @@ +// 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 . + +//! The Treasury: Keeps account of the taxed cash and handles its deployment. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg_attr(any(feature = "std", test), macro_use)] +extern crate substrate_runtime_std as rstd; + +#[macro_use] +extern crate substrate_runtime_support as runtime_support; + +#[cfg(any(feature = "std", test))] +extern crate substrate_runtime_io as runtime_io; + +#[cfg(feature = "std")] +#[macro_use] +extern crate serde_derive; + +#[macro_use] +extern crate substrate_codec_derive; + +extern crate substrate_codec as codec; +#[cfg(test)] +extern crate substrate_primitives; +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 runtime_support::{StorageValue, StorageMap}; +use runtime_support::dispatch::Result; +use runtime_primitives::traits::{As, OnFinalise, Zero, RefInto}; +use balances::OnMinted; + +/// Our module's configuration trait. All our types and consts go in here. If the +/// module is dependent on specific other modules, then their configuration traits +/// should be added to our implied traits list. +/// +/// `system::Trait` should always be included in our implied traits. +pub trait Trait: balances::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; +} + +type ProposalIndex = u32; + +// The module declaration. This states the entry points that we handle. The +// macro takes care of the marshalling of arguments and dispatch. +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what its working on. + pub struct Module; + + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + pub enum Call where aux: T::PublicAux { + // Put forward a suggestion for spending. A deposit proportional to the value + // is reserved and slashed if the proposal is rejected. It is returned once the + // proposal is awarded. + fn propose_spend(aux, value: T::Balance, beneficiary: T::AccountId) -> Result = 0; + } + + // The priviledged entry points. These are provided to allow any governance modules in + // the runtime to be able to execute common functions. Unlike for `Call` there is no + // auxilliary data to encode the sender (since there is no sender). Though still important + // to ensure that these execute in reasonable time and space, they can do what would + // otherwise be costly or unsafe operations. + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + pub enum PrivCall { + // Set the balance of funds available to spend. + fn set_pot(new_pot: T::Balance) -> Result = 0; + + // (Re-)configure this module. + fn configure(proposal_bond: Permill, proposal_bond_minimum: T::Balance, spend_period: T::BlockNumber, burn: Permill) -> Result = 1; + + // Reject a proposed spend. The original deposit will be slashed. + fn reject_proposal(proposal_id: ProposalIndex) -> Result = 2; + + // Approve a proposal. At a later time, the proposal will be allocated to the beneficiary + // and the original deposit will be returned. + fn approve_proposal(proposal_id: ProposalIndex) -> Result = 3; + } +} + +/// A spending proposal. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, Clone, PartialEq, Eq)] +pub struct Proposal { + proposer: AccountId, + value: Balance, + beneficiary: AccountId, + 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... + + // Proportion of funds that should be bonded in order to place a proposal. An accepted + // proposal gets these back. A rejected proposal doesn't. + ProposalBond get(proposal_bond): required Permill; + + // Minimum amount of funds that should be placed ina deposit for making a proposal. + ProposalBondMinimum get(proposal_bond_minimum): required T::Balance; + + // Period between successive spends. + SpendPeriod get(spend_period): required T::BlockNumber; + + // Percentage of spare funds (if any) that are burnt per spend period. + Burn get(burn): required Permill; + + // State... + + // Total funds available to this module for spending. + Pot get(pot): default T::Balance; + + // Number of proposals that have been made. + ProposalCount get(proposal_count): default ProposalIndex; + + // Proposals that have been made. + Proposals get(proposals): map [ ProposalIndex => Proposal ]; + + // Proposal indices that have been approved but not yet awarded. + Approvals get(approvals): default Vec; + } +} + +/// Exported Event type that's generic over the configuration trait. +pub type Event = RawEvent< + ::Balance, + ::AccountId, +>; + +/// An event in this module. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))] +#[derive(Encode, Decode, PartialEq, Eq, Clone)] +pub enum RawEvent { + /// New proposal. + Proposed(ProposalIndex), + /// We have ended a spend period and will now allocate funds. + Spending(Balance), + /// Some funds have been allocated. + Awarded(ProposalIndex, Balance, AccountId), + /// Some of our funds have been burnt. + Burnt(Balance), + /// Spending has finished; this is the amount that rolls over until next spend. + Rollover(Balance), +} + +impl From> for () { + fn from(_: RawEvent) -> () { () } +} + +impl Module { + /// Deposit one of this module's events. + fn deposit_event(event: Event) { + >::deposit_event(::Event::from(event).into()); + } + + // Implement Calls/PrivCalls and add public immutables and private mutables. + + fn propose_spend(aux: &T::PublicAux, value: T::Balance, beneficiary: T::AccountId) -> Result { + let proposer = aux.ref_into(); + + let bond = Self::calculate_bond(value); + >::reserve(proposer, bond) + .map_err(|_| "Proposer's balance too low")?; + + let c = Self::proposal_count(); + >::put(c + 1); + >::insert(c, Proposal { proposer: proposer.clone(), value, beneficiary, bond }); + + Self::deposit_event(RawEvent::Proposed(c)); + + Ok(()) + } + + fn reject_proposal(proposal_id: ProposalIndex) -> Result { + let proposal = >::take(proposal_id).ok_or("No proposal at that index")?; + + let value = proposal.bond; + let _ = >::slash_reserved(&proposal.proposer, value); + + Ok(()) + } + + fn approve_proposal(proposal_id: ProposalIndex) -> Result { + ensure!(>::exists(proposal_id), "No proposal at that index"); + + { + let mut v = >::get(); + v.push(proposal_id); + >::put(v); + } + //TODO gav: make work: + //>::mutate(|a| a.push(proposal_id)); + + Ok(()) + } + + fn set_pot(new_pot: T::Balance) -> Result { + // Put the new value into storage. + >::put(new_pot); + + // All good. + Ok(()) + } + + fn configure( + proposal_bond: Permill, + proposal_bond_minimum: T::Balance, + spend_period: T::BlockNumber, + burn: Permill + ) -> Result { + >::put(proposal_bond); + >::put(proposal_bond_minimum); + >::put(spend_period); + >::put(burn); + Ok(()) + } + + /// The needed bond for a proposal whose spend is `value`. + fn calculate_bond(value: T::Balance) -> T::Balance { + Self::proposal_bond_minimum().max(Self::proposal_bond().times(value)) + } + + // Spend some money! + fn spend_funds() { + let mut budget_remaining = Self::pot(); + Self::deposit_event(RawEvent::Spending(budget_remaining)); + + let mut missed_any = false; + let remaining_approvals: Vec<_> = >::get().into_iter().filter(|&index| { + // Should always be true, but shouldn't panic if false or we're screwed. + if let Some(p) = Self::proposals(index) { + if p.value <= budget_remaining { + budget_remaining -= p.value; + >::remove(index); + + // return their deposit. + let _ = >::unreserve(&p.proposer, p.bond); + + // provide the allocation. + >::increase_free_balance_creating(&p.beneficiary, p.value); + + Self::deposit_event(RawEvent::Awarded(index, p.value, p.beneficiary)); + false + } else { + missed_any = true; + true + } + } else { + false + } + }).collect(); + >::put(remaining_approvals); + + if !missed_any { + // burn some proportion of the remaining budget if we run a surplus. + let burn = Self::burn().times(budget_remaining); + budget_remaining -= burn; + Self::deposit_event(RawEvent::Burnt(burn)) + } + + Self::deposit_event(RawEvent::Rollover(budget_remaining)); + + >::put(budget_remaining); + } +} + +impl OnMinted for Module { + fn on_minted(b: T::Balance) { + >::put(Self::pot() + b); + } +} + +impl OnFinalise for Module { + fn on_finalise(n: T::BlockNumber) { + // Check to see if we should spend some funds! + if (n % Self::spend_period()).is_zero() { + Self::spend_funds(); + } + } +} + +#[cfg(any(feature = "std", test))] +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] +/// The genesis block configuration type. This is a simple default-capable struct that +/// contains any fields with which this module can be configured at genesis time. +pub struct GenesisConfig { + pub proposal_bond: Permill, + pub proposal_bond_minimum: T::Balance, + pub spend_period: T::BlockNumber, + pub burn: Permill, +} + +#[cfg(any(feature = "std", test))] +impl Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { + proposal_bond: Default::default(), + proposal_bond_minimum: Default::default(), + spend_period: Default::default(), + burn: Default::default(), + } + } +} + +#[cfg(any(feature = "std", test))] +impl runtime_primitives::BuildStorage for GenesisConfig +{ + fn build_storage(self) -> ::std::result::Result { + use codec::Encode; + Ok(map![ + Self::hash(>::key()).to_vec() => self.proposal_bond.encode(), + Self::hash(>::key()).to_vec() => self.proposal_bond_minimum.encode(), + Self::hash(>::key()).to_vec() => self.spend_period.encode(), + Self::hash(>::key()).to_vec() => self.burn.encode() + ]) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use runtime_io::with_externalities; + use substrate_primitives::{H256, KeccakHasher}; + use runtime_primitives::BuildStorage; + use runtime_primitives::traits::{BlakeTwo256}; + use runtime_primitives::testing::{Digest, Header}; + + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + impl system::Trait for Test { + type PublicAux = Self::AccountId; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type Digest = Digest; + type AccountId = u64; + type Header = Header; + type Event = (); + } + impl balances::Trait for Test { + type Balance = u64; + type AccountIndex = u64; + type OnFreeBalanceZero = (); + type EnsureAccountLiquid = (); + type Event = (); + } + impl Trait for Test { + type Event = (); + } + type Balances = balances::Module; + type Treasury = Module; + + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::::default().build_storage().unwrap(); + t.extend(balances::GenesisConfig::{ + balances: vec![(0, 100), (1, 10), (2, 1)], + transaction_base_fee: 0, + transaction_byte_fee: 0, + transfer_fee: 0, + creation_fee: 0, + existential_deposit: 0, + reclaim_rebate: 0, + }.build_storage().unwrap()); + t.extend(GenesisConfig::{ + proposal_bond: Permill(50_000), // 5% + proposal_bond_minimum: 1, + spend_period: 2, + burn: Permill(500_000), // 50% + }.build_storage().unwrap()); + t.into() + } + + #[test] + fn genesis_config_works() { + with_externalities(&mut new_test_ext(), || { + assert_eq!(Treasury::proposal_bond(), Permill(50_000)); + assert_eq!(Treasury::proposal_bond_minimum(), 1); + assert_eq!(Treasury::spend_period(), 2); + assert_eq!(Treasury::burn(), Permill(500_000)); + assert_eq!(Treasury::pot(), 0); + assert_eq!(Treasury::proposal_count(), 0); + }); + } + + #[test] + fn minting_works() { + with_externalities(&mut new_test_ext(), || { + // Check that accumulate works when we have Some value in Dummy already. + Treasury::on_minted(100); + assert_eq!(Treasury::pot(), 100); + }); + } + + #[test] + fn spend_proposal_takes_min_deposit() { + with_externalities(&mut new_test_ext(), || { + assert_ok!(Treasury::propose_spend(&0, 1, 3)); + assert_eq!(Balances::free_balance(&0), 99); + assert_eq!(Balances::reserved_balance(&0), 1); + }); + } + + #[test] + fn spend_proposal_takes_proportional_deposit() { + with_externalities(&mut new_test_ext(), || { + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_eq!(Balances::free_balance(&0), 95); + assert_eq!(Balances::reserved_balance(&0), 5); + }); + } + + #[test] + fn spend_proposal_fails_when_proposer_poor() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Treasury::propose_spend(&2, 100, 3), "Proposer's balance too low"); + }); + } + + #[test] + fn accepted_spend_proposal_ignored_outside_spend_period() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_ok!(Treasury::approve_proposal(0)); + + >::on_finalise(1); + assert_eq!(Balances::free_balance(&3), 0); + assert_eq!(Treasury::pot(), 100); + }); + } + + #[test] + fn unused_pot_should_diminish() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + >::on_finalise(2); + assert_eq!(Treasury::pot(), 50); + }); + } + + #[test] + fn rejected_spend_proposal_ignored_on_spend_period() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_ok!(Treasury::reject_proposal(0)); + + >::on_finalise(2); + assert_eq!(Balances::free_balance(&3), 0); + assert_eq!(Treasury::pot(), 50); + }); + } + + #[test] + fn reject_already_rejected_spend_proposal_fails() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_ok!(Treasury::reject_proposal(0)); + assert_noop!(Treasury::reject_proposal(0), "No proposal at that index"); + }); + } + + #[test] + fn reject_non_existant_spend_proposal_fails() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Treasury::reject_proposal(0), "No proposal at that index"); + }); + } + + #[test] + fn accept_non_existant_spend_proposal_fails() { + with_externalities(&mut new_test_ext(), || { + assert_noop!(Treasury::approve_proposal(0), "No proposal at that index"); + }); + } + + #[test] + fn accept_already_rejected_spend_proposal_fails() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_ok!(Treasury::reject_proposal(0)); + assert_noop!(Treasury::approve_proposal(0), "No proposal at that index"); + }); + } + + #[test] + fn accepted_spend_proposal_enacted_on_spend_period() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 100, 3)); + assert_ok!(Treasury::approve_proposal(0)); + + >::on_finalise(2); + assert_eq!(Balances::free_balance(&3), 100); + assert_eq!(Treasury::pot(), 0); + }); + } + + #[test] + fn pot_underflow_should_not_diminish() { + with_externalities(&mut new_test_ext(), || { + Treasury::on_minted(100); + + assert_ok!(Treasury::propose_spend(&0, 150, 3)); + assert_ok!(Treasury::approve_proposal(0)); + + >::on_finalise(2); + assert_eq!(Treasury::pot(), 100); + + Treasury::on_minted(100); + >::on_finalise(4); + assert_eq!(Balances::free_balance(&3), 150); + assert_eq!(Treasury::pot(), 25); + }); + } +}