Introduce treasury and document (#646)

* Introduce treasury and document

* Revert bad changes

* More reversions

* Add example crate

- Remove HasPublicAux
- Rename Concrete -> Runtime

* Actually commit stuff

* Changes

* Propagate block number in finalise.

* Fix and build example

* Fixes.

* Fix compilation for treasury.

* Fix the treasury test

* Tests

* Fix.

* Fix tests

* Fix a few grumbles

* Fixes

* Fix grumbles
This commit is contained in:
Gav Wood
2018-09-04 17:29:06 +02:00
committed by GitHub
parent 69781a7ccc
commit 7657a2326f
25 changed files with 1480 additions and 216 deletions
+36
View File
@@ -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"
+2
View File
@@ -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",
+50 -50
View File
@@ -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::<Concrete>(bob().into(), 69)),
function: Call::Balances(balances::Call::transfer::<Runtime>(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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::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<KeccakHasher> = map![
twox_128(&<balances::FreeBalance<Concrete>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Concrete>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Concrete>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Concrete>>::key_for(0)).to_vec() => vec![0u8; 32]
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(<balances::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 8],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32]
];
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm");
+29 -32
View File
@@ -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<Concrete>;
pub type Version = version::Module<Runtime>;
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 = <Self as HasPublicAux>::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<Concrete>;
pub type System = system::Module<Runtime>;
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<Concrete>;
pub type Balances = balances::Module<Runtime>;
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<Concrete>;
pub type Consensus = consensus::Module<Runtime>;
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<Concrete>;
pub type Timestamp = timestamp::Module<Runtime>;
/// Session key conversion.
pub struct SessionKeyConversion;
@@ -140,38 +136,39 @@ impl Convert<AccountId, SessionKey> 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<Concrete>;
pub type Session = session::Module<Runtime>;
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<Concrete>;
pub type Staking = staking::Module<Runtime>;
impl democracy::Trait for Concrete {
impl democracy::Trait for Runtime {
type Proposal = PrivCall;
}
/// Democracy module for this concrete runtime.
pub type Democracy = democracy::Module<Concrete>;
pub type Democracy = democracy::Module<Runtime>;
impl council::Trait for Concrete {}
impl council::Trait for Runtime {}
/// Council module for this concrete runtime.
pub type Council = council::Module<Concrete>;
pub type Council = council::Module<Runtime>;
/// Council voting module for this concrete runtime.
pub type CouncilVoting = council::voting::Module<Concrete>;
pub type CouncilVoting = council::voting::Module<Runtime>;
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: <Concrete as HasPublicAux>::PublicAux {
pub enum Call where aux: <Runtime as system::Trait>::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<Concrete>;
pub type Address = balances::Address<Runtime>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256, Vec<u8>>;
/// Block type as expected by this runtime.
@@ -218,11 +215,11 @@ pub type Extrinsic = generic::Extrinsic<Address, Index, Call>;
/// Extrinsic type that is signed.
pub type BareExtrinsic = generic::Extrinsic<AccountId, Index, Call>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Concrete, Block, Balances, Balances,
pub type Executive = executive::Executive<Runtime, Block, Balances, Balances,
(((((), Council), Democracy), Staking), Session)>;
impl_outer_config! {
pub struct GenesisConfig for Concrete {
pub struct GenesisConfig for Runtime {
ConsensusConfig => consensus,
SystemConfig => system,
BalancesConfig => balances,
@@ -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"
@@ -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)*) => {
@@ -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<Balance> {
/// Some balance `b` was minted.
fn on_minted(b: Balance);
}
impl<Balance> OnMinted<Balance> for () {
fn on_minted(_b: Balance) {}
}
/// Determinator for whether a given account is able to transfer balance.
pub trait EnsureAccountLiquid<AccountId> {
/// Returns `Ok` iff the account is able to transfer funds normally. `Err(...)`
@@ -400,6 +410,17 @@ impl<T: Trait> Module<T> {
}
}
/// 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<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
}
}
@@ -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 = <Self as HasPublicAux>::PublicAux;
type PublicAux = Self::AccountId;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -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<T: Trait> balances::OnFreeBalanceZero<T::AccountId> for Module<T> {
}
/// Finalization hook for the smart-contract module.
impl<T: Trait> Executable for Module<T> {
fn execute() {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
<GasSpent<T>>::kill();
}
}
@@ -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 = <Self as HasPublicAux>::PublicAux;
type PublicAux = Self::AccountId;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -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",
@@ -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 = <Self as HasPublicAux>::PublicAux;
type PublicAux = Self::AccountId;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -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<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Council<T> {
fn execute() {
let n = <system::Module<T>>::block_number();
impl<T: Trait> OnFinalise<T::BlockNumber> for Council<T> {
fn on_finalise(n: T::BlockNumber) {
if let Err(e) = Self::end_block(n) {
print("Guru meditation");
print(e);
@@ -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<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
if let Err(e) = Self::end_block(<system::Module<T>>::block_number()) {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
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 = <Self as HasPublicAux>::PublicAux;
type PublicAux = Self::AccountId;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
@@ -0,0 +1,34 @@
[package]
name = "substrate-runtime-example"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[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",
]
@@ -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 <http://www.gnu.org/licenses/>.
//! 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<Event<Self>> + Into<<Self as system::Trait>::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<T: Trait>;
// 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<T> = RawEvent<
<T as balances::Trait>::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<B> {
// 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<B> From<RawEvent<B>> for () {
fn from(_: RawEvent<B>) -> () { () }
}
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<T: Trait> as Example {
// Any storage declarations of the form:
// `pub? Name get(getter_name)? : [required | default]? <type>;`
// where `<type>` 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<T: Trait> Module<T> {
/// Deposit one of this module's events.
// TODO: move into `decl_module` macro.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::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 = <Dummy<T>>::get();
// Calculate the new value.
let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by);
// Put the new value into storage.
<Dummy<T>>::put(new_dummy);
// Will also work with a reference:
// <Dummy<T>>::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.
<Dummy<T>>::put(new_value);
// All good.
Ok(())
}
}
// This trait expresses what should happen when the block is finalised.
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_: T::BlockNumber) {
// Anything that needs to be done at the end of the block.
// We just kill our dummy storage item.
<Dummy<T>>::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<T: Trait> {
/// A value with which to initialise the Dummy storage item.
pub dummy: T::Balance,
}
#[cfg(feature = "std")]
impl<T: Trait> Default for GenesisConfig<T> {
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<u8>, Vec<u8>>`). 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<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_primitives::StorageMap, String> {
use codec::Encode;
Ok(map![
Self::hash(<Dummy<T>>::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<Test>;
// This function basically just builds a genesis storage key/value store according to
// our desired mockup.
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
// We use default for brevity, but you can configure as desired if needed.
t.extend(balances::GenesisConfig::<Test>::default().build_storage().unwrap());
t.extend(GenesisConfig::<Test>{
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.
<Example as OnFinalise<u64>>::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));
});
}
}
@@ -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<Header=System::Header, Hash=System::Hash>,
Lookup: AuxLookup<Source=Address, Target=System::AccountId>,
Payment: MakePayment<System::AccountId>,
Finalisation: Executable,
Finalisation: OnFinalise<System::BlockNumber>,
> Executive<System, Block, Lookup, Payment, Finalisation> where
Block::Extrinsic: Checkable<fn(Address) -> Result<System::AccountId, &'static str>> + Codec,
<Block::Extrinsic as Checkable<fn(Address) -> Result<System::AccountId, &'static str>>>::Checked: Applyable<Index=System::Index, AccountId=System::AccountId>
@@ -135,7 +135,7 @@ impl<
// post-transactional book-keeping.
<system::Module<System>>::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 {
<system::Module<System>>::note_finished_extrinsics();
Finalisation::execute();
Finalisation::on_finalise(<system::Module<System>>::block_number());
// setup extrinsics
<system::Module<System>>::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 = <Self as HasPublicAux>::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 {
@@ -118,10 +118,6 @@ impl<T: Default + PartialEq> MaybeEmpty for T {
}
}
pub trait HasPublicAux {
type PublicAux: MaybeEmpty;
}
pub trait RefInto<T> {
fn ref_into(&self) -> &T;
}
@@ -184,18 +180,18 @@ impl<T:
rstd::ops::BitAnd<Self, Output = Self>
> 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<BlockNumber> {
/// The block is being finalised. Implement to have something happen.
fn on_finalise(_n: BlockNumber) {}
}
impl Executable for () {
fn execute() {}
}
impl<A: Executable, B: Executable> Executable for (A, B) {
fn execute() {
A::execute();
B::execute();
impl<N> OnFinalise<N> for () {}
impl<N: Copy, A: OnFinalise<N>, B: OnFinalise<N>> OnFinalise<N> for (A, B) {
fn on_finalise(n: N) {
A::on_finalise(n);
B::on_finalise(n);
}
}
+23 -31
View File
@@ -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<T::AccountId>;
// 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<T: Trait> Module<T> {
}
/// 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 = <system::Module<T>>::block_number();
let is_final_block = ((block_number - Self::last_length_change()) % Self::length()).is_zero();
let (should_end_session, apply_rewards) = <ForcingNewSession<T>>::take()
.map_or((is_final_block, is_final_block), |apply_rewards| (true, apply_rewards));
@@ -245,9 +240,9 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
Self::check_rotate_session();
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
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 = <Self as HasPublicAux>::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]);
});
}
+10 -5
View File
@@ -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<B: Parameter + Codec + Default> Default for ValidatorPrefs<B> {
}
*/
pub trait Trait: balances::Trait + session::Trait {
/// Some tokens minted.
type OnRewardMinted: OnMinted<<Self as balances::Trait>::Balance>;
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
@@ -435,10 +438,12 @@ impl<T: Trait> Module<T> {
if should_reward {
// apply good session reward
let reward = Self::this_session_reward(actual_elapsed);
for v in <session::Module<T>>::validators().iter() {
let validators = <session::Module<T>>::validators();
for v in validators.iter() {
Self::reward_validator(v, reward);
}
Self::deposit_event(RawEvent::Reward(reward));
T::OnRewardMinted::on_minted(reward * <T::Balance as As<usize>>::sa(validators.len()));
}
let session_index = <session::Module<T>>::current_index();
@@ -507,8 +512,8 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
}
}
@@ -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 = <Self as HasPublicAux>::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 = ();
}
@@ -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);
@@ -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
<Self as system::Trait>::PublicAux: MaybeEmpty
@@ -101,8 +101,8 @@ impl<T: Trait> Module<T> {
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
fn on_finalise(_n: T::BlockNumber) {
assert!(<Self as Store>::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;
@@ -0,0 +1,34 @@
[package]
name = "substrate-runtime-treasury"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[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",
]
@@ -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 <http://www.gnu.org/licenses/>.
//! 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<Event<Self>> + Into<<Self as system::Trait>::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<T: Trait>;
#[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<AccountId, Balance> {
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<Permill> for N where N: As<usize>
impl Permill {
fn times<N: As<usize> + Mul<N, Output=N> + Div<N, Output=N>>(self, b: N) -> N {
// TODO: handle overflows
b * <N as As<usize>>::sa(self.0 as usize) / <N as As<usize>>::sa(1000000)
}
}
decl_storage! {
trait Store for Module<T: Trait> 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<T::AccountId, T::Balance> ];
// Proposal indices that have been approved but not yet awarded.
Approvals get(approvals): default Vec<ProposalIndex>;
}
}
/// Exported Event type that's generic over the configuration trait.
pub type Event<T> = RawEvent<
<T as balances::Trait>::Balance,
<T as system::Trait>::AccountId,
>;
/// An event in this module.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawEvent<Balance, AccountId> {
/// 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<B, A> From<RawEvent<B, A>> for () {
fn from(_: RawEvent<B, A>) -> () { () }
}
impl<T: Trait> Module<T> {
/// Deposit one of this module's events.
fn deposit_event(event: Event<T>) {
<system::Module<T>>::deposit_event(<T as Trait>::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);
<balances::Module<T>>::reserve(proposer, bond)
.map_err(|_| "Proposer's balance too low")?;
let c = Self::proposal_count();
<ProposalCount<T>>::put(c + 1);
<Proposals<T>>::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 = <Proposals<T>>::take(proposal_id).ok_or("No proposal at that index")?;
let value = proposal.bond;
let _ = <balances::Module<T>>::slash_reserved(&proposal.proposer, value);
Ok(())
}
fn approve_proposal(proposal_id: ProposalIndex) -> Result {
ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index");
{
let mut v = <Approvals<T>>::get();
v.push(proposal_id);
<Approvals<T>>::put(v);
}
//TODO gav: make work:
//<Approvals<T>>::mutate(|a| a.push(proposal_id));
Ok(())
}
fn set_pot(new_pot: T::Balance) -> Result {
// Put the new value into storage.
<Pot<T>>::put(new_pot);
// All good.
Ok(())
}
fn configure(
proposal_bond: Permill,
proposal_bond_minimum: T::Balance,
spend_period: T::BlockNumber,
burn: Permill
) -> Result {
<ProposalBond<T>>::put(proposal_bond);
<ProposalBondMinimum<T>>::put(proposal_bond_minimum);
<SpendPeriod<T>>::put(spend_period);
<Burn<T>>::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<_> = <Approvals<T>>::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;
<Proposals<T>>::remove(index);
// return their deposit.
let _ = <balances::Module<T>>::unreserve(&p.proposer, p.bond);
// provide the allocation.
<balances::Module<T>>::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();
<Approvals<T>>::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));
<Pot<T>>::put(budget_remaining);
}
}
impl<T: Trait> OnMinted<T::Balance> for Module<T> {
fn on_minted(b: T::Balance) {
<Pot<T>>::put(Self::pot() + b);
}
}
impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
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<T: Trait> {
pub proposal_bond: Permill,
pub proposal_bond_minimum: T::Balance,
pub spend_period: T::BlockNumber,
pub burn: Permill,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
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<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
{
fn build_storage(self) -> ::std::result::Result<runtime_primitives::StorageMap, String> {
use codec::Encode;
Ok(map![
Self::hash(<ProposalBond<T>>::key()).to_vec() => self.proposal_bond.encode(),
Self::hash(<ProposalBondMinimum<T>>::key()).to_vec() => self.proposal_bond_minimum.encode(),
Self::hash(<SpendPeriod<T>>::key()).to_vec() => self.spend_period.encode(),
Self::hash(<Burn<T>>::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<Test>;
type Treasury = Module<Test>;
fn new_test_ext() -> runtime_io::TestExternalities<KeccakHasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap();
t.extend(balances::GenesisConfig::<Test>{
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::<Test>{
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));
<Treasury as OnFinalise<u64>>::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);
<Treasury as OnFinalise<u64>>::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));
<Treasury as OnFinalise<u64>>::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));
<Treasury as OnFinalise<u64>>::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));
<Treasury as OnFinalise<u64>>::on_finalise(2);
assert_eq!(Treasury::pot(), 100);
Treasury::on_minted(100);
<Treasury as OnFinalise<u64>>::on_finalise(4);
assert_eq!(Balances::free_balance(&3), 150);
assert_eq!(Treasury::pot(), 25);
});
}
}