Traitify Runtime (#104)

* Factor out safe-mix and dispatch

* Refactor dispatch into something more modular.

* Fix wasm build.

* Fix up timestamp

* fix warnings.

* Borked timestamp example

* Fix build

* Timestamp as skeleton for traity runtime.

* New storage macro.

* Dispatch module has traity API.

* Move consensus module to new API

* Refactoring and outer dispatch

* Avoid unnecessary derives.

* Abstract the low-level half of system.

* nicer outer dispatch syntax.

* Make runtime compile again (albeit in a heavily simplified state)

* Reworking runtime and the upper levels of system.

* Initial reworking of runtime:

- Introduced executive module;
- Introduced trait primitives module;
- Provided an API endpoint.

* Expose an additional function in system

* Another couple of functions traitified in executive.

* another function in executive traitified.

* One more function traitified.

* Finish traitifying executive!

* Traitify session module.

* Cleanups and ensure session gets run.

* First part of traitification of staking module.

* Bit more of staking traitified.

* Additional stuff in staking. Fix up session.

* Penultimate part of staking module.

* Final part of staking (code)

* Update demo runtime to include staking.

* Final tweaks for staking integration.

* Remove old runtime files.

* Schedule staking.

* Minor fixes

* First bits of democracy.

* Democracy module integrated.

* Fix warning.

* Traitify and integrate council module

* Council voting.

* Runtime binary and tweaks.

* Binary update.

* Fix `*Type` grumble.

* Fix up genesis_map

* Remove NonTrivialSlicable

* Staking "test externalities" stuff along with refactor.

* Add session test externalities constructor

* Fixed executor tests.

* Make one test in executive module work.

* Remove test framework stuff into common module.

* Enable other tests in executive

* Session tests reinstated, minor refactoring of keyring.

* Fix staking tests.

* Fix up democracy tests.

* First few tests in council.

* Council tests reinstated :)

* Avoid hardcoding blake2 into Header.

* Fix last few tests.

* Make all primitives generic.

* Fix tests.

* Refactor runtime to remove genesismap.

* Streamline runtime more with macrofied config.

* Clean paths

* Fix warning.

* Consolidate demo runtime crate.

* Remove stale code.

* Refactor away dodgy trait.

* Add corresponding Aux type.

* Fixes

* Rename Digesty -> Digest

* Rename Headery -> Header

* Blocky -> Block

* Fix wasm build.

* kill warnings

* more docs

* minor cleanups
This commit is contained in:
Gav Wood
2018-04-04 12:06:39 +02:00
committed by GitHub
parent 3ec6d2dde6
commit bd066e27a6
92 changed files with 7890 additions and 5243 deletions
@@ -0,0 +1,24 @@
[package]
name = "substrate-runtime-consensus"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
substrate-codec = { path = "../../codec", default_features = false }
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 }
[features]
default = ["std"]
std = [
"serde/std",
"substrate-codec/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
]
@@ -0,0 +1,111 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Conensus module for runtime; manages the authority set ready for the native code.
#![cfg_attr(not(feature = "std"), no_std)]
#[allow(unused_imports)]
#[macro_use]
extern crate substrate_runtime_std as rstd;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_codec as codec;
use rstd::prelude::*;
use runtime_support::{storage, Parameter};
use runtime_support::storage::unhashed::StorageVec;
pub const AUTHORITY_AT: &'static[u8] = b":auth:";
pub const AUTHORITY_COUNT: &'static[u8] = b":auth:len";
struct AuthorityStorageVec<S: codec::Slicable + Default>(rstd::marker::PhantomData<S>);
impl<S: codec::Slicable + Default> StorageVec for AuthorityStorageVec<S> {
type Item = S;
const PREFIX: &'static [u8] = AUTHORITY_AT;
}
pub const CODE: &'static [u8] = b":code";
pub trait Trait {
type SessionKey: Parameter + Default;
}
decl_module! {
pub struct Module<T: Trait>;
pub enum PrivCall {
fn set_code(new: Vec<u8>) = 0;
fn dummy() = 1;
}
}
impl<T: Trait> Module<T> {
/// Get the current set of authorities. These are the session keys.
pub fn authorities() -> Vec<T::SessionKey> {
AuthorityStorageVec::<T::SessionKey>::items()
}
/// Set the new code.
fn set_code(new: Vec<u8>) {
storage::unhashed::put_raw(CODE, &new);
}
fn dummy() {}
/// Set the current set of authorities' session keys.
///
/// Called by `next_session` only.
pub fn set_authorities(authorities: &[T::SessionKey]) {
AuthorityStorageVec::<T::SessionKey>::set_items(authorities);
}
/// Set a single authority by index.
pub fn set_authority(index: u32, key: &T::SessionKey) {
AuthorityStorageVec::<T::SessionKey>::set_item(index, key);
}
}
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait> {
pub authorities: Vec<T::SessionKey>,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
authorities: vec![],
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_io::TestExternalities {
use codec::{Slicable, KeyedVec};
let auth_count = self.authorities.len() as u32;
let mut r: runtime_io::TestExternalities = self.authorities.into_iter().enumerate().map(|(i, v)|
((i as u32).to_keyed_vec(b":auth:"), v.encode())
).collect();
r.insert(b":auth:len".to_vec(), auth_count.encode());
r
}
}
@@ -0,0 +1,41 @@
[package]
name = "substrate-runtime-council"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
integer-sqrt = "0.1.0"
serde = { version = "1.0", default_features = false }
safe-mix = { path = "../../../safe-mix", default_features = false}
substrate-keyring = { path = "../../keyring", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-runtime-consensus = { path = "../consensus", default_features = false }
substrate-runtime-democracy = { path = "../democracy", default_features = false }
substrate-runtime-session = { path = "../session", default_features = false }
substrate-runtime-staking = { path = "../staking", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"safe-mix/std",
"substrate-keyring",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-consensus/std",
"substrate-runtime-democracy/std",
"substrate-runtime-session/std",
"substrate-runtime-staking/std",
"substrate-runtime-system/std",
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,457 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Council voting system.
use rstd::prelude::*;
use rstd::borrow::Borrow;
use primitives::traits::{Executable, RefInto};
use runtime_io::Hashing;
use runtime_support::{StorageValue, StorageMap, IsSubType};
use {system, democracy};
use super::{Trait, Module as Council};
decl_module! {
pub struct Module<T: Trait>;
pub enum Call where aux: T::PublicAux {
fn propose(aux, proposal: Box<T::Proposal>) = 0;
fn vote(aux, proposal: T::Hash, approve: bool) = 1;
fn veto(aux, proposal_hash: T::Hash) = 2;
}
pub enum PrivCall {
fn set_cooloff_period(blocks: T::BlockNumber) = 0;
fn set_voting_period(blocks: T::BlockNumber) = 1;
}
}
decl_storage! {
trait Store for Module<T: Trait>;
pub CooloffPeriod get(cooloff_period): b"cov:cooloff" => required T::BlockNumber;
pub VotingPeriod get(voting_period): b"cov:period" => required T::BlockNumber;
pub Proposals get(proposals): b"cov:prs" => default Vec<(T::BlockNumber, T::Hash)>; // ordered by expiry.
pub ProposalOf get(proposal_of): b"cov:pro" => map [ T::Hash => T::Proposal ];
pub ProposalVoters get(proposal_voters): b"cov:voters:" => default map [ T::Hash => Vec<T::AccountId> ];
pub CouncilVoteOf get(vote_of): b"cov:vote:" => map [ (T::Hash, T::AccountId) => bool ];
pub VetoedProposal get(veto_of): b"cov:veto:" => map [ T::Hash => (T::BlockNumber, Vec<T::AccountId>) ];
}
impl<T: Trait> Module<T> {
pub fn is_vetoed<B: Borrow<T::Hash>>(proposal: B) -> bool {
Self::veto_of(proposal.borrow())
.map(|(expiry, _): (T::BlockNumber, Vec<T::AccountId>)| <system::Module<T>>::block_number() < expiry)
.unwrap_or(false)
}
pub fn will_still_be_councillor_at(who: &T::AccountId, n: T::BlockNumber) -> bool {
<Council<T>>::active_council().iter()
.find(|&&(ref a, _)| a == who)
.map(|&(_, expires)| expires > n)
.unwrap_or(false)
}
pub fn is_councillor(who: &T::AccountId) -> bool {
<Council<T>>::active_council().iter()
.any(|&(ref a, _)| a == who)
}
pub fn tally(proposal_hash: &T::Hash) -> (u32, u32, u32) {
Self::generic_tally(proposal_hash, |w: &T::AccountId, p: &T::Hash| Self::vote_of((*p, w.clone())))
}
// Dispatch
fn propose(aux: &T::PublicAux, proposal: Box<T::Proposal>) {
let expiry = <system::Module<T>>::block_number() + Self::voting_period();
assert!(Self::will_still_be_councillor_at(aux.ref_into(), expiry));
let proposal_hash = T::Hashing::hash_of(&proposal);
assert!(!Self::is_vetoed(&proposal_hash));
let mut proposals = Self::proposals();
proposals.push((expiry, proposal_hash));
proposals.sort_by_key(|&(expiry, _)| expiry);
Self::set_proposals(&proposals);
<ProposalOf<T>>::insert(proposal_hash, *proposal);
<ProposalVoters<T>>::insert(proposal_hash, vec![aux.ref_into().clone()]);
<CouncilVoteOf<T>>::insert((proposal_hash, aux.ref_into().clone()), true);
}
fn vote(aux: &T::PublicAux, proposal: T::Hash, approve: bool) {
if Self::vote_of((proposal, aux.ref_into().clone())).is_none() {
let mut voters = Self::proposal_voters(&proposal);
voters.push(aux.ref_into().clone());
<ProposalVoters<T>>::insert(proposal, voters);
}
<CouncilVoteOf<T>>::insert((proposal, aux.ref_into().clone()), approve);
}
fn veto(aux: &T::PublicAux, proposal_hash: T::Hash) {
assert!(Self::is_councillor(aux.ref_into()), "only councillors may veto council proposals");
assert!(<ProposalVoters<T>>::exists(&proposal_hash), "proposal must exist to be vetoed");
let mut existing_vetoers = Self::veto_of(&proposal_hash)
.map(|pair| pair.1)
.unwrap_or_else(Vec::new);
let insert_position = existing_vetoers.binary_search(aux.ref_into())
.expect_err("a councillor may not veto a proposal twice");
existing_vetoers.insert(insert_position, aux.ref_into().clone());
Self::set_veto_of(&proposal_hash, <system::Module<T>>::block_number() + Self::cooloff_period(), existing_vetoers);
Self::set_proposals(&Self::proposals().into_iter().filter(|&(_, h)| h != proposal_hash).collect::<Vec<_>>());
<ProposalVoters<T>>::remove(proposal_hash);
<ProposalOf<T>>::remove(proposal_hash);
for (c, _) in <Council<T>>::active_council() {
<CouncilVoteOf<T>>::remove((proposal_hash, c));
}
}
fn set_cooloff_period(blocks: T::BlockNumber) {
<CooloffPeriod<T>>::put(blocks);
}
fn set_voting_period(blocks: T::BlockNumber) {
<VotingPeriod<T>>::put(blocks);
}
// private
fn set_veto_of(proposal: &T::Hash, expiry: T::BlockNumber, vetoers: Vec<T::AccountId>) {
<VetoedProposal<T>>::insert(proposal, (expiry, vetoers));
}
fn kill_veto_of(proposal: &T::Hash) {
<VetoedProposal<T>>::remove(proposal);
}
fn take_tally(proposal_hash: &T::Hash) -> (u32, u32, u32) {
Self::generic_tally(proposal_hash, |w: &T::AccountId, p: &T::Hash| <CouncilVoteOf<T>>::take((*p, w.clone())))
}
fn generic_tally<F: Fn(&T::AccountId, &T::Hash) -> Option<bool>>(proposal_hash: &T::Hash, vote_of: F) -> (u32, u32, u32) {
let c = <Council<T>>::active_council();
let (approve, reject) = c.iter()
.filter_map(|&(ref a, _)| vote_of(a, proposal_hash))
.map(|approve| if approve { (1, 0) } else { (0, 1) })
.fold((0, 0), |(a, b), (c, d)| (a + c, b + d));
(approve, reject, c.len() as u32 - approve - reject)
}
fn set_proposals(p: &Vec<(T::BlockNumber, T::Hash)>) {
<Proposals<T>>::put(p);
}
fn take_proposal_if_expiring_at(n: T::BlockNumber) -> Option<(T::Proposal, T::Hash)> {
let proposals = Self::proposals();
match proposals.first() {
Some(&(expiry, hash)) if expiry == n => {
// yes this is horrible, but fixing it will need substantial work in storage.
Self::set_proposals(&proposals[1..].to_vec());
let proposal = <ProposalOf<T>>::take(hash).expect("all queued proposal hashes must have associated proposals");
Some((proposal, hash))
}
_ => None,
}
}
fn end_block(now: T::BlockNumber) {
while let Some((proposal, proposal_hash)) = Self::take_proposal_if_expiring_at(now) {
let tally = Self::take_tally(&proposal_hash);
if let Some(&democracy::PrivCall::cancel_referendum(ref_index)) = IsSubType::<democracy::Module<T>>::is_sub_type(&proposal) {
if let (_, 0, 0) = tally {
<democracy::Module<T>>::internal_cancel_referendum(ref_index);
}
} else {
if tally.0 > tally.1 + tally.2 {
Self::kill_veto_of(&proposal_hash);
match tally {
(_, 0, 0) => <democracy::Module<T>>::internal_start_referendum(proposal, democracy::VoteThreshold::SuperMajorityAgainst),
_ => <democracy::Module<T>>::internal_start_referendum(proposal, democracy::VoteThreshold::SimpleMajority),
};
}
}
}
}
}
impl<T: Trait> Executable for Council<T> {
fn execute() {
let n = <system::Module<T>>::block_number();
Self::end_block(n);
<Module<T>>::end_block(n);
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::tests::*;
use runtime_support::Hashable;
use democracy::VoteThreshold;
type CouncilVoting = super::Module<Test>;
#[test]
fn basic_environment_works() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
assert_eq!(Staking::bonding_duration(), 0);
assert_eq!(CouncilVoting::cooloff_period(), 2);
assert_eq!(CouncilVoting::voting_period(), 1);
assert_eq!(CouncilVoting::will_still_be_councillor_at(&1, 1), true);
assert_eq!(CouncilVoting::will_still_be_councillor_at(&1, 10), false);
assert_eq!(CouncilVoting::will_still_be_councillor_at(&4, 10), false);
assert_eq!(CouncilVoting::is_councillor(&1), true);
assert_eq!(CouncilVoting::is_councillor(&4), false);
assert_eq!(CouncilVoting::proposals(), Vec::<(u64, H256)>::new());
assert_eq!(CouncilVoting::proposal_voters(H256::default()), Vec::<u64>::new());
assert_eq!(CouncilVoting::is_vetoed(&H256::default()), false);
assert_eq!(CouncilVoting::vote_of((H256::default(), 1)), None);
assert_eq!(CouncilVoting::tally(&H256::default()), (0, 0, 3));
});
}
fn bonding_duration_proposal(value: u64) -> Proposal {
Proposal::Staking(staking::PrivCall::set_bonding_duration(value))
}
fn cancel_referendum_proposal(id: u32) -> Proposal {
Proposal::Democracy(democracy::PrivCall::cancel_referendum(id))
}
#[test]
fn referendum_cancellation_should_work_when_unanimous() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
CouncilVoting::propose(&1, Box::new(cancellation));
CouncilVoting::vote(&2, hash, true);
CouncilVoting::vote(&3, hash, true);
assert_eq!(CouncilVoting::proposals(), vec![(2, hash)]);
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(Democracy::active_referendums(), vec![]);
assert_eq!(Staking::bonding_duration(), 0);
});
}
#[test]
fn referendum_cancellation_should_fail_when_not_unanimous() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
CouncilVoting::propose(&1, Box::new(cancellation));
CouncilVoting::vote(&2, hash, true);
CouncilVoting::vote(&3, hash, false);
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
});
}
#[test]
fn referendum_cancellation_should_fail_when_abstentions() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
Democracy::internal_start_referendum(proposal.clone(), VoteThreshold::SuperMajorityApprove);
let cancellation = cancel_referendum_proposal(0);
let hash = cancellation.blake2_256().into();
CouncilVoting::propose(&1, Box::new(cancellation));
CouncilVoting::vote(&2, hash, true);
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(Democracy::active_referendums(), vec![(0, 4, proposal, VoteThreshold::SuperMajorityApprove)]);
});
}
#[test]
fn veto_should_work() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums().len(), 0);
});
}
#[test]
#[should_panic]
fn double_veto_should_panic() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
System::set_block_number(3);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
});
}
#[test]
#[should_panic]
fn retry_in_cooloff_should_panic() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
System::set_block_number(2);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
});
}
#[test]
fn retry_after_cooloff_should_work() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
System::set_block_number(3);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::vote(&2, hash, false);
CouncilVoting::vote(&3, hash, true);
CouncilVoting::end_block(System::block_number());
System::set_block_number(4);
CouncilVoting::end_block(System::block_number());
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums(), vec![(0, 7, bonding_duration_proposal(42), VoteThreshold::SimpleMajority)]);
});
}
#[test]
fn alternative_double_veto_should_work() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&2, hash);
System::set_block_number(3);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::veto(&3, hash);
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums().len(), 0);
});
}
#[test]
fn simple_propose_should_work() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
let hash = proposal.blake2_256().into();
CouncilVoting::propose(&1, Box::new(proposal.clone()));
assert_eq!(CouncilVoting::proposals().len(), 1);
assert_eq!(CouncilVoting::proposal_voters(&hash), vec![1]);
assert_eq!(CouncilVoting::vote_of((hash, 1)), Some(true));
assert_eq!(CouncilVoting::tally(&hash), (1, 0, 2));
});
}
#[test]
fn unvoted_proposal_should_expire_without_action() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (1, 0, 2));
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums().len(), 0);
});
}
#[test]
fn unanimous_proposal_should_expire_with_biased_referendum() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::vote(&2, proposal.blake2_256().into(), true);
CouncilVoting::vote(&3, proposal.blake2_256().into(), true);
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (3, 0, 0));
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SuperMajorityAgainst)]);
});
}
#[test]
fn majority_proposal_should_expire_with_unbiased_referendum() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
CouncilVoting::propose(&1, Box::new(proposal.clone()));
CouncilVoting::vote(&2, proposal.blake2_256().into(), true);
CouncilVoting::vote(&3, proposal.blake2_256().into(), false);
assert_eq!(CouncilVoting::tally(&proposal.blake2_256().into()), (2, 1, 0));
CouncilVoting::end_block(System::block_number());
System::set_block_number(2);
CouncilVoting::end_block(System::block_number());
assert_eq!(CouncilVoting::proposals().len(), 0);
assert_eq!(Democracy::active_referendums(), vec![(0, 5, proposal, VoteThreshold::SimpleMajority)]);
});
}
#[test]
#[should_panic]
fn propose_by_public_should_panic() {
with_externalities(&mut new_test_ext(true), || {
System::set_block_number(1);
let proposal = bonding_duration_proposal(42);
CouncilVoting::propose(&4, Box::new(proposal));
});
}
}
@@ -0,0 +1,36 @@
[package]
name = "substrate-runtime-democracy"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
safe-mix = { path = "../../../safe-mix", default_features = false}
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-runtime-consensus = { path = "../consensus", default_features = false }
substrate-runtime-session = { path = "../session", default_features = false }
substrate-runtime-staking = { path = "../staking", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"safe-mix/std",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-consensus/std",
"substrate-runtime-session/std",
"substrate-runtime-staking/std",
"substrate-runtime-system/std",
]
@@ -0,0 +1,659 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Democratic system: Handles administration of general stakeholder voting.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate serde;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
#[cfg(feature = "std")]
extern crate substrate_primitives;
#[macro_use]
extern crate substrate_runtime_std as rstd;
extern crate substrate_codec as codec;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_runtime_consensus as consensus;
extern crate substrate_runtime_session as session;
extern crate substrate_runtime_staking as staking;
extern crate substrate_runtime_system as system;
use rstd::prelude::*;
use primitives::traits::{Zero, Executable, RefInto, As};
use runtime_support::{StorageValue, StorageMap, Parameter, Dispatchable, IsSubType};
mod vote_threshold;
pub use vote_threshold::{Approved, VoteThreshold};
/// A proposal index.
pub type PropIndex = u32;
/// A referendum index.
pub type ReferendumIndex = u32;
pub trait Trait: staking::Trait + Sized {
type Proposal: Parameter + Dispatchable + IsSubType<Module<Self>>;
}
decl_module! {
pub struct Module<T: Trait>;
pub enum Call where aux: T::PublicAux {
fn propose(aux, proposal: Box<T::Proposal>, value: T::Balance) = 0;
fn second(aux, proposal: PropIndex) = 1;
fn vote(aux, ref_index: ReferendumIndex, approve_proposal: bool) = 2;
}
pub enum PrivCall {
fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) = 0;
fn cancel_referendum(ref_index: ReferendumIndex) = 1;
}
}
decl_storage! {
trait Store for Module<T: Trait>;
// The number of (public) proposals that have been made so far.
pub PublicPropCount get(public_prop_count): b"dem:ppc" => default PropIndex;
// The public proposals. Unsorted.
pub PublicProps get(public_props): b"dem:pub" => default Vec<(PropIndex, T::Proposal, T::AccountId)>;
// Those who have locked a deposit.
pub DepositOf get(deposit_of): b"dem:dep:" => map [ PropIndex => (T::Balance, Vec<T::AccountId>) ];
// How often (in blocks) new public referenda are launched.
pub LaunchPeriod get(launch_period): b"dem:lau" => required T::BlockNumber;
// The minimum amount to be used as a deposit for a public referendum proposal.
pub MinimumDeposit get(minimum_deposit): b"dem:min" => required T::Balance;
// How often (in blocks) to check for new votes.
pub VotingPeriod get(voting_period): b"dem:per" => required T::BlockNumber;
// The next free referendum index, aka the number of referendums started so far.
pub ReferendumCount get(referendum_count): b"dem:rco" => default ReferendumIndex;
// The next referendum index that should be tallied.
pub NextTally get(next_tally): b"dem:nxt" => default ReferendumIndex;
// Information concerning any given referendum.
pub ReferendumInfoOf get(referendum_info): b"dem:pro:" => map [ ReferendumIndex => (T::BlockNumber, T::Proposal, VoteThreshold) ];
// Get the voters for the current proposal.
pub VotersFor get(voters_for): b"dem:vtr:" => default map [ ReferendumIndex => Vec<T::AccountId> ];
// Get the vote, if Some, of `who`.
pub VoteOf get(vote_of): b"dem:vot:" => map [ (ReferendumIndex, T::AccountId) => bool ];
}
impl<T: Trait> Module<T> {
// exposed immutables.
/// Get the amount locked in support of `proposal`; false if proposal isn't a valid proposal
/// index.
pub fn locked_for(proposal: PropIndex) -> Option<T::Balance> {
Self::deposit_of(proposal).map(|(d, l)| d * T::Balance::sa(l.len()))
}
/// Return true if `ref_index` is an on-going referendum.
pub fn is_active_referendum(ref_index: ReferendumIndex) -> bool {
<ReferendumInfoOf<T>>::exists(ref_index)
}
/// Get all referendums currently active.
pub fn active_referendums() -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold)> {
let next = Self::next_tally();
let last = Self::referendum_count();
(next..last).into_iter()
.filter_map(|i| Self::referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
.collect()
}
/// Get all referendums ready for tally at block `n`.
pub fn maturing_referendums_at(n: T::BlockNumber) -> Vec<(ReferendumIndex, T::BlockNumber, T::Proposal, VoteThreshold)> {
let next = Self::next_tally();
let last = Self::referendum_count();
(next..last).into_iter()
.filter_map(|i| Self::referendum_info(i).map(|(n, p, t)| (i, n, p, t)))
.take_while(|&(_, block_number, _, _)| block_number == n)
.collect()
}
/// Get the voters for the current proposal.
pub fn tally(ref_index: ReferendumIndex) -> (T::Balance, T::Balance) {
Self::voters_for(ref_index).iter()
.map(|a| (<staking::Module<T>>::balance(a), Self::vote_of((ref_index, a.clone())).expect("all items come from `voters`; for an item to be in `voters` there must be a vote registered; qed")))
.map(|(bal, vote)| if vote { (bal, Zero::zero()) } else { (Zero::zero(), bal) })
.fold((Zero::zero(), Zero::zero()), |(a, b), (c, d)| (a + c, b + d))
}
// dispatching.
/// Propose a sensitive action to be taken.
fn propose(aux: &T::PublicAux, proposal: Box<T::Proposal>, value: T::Balance) {
assert!(value >= Self::minimum_deposit());
assert!(<staking::Module<T>>::deduct_unbonded(aux.ref_into(), value));
let index = Self::public_prop_count();
<PublicPropCount<T>>::put(index + 1);
<DepositOf<T>>::insert(index, (value, vec![aux.ref_into().clone()]));
let mut props = Self::public_props();
props.push((index, (*proposal).clone(), aux.ref_into().clone()));
<PublicProps<T>>::put(props);
}
/// Propose a sensitive action to be taken.
fn second(aux: &T::PublicAux, proposal: PropIndex) {
let mut deposit = Self::deposit_of(proposal).expect("can only second an existing proposal");
assert!(<staking::Module<T>>::deduct_unbonded(aux.ref_into(), deposit.0));
deposit.1.push(aux.ref_into().clone());
<DepositOf<T>>::insert(proposal, deposit);
}
/// Vote in a referendum. If `approve_proposal` is true, the vote is to enact the proposal;
/// false would be a vote to keep the status quo..
fn vote(aux: &T::PublicAux, ref_index: ReferendumIndex, approve_proposal: bool) {
if !Self::is_active_referendum(ref_index) {
panic!("vote given for invalid referendum.")
}
if <staking::Module<T>>::balance(aux.ref_into()).is_zero() {
panic!("transactor must have balance to signal approval.");
}
if !<VoteOf<T>>::exists(&(ref_index, aux.ref_into().clone())) {
let mut voters = Self::voters_for(ref_index);
voters.push(aux.ref_into().clone());
<VotersFor<T>>::insert(ref_index, voters);
}
<VoteOf<T>>::insert(&(ref_index, aux.ref_into().clone()), approve_proposal);
}
/// Start a referendum.
fn start_referendum(proposal: Box<T::Proposal>, vote_threshold: VoteThreshold) {
Self::inject_referendum(<system::Module<T>>::block_number() + Self::voting_period(), *proposal, vote_threshold);
}
/// Remove a referendum.
fn cancel_referendum(ref_index: ReferendumIndex) {
Self::clear_referendum(ref_index);
}
// exposed mutables.
/// Start a referendum. Can be called directly by the council.
pub fn internal_start_referendum(proposal: T::Proposal, vote_threshold: VoteThreshold) {
<Module<T>>::inject_referendum(<system::Module<T>>::block_number() + <Module<T>>::voting_period(), proposal, vote_threshold);
}
/// Remove a referendum. Can be called directly by the council.
pub fn internal_cancel_referendum(ref_index: ReferendumIndex) {
<Module<T>>::clear_referendum(ref_index);
}
// private.
/// Start a referendum
fn inject_referendum(
end: T::BlockNumber,
proposal: T::Proposal,
vote_threshold: VoteThreshold
) -> ReferendumIndex {
let ref_index = Self::referendum_count();
if ref_index > 0 && Self::referendum_info(ref_index - 1).map(|i| i.0 > end).unwrap_or(false) {
panic!("Cannot inject a referendum that ends earlier than preceeding referendum");
}
<ReferendumCount<T>>::put(ref_index + 1);
<ReferendumInfoOf<T>>::insert(ref_index, (end, proposal, vote_threshold));
ref_index
}
/// Remove all info on a referendum.
fn clear_referendum(ref_index: ReferendumIndex) {
<ReferendumInfoOf<T>>::remove(ref_index);
<VotersFor<T>>::remove(ref_index);
for v in Self::voters_for(ref_index) {
<VoteOf<T>>::remove((ref_index, v));
}
}
/// Current era is ending; we should finish up any proposals.
fn end_block(now: T::BlockNumber) {
// pick out another public referendum if it's time.
if (now % Self::launch_period()).is_zero() {
let mut public_props = Self::public_props();
if let Some((winner_index, _)) = public_props.iter()
.enumerate()
.max_by_key(|x| Self::locked_for((x.1).0).expect("All current public proposals have an amount locked"))
{
let (prop_index, proposal, _) = public_props.swap_remove(winner_index);
let (deposit, depositors): (T::Balance, Vec<T::AccountId>) =
<DepositOf<T>>::take(prop_index).expect("depositors always exist for current proposals");
// refund depositors
for d in &depositors {
<staking::Module<T>>::refund(d, deposit);
}
<PublicProps<T>>::put(public_props);
Self::inject_referendum(now + Self::voting_period(), proposal, VoteThreshold::SuperMajorityApprove);
}
}
// tally up votes for any expiring referenda.
for (index, _, proposal, vote_threshold) in Self::maturing_referendums_at(now) {
let (approve, against) = Self::tally(index);
let total_stake = <staking::Module<T>>::total_stake();
Self::clear_referendum(index);
if vote_threshold.approved(approve, against, total_stake) {
proposal.dispatch();
}
<NextTally<T>>::put(index + 1);
}
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
Self::end_block(<system::Module<T>>::block_number());
}
}
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait> {
pub launch_period: T::BlockNumber,
pub voting_period: T::BlockNumber,
pub minimum_deposit: T::Balance,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> GenesisConfig<T> {
pub fn new() -> Self {
GenesisConfig {
launch_period: T::BlockNumber::sa(1),
voting_period: T::BlockNumber::sa(1),
minimum_deposit: T::Balance::sa(1),
}
}
pub fn extended() -> Self {
GenesisConfig {
launch_period: T::BlockNumber::sa(1),
voting_period: T::BlockNumber::sa(3),
minimum_deposit: T::Balance::sa(1),
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig {
launch_period: T::BlockNumber::sa(1000),
voting_period: T::BlockNumber::sa(1000),
minimum_deposit: T::Balance::sa(0),
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_io::TestExternalities {
use codec::Slicable;
use runtime_io::twox_128;
map![
twox_128(<LaunchPeriod<T>>::key()).to_vec() => self.launch_period.encode(),
twox_128(<VotingPeriod<T>>::key()).to_vec() => self.voting_period.encode(),
twox_128(<MinimumDeposit<T>>::key()).to_vec() => self.minimum_deposit.encode()
]
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use primitives::BuildExternalities;
use primitives::traits::{HasPublicAux, Identity};
use primitives::testing::{Digest, Header};
impl_outer_dispatch! {
pub enum Proposal {
Session = 0,
Staking = 1,
Democracy = 2,
}
}
pub struct Test;
impl HasPublicAux for Test {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type SessionKey = u64;
}
impl system::Trait for Test {
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = runtime_io::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl staking::Trait for Test {
type Balance = u64;
type DetermineContractAddress = staking::DummyContractAddressFor;
}
impl Trait for Test {
type Proposal = Proposal;
}
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
authorities: vec![],
}.build_externalities());
t.extend(session::GenesisConfig::<Test>{
session_length: 1, //??? or 2?
validators: vec![10, 20],
}.build_externalities());
t.extend(staking::GenesisConfig::<Test>{
sessions_per_era: 1,
current_era: 0,
balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)],
intentions: vec![],
validator_count: 2,
bonding_duration: 3,
transaction_fee: 0,
}.build_externalities());
t.extend(GenesisConfig::<Test>{
launch_period: 1,
voting_period: 1,
minimum_deposit: 1,
}.build_externalities());
t
}
type System = system::Module<Test>;
type Session = session::Module<Test>;
type Staking = staking::Module<Test>;
type Democracy = Module<Test>;
#[test]
fn params_should_work() {
with_externalities(&mut new_test_ext(), || {
assert_eq!(Democracy::launch_period(), 1);
assert_eq!(Democracy::voting_period(), 1);
assert_eq!(Democracy::minimum_deposit(), 1);
assert_eq!(Democracy::referendum_count(), 0);
assert_eq!(Staking::sessions_per_era(), 1);
assert_eq!(Staking::total_stake(), 210);
});
}
fn propose_sessions_per_era(who: u64, value: u64, locked: u64) {
Democracy::propose(&who, Box::new(Proposal::Staking(staking::PrivCall::set_sessions_per_era(value))), locked);
}
#[test]
fn locked_for_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 2);
propose_sessions_per_era(1, 4, 4);
propose_sessions_per_era(1, 3, 3);
assert_eq!(Democracy::locked_for(0), Some(2));
assert_eq!(Democracy::locked_for(1), Some(4));
assert_eq!(Democracy::locked_for(2), Some(3));
});
}
#[test]
fn single_proposal_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 1);
Democracy::end_block(System::block_number());
System::set_block_number(2);
let r = 0;
Democracy::vote(&1, r, true);
assert_eq!(Democracy::referendum_count(), 1);
assert_eq!(Democracy::voters_for(r), vec![1]);
assert_eq!(Democracy::vote_of((r, 1)), Some(true));
assert_eq!(Democracy::tally(r), (10, 0));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 2);
});
}
#[test]
fn deposit_for_proposals_should_be_taken() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 5);
Democracy::second(&2, 0);
Democracy::second(&5, 0);
Democracy::second(&5, 0);
Democracy::second(&5, 0);
assert_eq!(Staking::balance(&1), 5);
assert_eq!(Staking::balance(&2), 15);
assert_eq!(Staking::balance(&5), 35);
});
}
#[test]
fn deposit_for_proposals_should_be_returned() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 5);
Democracy::second(&2, 0);
Democracy::second(&5, 0);
Democracy::second(&5, 0);
Democracy::second(&5, 0);
Democracy::end_block(System::block_number());
assert_eq!(Staking::balance(&1), 10);
assert_eq!(Staking::balance(&2), 20);
assert_eq!(Staking::balance(&5), 50);
});
}
#[test]
#[should_panic]
fn proposal_with_deposit_below_minimum_should_panic() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 0);
});
}
#[test]
#[should_panic]
fn poor_proposer_should_panic() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(1, 2, 11);
});
}
#[test]
#[should_panic]
fn poor_seconder_should_panic() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
propose_sessions_per_era(2, 2, 11);
Democracy::second(&1, 0);
});
}
fn propose_bonding_duration(who: u64, value: u64, locked: u64) {
Democracy::propose(&who, Box::new(Proposal::Staking(staking::PrivCall::set_bonding_duration(value))), locked);
}
#[test]
fn runners_up_should_come_after() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(0);
propose_bonding_duration(1, 2, 2);
propose_bonding_duration(1, 4, 4);
propose_bonding_duration(1, 3, 3);
Democracy::end_block(System::block_number());
System::set_block_number(1);
Democracy::vote(&1, 0, true);
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::bonding_duration(), 4);
System::set_block_number(2);
Democracy::vote(&1, 1, true);
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::bonding_duration(), 3);
System::set_block_number(3);
Democracy::vote(&1, 2, true);
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::bonding_duration(), 2);
});
}
fn sessions_per_era_proposal(value: u64) -> Proposal {
Proposal::Staking(staking::PrivCall::set_sessions_per_era(value))
}
#[test]
fn simple_passing_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&1, r, true);
assert_eq!(Democracy::voters_for(r), vec![1]);
assert_eq!(Democracy::vote_of((r, 1)), Some(true));
assert_eq!(Democracy::tally(r), (10, 0));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 2);
});
}
#[test]
fn cancel_referendum_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&1, r, true);
Democracy::cancel_referendum(r);
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 1);
});
}
#[test]
fn simple_failing_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&1, r, false);
assert_eq!(Democracy::voters_for(r), vec![1]);
assert_eq!(Democracy::vote_of((r, 1)), Some(false));
assert_eq!(Democracy::tally(r), (0, 10));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 1);
});
}
#[test]
fn controversial_voting_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&1, r, true);
Democracy::vote(&2, r, false);
Democracy::vote(&3, r, false);
Democracy::vote(&4, r, true);
Democracy::vote(&5, r, false);
Democracy::vote(&6, r, true);
assert_eq!(Democracy::tally(r), (110, 100));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 2);
});
}
#[test]
fn controversial_low_turnout_voting_should_work() {
with_externalities(&mut new_test_ext(), || {
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&5, r, false);
Democracy::vote(&6, r, true);
assert_eq!(Democracy::tally(r), (60, 50));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 1);
});
}
#[test]
fn passing_low_turnout_voting_should_work() {
with_externalities(&mut new_test_ext(), || {
assert_eq!(Staking::era_length(), 1);
assert_eq!(Staking::total_stake(), 210);
System::set_block_number(1);
let r = Democracy::inject_referendum(1, sessions_per_era_proposal(2), VoteThreshold::SuperMajorityApprove);
Democracy::vote(&4, r, true);
Democracy::vote(&5, r, false);
Democracy::vote(&6, r, true);
assert_eq!(Democracy::tally(r), (100, 50));
Democracy::end_block(System::block_number());
Staking::check_new_era();
assert_eq!(Staking::era_length(), 2);
});
}
}
@@ -0,0 +1,75 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Voting thresholds.
use primitives::traits::IntegerSquareRoot;
use codec::{Input, Slicable};
use rstd::ops::{Add, Mul, Div};
/// A means of determining if a vote is past pass threshold.
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub enum VoteThreshold {
/// A supermajority of approvals is needed to pass this vote.
SuperMajorityApprove,
/// A supermajority of rejects is needed to fail this vote.
SuperMajorityAgainst,
/// A simple majority of approvals is needed to pass this vote.
SimpleMajority,
}
impl Slicable for VoteThreshold {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
input.read_byte().and_then(|v| match v {
0 => Some(VoteThreshold::SuperMajorityApprove),
1 => Some(VoteThreshold::SuperMajorityAgainst),
2 => Some(VoteThreshold::SimpleMajority),
_ => None,
})
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&[match *self {
VoteThreshold::SuperMajorityApprove => 0u8,
VoteThreshold::SuperMajorityAgainst => 1u8,
VoteThreshold::SimpleMajority => 2u8,
}])
}
}
pub trait Approved<Balance> {
/// Given `approve` votes for and `against` votes against from a total electorate size of
/// `electorate` (`electorate - (approve + against)` are abstainers), then returns true if the
/// overall outcome is in favour of approval.
fn approved(&self, approve: Balance, against: Balance, electorate: Balance) -> bool;
}
impl<Balance: IntegerSquareRoot + Ord + Add<Balance, Output = Balance> + Mul<Balance, Output = Balance> + Div<Balance, Output = Balance> + Copy> Approved<Balance> for VoteThreshold {
/// Given `approve` votes for and `against` votes against from a total electorate size of
/// `electorate` (`electorate - (approve + against)` are abstainers), then returns true if the
/// overall outcome is in favour of approval.
fn approved(&self, approve: Balance, against: Balance, electorate: Balance) -> bool {
let voters = approve + against;
match *self {
VoteThreshold::SuperMajorityApprove =>
voters.integer_sqrt() * approve / electorate.integer_sqrt() > against,
VoteThreshold::SuperMajorityAgainst =>
approve > voters.integer_sqrt() * against / electorate.integer_sqrt(),
VoteThreshold::SimpleMajority => approve > against,
}
}
}
@@ -0,0 +1,32 @@
[package]
name = "substrate-runtime-executive"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
substrate-codec = { path = "../../codec", default_features = false }
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-runtime-system = { path = "../system", default_features = false }
[dev-dependencies]
substrate-primitives = { path = "../../primitives" }
substrate-runtime-session = { path = "../session" }
substrate-runtime-staking = { path = "../staking" }
substrate-runtime-consensus = { path = "../consensus" }
[features]
default = ["std"]
std = [
"substrate-runtime-std/std",
"substrate-runtime-support/std",
"serde/std",
"substrate-codec/std",
"substrate-runtime-primitives/std",
"substrate-runtime-io/std",
"substrate-runtime-system/std",
]
@@ -0,0 +1,284 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Executive: Handles all of the top-level stuff; essentially just executing blocks/extrinsics.
#![cfg_attr(not(feature = "std"), no_std)]
extern crate substrate_runtime_std as rstd;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_codec as codec;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_runtime_system as system;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
#[cfg(test)]
extern crate substrate_primitives;
#[cfg(test)]
extern crate substrate_runtime_consensus as consensus;
#[cfg(test)]
extern crate substrate_runtime_session as session;
#[cfg(test)]
extern crate substrate_runtime_staking as staking;
#[cfg(feature = "std")] extern crate serde;
use rstd::prelude::*;
use rstd::marker::PhantomData;
use runtime_io::Hashing;
use primitives::traits::{self, Header, Zero, One, Checkable, Applyable, CheckEqual, Executable, MakePayment};
use codec::Slicable;
pub struct Executive<
System,
Block,
Payment,
Finalisation,
>(PhantomData<(System, Block, Payment, Finalisation)>);
impl<
System: system::Trait,
Block: traits::Block<Header = System::Header>,
Payment: MakePayment<System::AccountId>,
Finalisation: Executable,
> Executive<System, Block, Payment, Finalisation> where
Block::Extrinsic: Checkable + Slicable,
<Block::Extrinsic as Checkable>::Checked: Applyable<Index = System::Index, AccountId = System::AccountId>
{
/// Start the execution of a particular block.
pub fn initialise_block(header: &System::Header) {
<system::Module<System>>::initialise(header.number(), header.parent_hash(), header.extrinsics_root());
}
fn initial_checks(block: &Block) {
let header = block.header();
// check parent_hash is correct.
let n = header.number().clone();
assert!(
n > System::BlockNumber::zero() && <system::Module<System>>::block_hash(n - System::BlockNumber::one()) == *header.parent_hash(),
"Parent hash should be valid."
);
// check transaction trie root represents the transactions.
let txs = block.extrinsics().iter().map(Slicable::encode).collect::<Vec<_>>();
let txs = txs.iter().map(Vec::as_slice).collect::<Vec<_>>();
let txs_root = System::Hashing::enumerated_trie_root(&txs);
header.extrinsics_root().check_equal(&txs_root);
assert!(header.extrinsics_root() == &txs_root, "Transaction trie root must be valid.");
}
/// Actually execute all transitioning for `block`.
pub fn execute_block(block: Block) {
Self::initialise_block(block.header());
// any initial checks
Self::initial_checks(&block);
// execute transactions
let (header, extrinsics) = block.deconstruct();
extrinsics.into_iter().for_each(Self::apply_extrinsic);
// post-transactional book-keeping.
Finalisation::execute();
// any final checks
Self::final_checks(&header);
// any stuff that we do after taking the storage root.
Self::post_finalise(&header);
}
/// Finalise the block - it is up the caller to ensure that all header fields are valid
/// except state-root.
pub fn finalise_block() -> System::Header {
Finalisation::execute();
let header = <system::Module<System>>::finalise();
Self::post_finalise(&header);
header
}
/// Apply outside of the block execution function.
/// This doesn't attempt to validate anything regarding the block.
pub fn apply_extrinsic(utx: Block::Extrinsic) {
// Verify the signature is good.
let tx = match utx.check() {
Ok(tx) => tx,
Err(_) => panic!("All transactions should be properly signed"),
};
{
// check index
let expected_index = <system::Module<System>>::account_index(tx.sender());
assert!(tx.index() == &expected_index, "All transactions should have the correct nonce");
// increment nonce in storage
<system::Module<System>>::inc_account_index(tx.sender());
}
// pay any fees.
Payment::make_payment(tx.sender());
// decode parameters and dispatch
tx.apply();
}
fn final_checks(header: &System::Header) {
// check digest
assert!(header.digest() == &<system::Module<System>>::digest());
// remove temporaries.
<system::Module<System>>::finalise();
// check storage root.
let storage_root = System::Hashing::storage_root();
header.state_root().check_equal(&storage_root);
assert!(header.state_root() == &storage_root, "Storage root must match that calculated.");
}
fn post_finalise(header: &System::Header) {
// store the header hash in storage; we can't do it before otherwise there would be a
// cyclic dependency.
<system::Module<System>>::record_block_hash(header)
}
}
#[cfg(test)]
mod tests {
use super::*;
use staking::Call;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use primitives::BuildExternalities;
use primitives::traits::{HasPublicAux, Identity, Header as HeaderT};
use primitives::testing::{Digest, Header, Block};
pub struct Test;
impl HasPublicAux for Test {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type SessionKey = u64;
}
impl system::Trait for Test {
type Index = u64;
type BlockNumber = u64;
type Hash = substrate_primitives::H256;
type Hashing = runtime_io::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
}
impl session::Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
impl staking::Trait for Test {
type Balance = u64;
type DetermineContractAddress = staking::DummyContractAddressFor;
}
type TestXt = primitives::testing::TestXt<Call<Test>>;
type Executive = super::Executive<Test, Block<TestXt>, staking::Module<Test>, (session::Module<Test>, staking::Module<Test>)>;
#[test]
fn staking_balance_transfer_dispatch_works() {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(staking::GenesisConfig::<Test> {
sessions_per_era: 0,
current_era: 0,
balances: vec![(1, 111)],
intentions: vec![],
validator_count: 0,
bonding_duration: 0,
transaction_fee: 10,
}.build_externalities());
let xt = primitives::testing::TestXt((1, 0, Call::transfer(2, 69)));
with_externalities(&mut t, || {
Executive::initialise_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default()));
Executive::apply_extrinsic(xt);
assert_eq!(<staking::Module<Test>>::balance(&1), 32);
assert_eq!(<staking::Module<Test>>::balance(&2), 69);
});
}
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>::default().build_externalities());
t.extend(session::GenesisConfig::<Test>::default().build_externalities());
t.extend(staking::GenesisConfig::<Test>::default().build_externalities());
t
}
#[test]
fn block_import_works() {
with_externalities(&mut new_test_ext(), || {
Executive::execute_block(Block {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("9228e363883f4f5a01981985b5598d1a767e987eb3ccea017a0e14cac7acc79d").into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
},
extrinsics: vec![],
});
});
}
#[test]
#[should_panic]
fn block_import_of_bad_state_root_fails() {
with_externalities(&mut new_test_ext(), || {
Executive::execute_block(Block {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: [0u8; 32].into(),
extrinsics_root: hex!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").into(),
digest: Digest { logs: vec![], },
},
extrinsics: vec![],
});
});
}
#[test]
#[should_panic]
fn block_import_of_bad_extrinsic_root_fails() {
with_externalities(&mut new_test_ext(), || {
Executive::execute_block(Block {
header: Header {
parent_hash: [69u8; 32].into(),
number: 1,
state_root: hex!("93dde1251278e65430baf291337ba219bacfa9ad583c52513b12cf1974109a97").into(),
extrinsics_root: [0u8; 32].into(),
digest: Digest { logs: vec![], },
},
extrinsics: vec![],
});
});
}
}
@@ -0,0 +1,28 @@
[package]
name = "substrate-runtime-primitives"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
num-traits = { version = "0.2", default_features = false }
integer-sqrt = "0.1.0"
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
[features]
default = ["std"]
std = [
"num-traits/std",
"serde",
"serde_derive",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-codec/std",
"substrate-primitives/std",
]
@@ -0,0 +1,398 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Generic implementations of Extrinsic/Header/Block.
#[cfg(feature = "std")] use serde::Serialize;
use rstd::prelude::*;
use codec::{Slicable, Input};
use runtime_support::AuxDispatchable;
use traits;
use rstd::ops;
#[cfg(feature = "std")]
use std::fmt::{self, Debug};
#[cfg(feature = "std")]
pub trait MaybeSerializeDebug: Serialize + Debug {}
#[cfg(feature = "std")]
impl<T: Serialize + Debug> MaybeSerializeDebug for T {}
#[cfg(not(feature = "std"))]
pub trait MaybeSerializeDebug {}
#[cfg(not(feature = "std"))]
impl<T> MaybeSerializeDebug for T {}
pub trait Member: MaybeSerializeDebug + Eq + PartialEq + Clone {}
impl<T: MaybeSerializeDebug + Eq + PartialEq + Clone> Member for T {}
/// A vetted and verified extrinsic from the external world.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
pub struct Extrinsic<AccountId, Index, Call> where
AccountId: Member,
Index: Member,
Call: Member,
{
/// Who signed it (note this is not a signature).
pub signed: AccountId,
/// The number of extrinsics have come before from the same signer.
pub index: Index,
/// The function that should be called.
pub function: Call,
}
impl<AccountId, Index, Call> Slicable for Extrinsic<AccountId, Index, Call> where
AccountId: Member + Slicable,
Index: Member + Slicable,
Call: Member + Slicable
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Extrinsic {
signed: Slicable::decode(input)?,
index: Slicable::decode(input)?,
function: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.signed.using_encoded(|s| v.extend(s));
self.index.using_encoded(|s| v.extend(s));
self.function.using_encoded(|s| v.extend(s));
v
}
}
/// A extrinsics right from the external world. Unchecked.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize))]
pub struct UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
/// The actual extrinsic information.
pub extrinsic: Extrinsic<AccountId, Index, Call>,
/// The signature; should be an Ed25519 signature applied to the serialised `extrinsic` field.
pub signature: Signature,
}
impl<AccountId, Index, Call, Signature> Slicable for UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member + Slicable,
Index: Member + Slicable,
Call: Member + Slicable,
Signature: Member + Slicable
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
// This is a little more complicated than usual since the binary format must be compatible
// with substrate's generic `Vec<u8>` type. Basically this just means accepting that there
// will be a prefix of u32, which has the total number of bytes following (we don't need
// to use this).
let _length_do_not_remove_me_see_above: u32 = Slicable::decode(input)?;
Some(UncheckedExtrinsic {
extrinsic: Slicable::decode(input)?,
signature: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
// need to prefix with the total length as u32 to ensure it's binary comptible with
// Vec<u8>. we'll make room for it here, then overwrite once we know the length.
v.extend(&[0u8; 4]);
self.extrinsic.signed.using_encoded(|s| v.extend(s));
self.extrinsic.index.using_encoded(|s| v.extend(s));
self.extrinsic.function.using_encoded(|s| v.extend(s));
self.signature.using_encoded(|s| v.extend(s));
let length = (v.len() - 4) as u32;
length.using_encoded(|s| v[0..4].copy_from_slice(s));
v
}
}
#[cfg(feature = "std")]
impl<AccountId, Index, Call, Signature> fmt::Debug for UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedExtrinsic({:?})", self.extrinsic)
}
}
impl<AccountId, Index, Call, Signature> traits::Checkable for UncheckedExtrinsic<AccountId, Index, Call, Signature> where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member + traits::Verify<Signer = AccountId>,
Extrinsic<AccountId, Index, Call>: Slicable
{
type Checked = CheckedExtrinsic<AccountId, Index, Call, Signature>;
fn check(self) -> Result<Self::Checked, Self> {
if ::codec::Slicable::using_encoded(&self.extrinsic, |msg|
self.signature.verify(msg, &self.extrinsic.signed)
) {
Ok(CheckedExtrinsic(self))
} else {
Err(self)
}
}
}
/// A type-safe indicator that a extrinsic has been checked.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct CheckedExtrinsic<AccountId, Index, Call, Signature>
(UncheckedExtrinsic<AccountId, Index, Call, Signature>)
where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member;
impl<AccountId, Index, Call, Signature> CheckedExtrinsic<AccountId, Index, Call, Signature>
where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
/// Get a reference to the checked signature.
pub fn signature(&self) -> &Signature {
&self.0.signature
}
}
impl<AccountId, Index, Call, Signature> ops::Deref
for CheckedExtrinsic<AccountId, Index, Call, Signature>
where
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
type Target = Extrinsic<AccountId, Index, Call>;
fn deref(&self) -> &Self::Target {
&self.0.extrinsic
}
}
impl<AccountId, Index, Call, Signature> traits::Applyable
for CheckedExtrinsic<AccountId, Index, Call, Signature>
where
AccountId: Member,
Index: Member,
Call: Member + AuxDispatchable<Aux = AccountId>,
Signature: Member
{
type Index = Index;
type AccountId = AccountId;
fn index(&self) -> &Self::Index {
&self.0.extrinsic.index
}
fn sender(&self) -> &Self::AccountId {
&self.0.extrinsic.signed
}
fn apply(self) {
let xt = self.0.extrinsic;
xt.function.dispatch(&xt.signed);
}
}
#[derive(Default, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
pub struct Digest<Item: Member> {
pub logs: Vec<Item>,
}
impl<Item> Slicable for Digest<Item> where
Item: Member + Slicable
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Digest { logs: Slicable::decode(input)? })
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.logs.using_encoded(f)
}
}
impl<Item> traits::Digest for Digest<Item> where
Item: Member + Slicable
{
type Item = Item;
fn push(&mut self, item: Self::Item) {
self.logs.push(item);
}
}
/// Abstraction over a block header for a substrate chain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header<Number, Hash, DigestItem> where
Number: Member,
Hash: Member,
DigestItem: Member,
{
/// The parent hash.
pub parent_hash: Hash,
/// The block number.
pub number: Number,
/// The state trie merkle root
pub state_root: Hash,
/// The merkle root of the extrinsics.
pub extrinsics_root: Hash,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest<DigestItem>,
}
impl<Number, Hash, DigestItem> Slicable for Header<Number, Hash, DigestItem> where
Number: Member + Slicable,
Hash: Member + Slicable,
DigestItem: Member + Slicable,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Header {
parent_hash: Slicable::decode(input)?,
number: Slicable::decode(input)?,
state_root: Slicable::decode(input)?,
extrinsics_root: Slicable::decode(input)?,
digest: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.parent_hash.using_encoded(|s| v.extend(s));
self.number.using_encoded(|s| v.extend(s));
self.state_root.using_encoded(|s| v.extend(s));
self.extrinsics_root.using_encoded(|s| v.extend(s));
self.digest.using_encoded(|s| v.extend(s));
v
}
}
impl<Number, Hash, DigestItem> traits::Header for Header<Number, Hash, DigestItem> where
Number: Member + Slicable,
Hash: Member + Slicable,
DigestItem: Member + Slicable,
{
type Number = Number;
type Hash = Hash;
type Digest = Digest<DigestItem>;
fn number(&self) -> &Self::Number { &self.number }
fn extrinsics_root(&self) -> &Self::Hash { &self.extrinsics_root }
fn state_root(&self) -> &Self::Hash { &self.state_root }
fn parent_hash(&self) -> &Self::Hash { &self.parent_hash }
fn digest(&self) -> &Self::Digest { &self.digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self {
Header {
number, extrinsics_root: extrinsics_root, state_root, parent_hash, digest
}
}
}
/// Abstraction over a substrate block.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature> where
Number: Member,
Hash: Member,
DigestItem: Member,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
/// The block header.
pub header: Header<Number, Hash, DigestItem>,
/// The accompanying extrinsics.
pub extrinsics: Vec<UncheckedExtrinsic<AccountId, Index, Call, Signature>>,
}
impl<Number, Hash, DigestItem, AccountId, Index, Call, Signature> Slicable
for Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature>
where
Number: Member,
Hash: Member,
DigestItem: Member,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member,
Header<Number, Hash, DigestItem>: Slicable,
UncheckedExtrinsic<AccountId, Index, Call, Signature>: Slicable,
{
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Block {
header: Slicable::decode(input)?,
extrinsics: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v: Vec<u8> = Vec::new();
v.extend(self.header.encode());
v.extend(self.extrinsics.encode());
v
}
}
impl<Number, Hash, DigestItem, AccountId, Index, Call, Signature> traits::Block
for Block<Number, Hash, DigestItem, AccountId, Index, Call, Signature>
where
Number: Member + Slicable,
Hash: Member + Slicable,
DigestItem: Member + Slicable,
AccountId: Member,
Index: Member,
Call: Member,
Signature: Member
{
type Extrinsic = UncheckedExtrinsic<AccountId, Index, Call, Signature>;
type Header = Header<Number, Hash, DigestItem>;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.extrinsics[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.extrinsics)
}
}
@@ -0,0 +1,87 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! System manager: Handles all of the top-level stuff; executing block/transaction, setting code
//! and depositing logs.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate serde;
#[cfg(feature = "std")]
#[macro_use]
extern crate serde_derive;
extern crate num_traits;
extern crate integer_sqrt;
extern crate substrate_runtime_std as rstd;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_codec as codec;
extern crate substrate_primitives;
#[cfg(feature = "std")] use std::collections::HashMap;
#[cfg(feature = "std")]
pub mod testing;
pub mod traits;
pub mod generic;
#[cfg(feature = "std")]
pub type BuiltExternalities = HashMap<Vec<u8>, Vec<u8>>;
#[cfg(feature = "std")]
pub trait BuildExternalities {
fn build_externalities(self) -> BuiltExternalities;
}
#[macro_export]
macro_rules! __impl_outer_config_types {
($concrete:ident $config:ident $snake:ident $($rest:ident)*) => {
#[cfg(any(feature = "std", test))]
pub type $config = $snake::GenesisConfig<$concrete>;
__impl_outer_config_types! {$concrete $($rest)*}
};
($concrete:ident) => ()
}
#[macro_export]
/// Implement the output "meta" module configuration struct.
macro_rules! impl_outer_config {
( pub struct $main:ident for $concrete:ident { $( $config:ident => $snake:ident, )* } ) => {
__impl_outer_config_types! { $concrete $( $config $snake )* }
#[cfg(any(feature = "std", test))]
pub struct $main {
$(
pub $snake: Option<$config>,
)*
}
#[cfg(any(feature = "std", test))]
impl $crate::BuildExternalities for $main {
fn build_externalities(self) -> $crate::BuiltExternalities {
let mut s = $crate::BuiltExternalities::new();
$(
if let Some(extra) = self.$snake {
s.extend(extra.build_externalities());
}
)*
s
}
}
}
}
@@ -0,0 +1,150 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Testing utilities.
use serde;
use codec::{Slicable, Input};
use runtime_support::AuxDispatchable;
use substrate_primitives::H256;
use traits::{self, Checkable, Applyable};
#[derive(Default, PartialEq, Eq, Clone, Serialize, Debug)]
pub struct Digest {
pub logs: Vec<u64>,
}
impl Slicable for Digest {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Vec::<u64>::decode(input).map(|logs| Digest { logs })
}
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.logs.using_encoded(f)
}
}
impl traits::Digest for Digest {
type Item = u64;
fn push(&mut self, item: Self::Item) {
self.logs.push(item);
}
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct Header {
pub parent_hash: H256,
pub number: u64,
pub state_root: H256,
pub extrinsics_root: H256,
pub digest: Digest,
}
impl Slicable for Header {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Header {
parent_hash: Slicable::decode(input)?,
number: Slicable::decode(input)?,
state_root: Slicable::decode(input)?,
extrinsics_root: Slicable::decode(input)?,
digest: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
self.parent_hash.using_encoded(|s| v.extend(s));
self.number.using_encoded(|s| v.extend(s));
self.state_root.using_encoded(|s| v.extend(s));
self.extrinsics_root.using_encoded(|s| v.extend(s));
self.digest.using_encoded(|s| v.extend(s));
v
}
}
impl traits::Header for Header {
type Number = u64;
type Hash = H256;
type Digest = Digest;
fn number(&self) -> &Self::Number { &self.number }
fn extrinsics_root(&self) -> &Self::Hash { &self.extrinsics_root }
fn state_root(&self) -> &Self::Hash { &self.state_root }
fn parent_hash(&self) -> &Self::Hash { &self.parent_hash }
fn digest(&self) -> &Self::Digest { &self.digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self {
Header {
number, extrinsics_root: extrinsics_root, state_root, parent_hash, digest
}
}
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug)]
pub struct Block<Xt: Slicable + Sized + serde::Serialize> {
pub header: Header,
pub extrinsics: Vec<Xt>,
}
impl<Xt: Slicable + Sized + serde::Serialize> Slicable for Block<Xt> {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(Block {
header: Slicable::decode(input)?,
extrinsics: Slicable::decode(input)?,
})
}
fn encode(&self) -> Vec<u8> {
let mut v: Vec<u8> = Vec::new();
v.extend(self.header.encode());
v.extend(self.extrinsics.encode());
v
}
}
impl<Xt: Slicable + Sized + serde::Serialize> traits::Block for Block<Xt> {
type Extrinsic = Xt;
type Header = Header;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.extrinsics[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.extrinsics)
}
}
#[derive(PartialEq, Eq, Clone, Serialize, Debug)]
pub struct TestXt<Call: AuxDispatchable + Slicable + Sized + serde::Serialize>(pub (u64, u64, Call));
impl<Call: AuxDispatchable + Slicable + Sized + serde::Serialize> Slicable for TestXt<Call> {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
Some(TestXt(Slicable::decode(input)?))
}
fn encode(&self) -> Vec<u8> {
self.0.encode()
}
}
impl<Call: AuxDispatchable + Slicable + Sized + serde::Serialize> Checkable for TestXt<Call> {
type Checked = Self;
fn check(self) -> Result<Self, Self> { Ok(self) }
}
impl<Call: AuxDispatchable<Aux = u64> + Slicable + Sized + serde::Serialize> Applyable for TestXt<Call> {
type AccountId = u64;
type Index = u64;
fn sender(&self) -> &u64 { &(self.0).0 }
fn index(&self) -> &u64 { &(self.0).1 }
fn apply(self) { (self.0).2.dispatch(&(self.0).0); }
}
@@ -0,0 +1,293 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Primitives for the runtime modules.
use rstd::prelude::*;
use rstd;
#[cfg(not(feature = "std"))] use runtime_io;
use substrate_primitives;
use codec::{Input, Slicable};
use substrate_primitives::hash::H512;
pub use integer_sqrt::IntegerSquareRoot;
pub use num_traits::{Zero, One, Bounded};
use rstd::ops::{Add, Sub, Mul, Div, Rem, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
/// Means of signature verification.
pub trait Verify {
/// Type of the signer.
type Signer;
/// Verify a signature.
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool;
}
/// Ed25519 signature verify.
#[derive(Eq, PartialEq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
pub struct Ed25519Signature(H512);
impl Verify for Ed25519Signature {
type Signer = [u8; 32];
fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool {
::runtime_io::ed25519_verify(&(self.0).0, msg, &signer[..])
}
}
impl Slicable for Ed25519Signature {
fn decode<I: Input>(input: &mut I) -> Option<Self> { Some(Ed25519Signature(Slicable::decode(input)?,)) }
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R { self.0.using_encoded(f) }
}
impl From<H512> for Ed25519Signature {
fn from(h: H512) -> Ed25519Signature {
Ed25519Signature(h)
}
}
/// Simple payment making trait, operating on a single generic `AccountId` type.
pub trait MakePayment<AccountId> {
/// Make some sort of payment concerning `who`.
fn make_payment(who: &AccountId);
}
impl<T> MakePayment<T> for () {
fn make_payment(_: &T) {}
}
/// Extensible conversion trait. Generic over both source and destination types.
pub trait Convert<A, B> {
/// Make conversion.
fn convert(a: A) -> B;
}
/// Simple trait similar to `Into`, except that it can be used to convert numerics between each
/// other.
pub trait As<T> {
/// Convert forward (ala `Into::into`).
fn as_(self) -> T;
/// Convert backward (ala `From::from`).
fn sa(T) -> Self;
}
macro_rules! impl_numerics {
( $( $t:ty ),* ) => {
$(
impl_numerics!($t: u8, u16, u32, u64, usize, i8, i16, i32, i64, isize,);
)*
};
( $f:ty : $t:ty, $( $rest:ty, )* ) => {
impl As<$t> for $f {
fn as_(self) -> $t { self as $t }
fn sa(t: $t) -> Self { t as Self }
}
impl_numerics!($f: $( $rest, )*);
};
( $f:ty : ) => {}
}
impl_numerics!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
pub struct Identity;
impl<T> Convert<T, T> for Identity {
fn convert(a: T) -> T { a }
}
pub trait HasPublicAux {
type PublicAux;
}
pub trait RefInto<T> {
fn ref_into(&self) -> &T;
}
impl<T> RefInto<T> for T {
fn ref_into(&self) -> &T { &self }
}
pub trait SimpleArithmetic:
Zero + One + IntegerSquareRoot + As<usize> +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
PartialOrd<Self> + Ord
{}
impl<T:
Zero + One + IntegerSquareRoot + As<usize> +
Add<Self, Output = Self> + AddAssign<Self> +
Sub<Self, Output = Self> + SubAssign<Self> +
Mul<Self, Output = Self> + MulAssign<Self> +
Div<Self, Output = Self> + DivAssign<Self> +
Rem<Self, Output = Self> + RemAssign<Self> +
PartialOrd<Self> + Ord
> SimpleArithmetic for T {}
pub trait SimpleBitOps:
Sized +
rstd::ops::BitOr<Self, Output = Self> +
rstd::ops::BitAnd<Self, Output = Self>
{}
impl<T:
Sized +
rstd::ops::BitOr<Self, Output = Self> +
rstd::ops::BitAnd<Self, Output = Self>
> SimpleBitOps for T {}
/// Something that can be executed.
pub trait Executable {
fn execute();
}
impl Executable for () {
fn execute() {}
}
impl<A: Executable, B: Executable> Executable for (A, B) {
fn execute() {
A::execute();
B::execute();
}
}
/// Something that acts like a `Digest` - it can have `Log`s `push`ed onto it and these `Log`s are
/// each `Slicable`.
pub trait Digest {
type Item: Sized;
fn push(&mut self, item: Self::Item);
}
impl Digest for substrate_primitives::Digest {
type Item = substrate_primitives::block::Log;
fn push(&mut self, item: Self::Item) {
self.logs.push(item);
}
}
/// Something which fulfills the abstract idea of a Substrate header. It has types for a `Number`,
/// a `Hash` and a `Digest`. It provides access to an `extrinsics_root`, `state_root` and
/// `parent_hash`, as well as a `digest` and a block `number`.
///
/// You can also create a `new` one from those fields.
pub trait Header: Sized + Slicable {
type Number: Sized;
type Hash: Sized;
type Digest: Sized;
fn number(&self) -> &Self::Number;
fn extrinsics_root(&self) -> &Self::Hash;
fn state_root(&self) -> &Self::Hash;
fn parent_hash(&self) -> &Self::Hash;
fn digest(&self) -> &Self::Digest;
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self;
}
impl Header for substrate_primitives::Header {
type Number = substrate_primitives::block::Number;
type Hash = substrate_primitives::block::HeaderHash;
type Digest = substrate_primitives::block::Digest;
fn number(&self) -> &Self::Number { &self.number }
fn extrinsics_root(&self) -> &Self::Hash { &self.transaction_root }
fn state_root(&self) -> &Self::Hash { &self.state_root }
fn parent_hash(&self) -> &Self::Hash { &self.parent_hash }
fn digest(&self) -> &Self::Digest { &self.digest }
fn new(
number: Self::Number,
extrinsics_root: Self::Hash,
state_root: Self::Hash,
parent_hash: Self::Hash,
digest: Self::Digest
) -> Self {
substrate_primitives::Header {
number: number,
transaction_root: extrinsics_root,
state_root: state_root,
parent_hash: parent_hash,
digest: digest,
}
}
}
/// Something which fulfills the abstract idea of a Substrate block. It has types for an
/// `Extrinsic` piece of information as well as a `Header`.
///
/// You can get an iterator over each of the `extrinsics` and retrieve the `header`.
pub trait Block {
type Extrinsic: Sized;
type Header: Header;
fn header(&self) -> &Self::Header;
fn extrinsics(&self) -> &[Self::Extrinsic];
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>);
}
impl Block for substrate_primitives::Block {
type Extrinsic = substrate_primitives::block::Transaction;
type Header = substrate_primitives::Header;
fn header(&self) -> &Self::Header {
&self.header
}
fn extrinsics(&self) -> &[Self::Extrinsic] {
&self.transactions[..]
}
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
(self.header, self.transactions)
}
}
/// A "checkable" piece of information, used by the standard Substrate Executive in order to
/// check the validity of a piece of extrinsic information, usually by verifying the signature.
pub trait Checkable: Sized {
type Checked: Sized;
fn check(self) -> Result<Self::Checked, Self>;
}
/// An "executable" piece of information, used by the standard Substrate Executive in order to
/// enact a piece of extrinsic information by marshalling and dispatching to a named functioon
/// call.
///
/// Also provides information on to whom this information is attributable and an index that allows
/// each piece of attributable information to be disambiguated.
pub trait Applyable {
type AccountId;
type Index;
fn index(&self) -> &Self::Index;
fn sender(&self) -> &Self::AccountId;
fn apply(self);
}
/// Something that can be checked for equality and printed out to a debug channel if bad.
pub trait CheckEqual {
fn check_equal(&self, other: &Self);
}
impl CheckEqual for substrate_primitives::H256 {
#[cfg(feature = "std")]
fn check_equal(&self, other: &Self) {
use substrate_primitives::hexdisplay::HexDisplay;
if &self.0 != &other.0 {
println!("Hash: given={}, expected={}", HexDisplay::from(&self.0), HexDisplay::from(&other.0));
}
}
#[cfg(not(feature = "std"))]
fn check_equal(&self, other: &Self) {
if self != other {
runtime_io::print("Hash not equal");
runtime_io::print(&self.0[..]);
runtime_io::print(&other.0[..]);
}
}
}
@@ -0,0 +1,34 @@
[package]
name = "substrate-runtime-session"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
safe-mix = { path = "../../../safe-mix", default_features = false}
substrate-keyring = { path = "../../keyring", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-runtime-consensus = { path = "../consensus", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"safe-mix/std",
"substrate-keyring",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-consensus/std",
"substrate-runtime-system/std",
]
@@ -0,0 +1,345 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Session manager: is told the validators and allows them to manage their session keys for the
//! consensus module.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate serde;
#[cfg(any(feature = "std", test))]
extern crate substrate_keyring as keyring;
#[cfg(any(feature = "std", test))]
extern crate substrate_primitives;
#[cfg_attr(feature = "std", macro_use)]
extern crate substrate_runtime_std as rstd;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_codec as codec;
extern crate substrate_runtime_primitives as primitives;
extern crate substrate_runtime_consensus as consensus;
extern crate substrate_runtime_system as system;
use rstd::prelude::*;
use primitives::traits::{Zero, One, RefInto, Executable, Convert};
use runtime_support::{StorageValue, StorageMap};
pub trait Trait: consensus::Trait + system::Trait {
type PublicAux: RefInto<Self::AccountId>;
type ConvertAccountIdToSessionKey: Convert<Self::AccountId, Self::SessionKey>;
}
decl_module! {
pub struct Module<T: Trait>;
pub enum Call where aux: T::PublicAux {
fn set_key(aux, key: T::SessionKey) = 0;
}
pub enum PrivCall {
fn set_length(new: T::BlockNumber) = 0;
fn force_new_session() = 1;
}
}
decl_storage! {
trait Store for Module<T: Trait>;
// The current set of validators.
pub Validators get(validators): b"ses:val" => required Vec<T::AccountId>;
// Current length of the session.
pub SessionLength get(length): b"ses:len" => required T::BlockNumber;
// Current index of the session.
pub CurrentIndex get(current_index): b"ses:ind" => required T::BlockNumber;
// Block at which the session length last changed.
LastLengthChange: b"ses:llc" => T::BlockNumber;
// The next key for a given validator.
NextKeyFor: b"ses:nxt:" => map [ T::AccountId => T::SessionKey ];
// The next session length.
NextSessionLength: b"ses:nln" => T::BlockNumber;
}
impl<T: Trait> Module<T> {
/// The number of validators currently.
pub fn validator_count() -> u32 {
<Validators<T>>::get().len() as u32 // TODO: can probably optimised
}
/// The last length change, if there was one, zero if not.
pub fn last_length_change() -> T::BlockNumber {
<LastLengthChange<T>>::get().unwrap_or_else(T::BlockNumber::zero)
}
/// Sets the session key of `_validator` to `_key`. This doesn't take effect until the next
/// session.
fn set_key(aux: &T::PublicAux, key: T::SessionKey) {
// set new value for next session
<NextKeyFor<T>>::insert(aux.ref_into(), key)
}
/// Set a new era length. Won't kick in until the next era change (at current length).
fn set_length(new: T::BlockNumber) {
<NextSessionLength<T>>::put(new);
}
/// Forces a new session.
fn force_new_session() {
Self::rotate_session();
}
// INTERNAL API (available to other runtime modules)
/// Set the current set of validators.
///
/// Called by `staking::next_era()` only. `next_session` should be called after this in order to
/// update the session keys to the next validator set.
pub fn set_validators(new: &[T::AccountId]) {
<Validators<T>>::put(&new.to_vec()); // TODO: optimise.
<consensus::Module<T>>::set_authorities(
&new.iter().cloned().map(T::ConvertAccountIdToSessionKey::convert).collect::<Vec<_>>()
);
}
/// Hook to be called after transaction processing.
pub fn check_rotate_session() {
// 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();
if ((block_number - Self::last_length_change()) % Self::length()).is_zero() {
Self::rotate_session();
}
}
/// Move onto next session: register the new authority set.
pub fn rotate_session() {
// Increment current session index.
<CurrentIndex<T>>::put(<CurrentIndex<T>>::get() + One::one());
// Enact era length change.
if let Some(next_len) = <NextSessionLength<T>>::take() {
let block_number = <system::Module<T>>::block_number();
<SessionLength<T>>::put(next_len);
<LastLengthChange<T>>::put(block_number);
}
// Update any changes in session keys.
Self::validators().iter().enumerate().for_each(|(i, v)| {
if let Some(n) = <NextKeyFor<T>>::take(v) {
<consensus::Module<T>>::set_authority(i as u32, &n);
}
});
}
}
impl<T: Trait> Executable for Module<T> {
fn execute() {
Self::check_rotate_session();
}
}
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait> {
pub session_length: T::BlockNumber,
pub validators: Vec<T::AccountId>,
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> GenesisConfig<T> where T::AccountId: From<keyring::Keyring> {
pub fn simple() -> Self where T::AccountId: From<[u8; 32]> {
use primitives::traits::As;
use keyring::Keyring::*;
let three = [3u8; 32];
GenesisConfig {
session_length: T::BlockNumber::sa(2),
validators: vec![T::AccountId::from(One), T::AccountId::from(Two), T::AccountId::from(three)],
}
}
pub fn extended() -> Self {
use primitives::traits::As;
use keyring::Keyring::*;
GenesisConfig {
session_length: T::BlockNumber::sa(1),
validators: vec![T::AccountId::from(Alice), T::AccountId::from(Bob), T::AccountId::from(Charlie)],
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
use primitives::traits::As;
GenesisConfig {
session_length: T::BlockNumber::sa(1000),
validators: vec![],
}
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_io::TestExternalities {
use runtime_io::twox_128;
use codec::Slicable;
use primitives::traits::As;
map![
twox_128(<SessionLength<T>>::key()).to_vec() => self.session_length.encode(),
twox_128(<CurrentIndex<T>>::key()).to_vec() => T::BlockNumber::sa(0).encode(),
twox_128(<Validators<T>>::key()).to_vec() => self.validators.encode()
]
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::with_externalities;
use substrate_primitives::H256;
use primitives::BuildExternalities;
use primitives::traits::{HasPublicAux, Identity};
use primitives::testing::{Digest, Header};
pub struct Test;
impl HasPublicAux for Test {
type PublicAux = u64;
}
impl consensus::Trait for Test {
type SessionKey = u64;
}
impl system::Trait for Test {
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = runtime_io::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Header = Header;
}
impl Trait for Test {
type PublicAux = <Self as HasPublicAux>::PublicAux;
type ConvertAccountIdToSessionKey = Identity;
}
type System = system::Module<Test>;
type Consensus = consensus::Module<Test>;
type Session = Module<Test>;
fn new_test_ext() -> runtime_io::TestExternalities {
let mut t = system::GenesisConfig::<Test>::default().build_externalities();
t.extend(consensus::GenesisConfig::<Test>{
authorities: vec![1, 2, 3],
}.build_externalities());
t.extend(GenesisConfig::<Test>{
session_length: 2,
validators: vec![1, 2, 3],
}.build_externalities());
t
}
#[test]
fn simple_setup_should_work() {
with_externalities(&mut new_test_ext(), || {
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
assert_eq!(Session::length(), 2);
assert_eq!(Session::validators(), vec![1, 2, 3]);
});
}
#[test]
fn session_length_change_should_work() {
with_externalities(&mut new_test_ext(), || {
// Block 1: Change to length 3; no visible change.
System::set_block_number(1);
Session::set_length(3);
Session::check_rotate_session();
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);
Session::set_length(3);
Session::check_rotate_session();
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();
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);
Session::set_length(2);
Session::check_rotate_session();
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();
assert_eq!(Session::length(), 2);
assert_eq!(Session::current_index(), 2);
// Block 6: No change.
System::set_block_number(6);
Session::check_rotate_session();
assert_eq!(Session::length(), 2);
assert_eq!(Session::current_index(), 2);
// Block 7: Next index.
System::set_block_number(7);
Session::check_rotate_session();
assert_eq!(Session::length(), 2);
assert_eq!(Session::current_index(), 3);
});
}
#[test]
fn session_change_should_work() {
with_externalities(&mut new_test_ext(), || {
// Block 1: No change
System::set_block_number(1);
Session::check_rotate_session();
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
// Block 2: Session rollover, but no change.
System::set_block_number(2);
Session::check_rotate_session();
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
// Block 3: Set new key for validator 2; no visible change.
System::set_block_number(3);
Session::set_key(&2, 5);
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
Session::check_rotate_session();
assert_eq!(Consensus::authorities(), vec![1, 2, 3]);
// Block 4: Session rollover, authority 2 changes.
System::set_block_number(4);
Session::check_rotate_session();
assert_eq!(Consensus::authorities(), vec![1, 5, 3]);
});
}
}
@@ -0,0 +1,35 @@
[package]
name = "substrate-runtime-staking"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
safe-mix = { path = "../../../safe-mix", default_features = false}
substrate-keyring = { path = "../../keyring", optional = true }
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
substrate-runtime-consensus = { path = "../consensus", default_features = false }
substrate-runtime-system = { path = "../system", default_features = false }
substrate-runtime-session = { path = "../session", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"safe-mix/std",
"substrate-keyring",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"substrate-runtime-session/std",
"substrate-runtime-system/std",
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
[package]
name = "substrate-runtime-system"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
safe-mix = { path = "../../../safe-mix", default_features = false}
substrate-codec = { path = "../../codec", default_features = false }
substrate-primitives = { path = "../../primitives", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", default_features = false }
substrate-runtime-io = { path = "../../runtime-io", default_features = false }
substrate-runtime-support = { path = "../../runtime-support", default_features = false }
substrate-runtime-primitives = { path = "../primitives", default_features = false }
[features]
default = ["std"]
std = [
"serde/std",
"safe-mix/std",
"substrate-codec/std",
"substrate-primitives/std",
"substrate-runtime-std/std",
"substrate-runtime-io/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
]
@@ -0,0 +1,178 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! System manager: Handles lowest level stuff like depositing logs, basic set up and take down of
//! temporary storage entries, access to old block hashes.
#![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(feature = "std")]
extern crate serde;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_codec as codec;
extern crate substrate_runtime_primitives as primitives;
extern crate safe_mix;
use rstd::prelude::*;
use runtime_io::Hashing;
use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, One, Bounded};
use runtime_support::{StorageValue, StorageMap, Parameter};
use safe_mix::TripletMix;
#[cfg(any(feature = "std", test))]
use rstd::marker::PhantomData;
#[cfg(any(feature = "std", test))]
use codec::Slicable;
#[cfg(any(feature = "std", test))]
use runtime_io::{twox_128, TestExternalities};
pub trait Trait {
type Index: Parameter + Default + SimpleArithmetic + Copy;
type BlockNumber: Parameter + SimpleArithmetic + Default + Bounded + Copy;
type Hash: Parameter + SimpleBitOps + Default + Copy + CheckEqual;
type Hashing: Hashing<Output = Self::Hash>;
type Digest: Parameter + Default + traits::Digest;
type AccountId: Parameter + Ord + Default;
type Header: traits::Header<Number = Self::BlockNumber, Hash = Self::Hash, Digest = Self::Digest>;
}
decl_module! {
pub struct Module<T: Trait>;
}
decl_storage! {
trait Store for Module<T: Trait>;
pub AccountIndex get(account_index): b"sys:non" => default map [ T::AccountId => T::Index ];
pub BlockHash get(block_hash): b"sys:old" => required map [ T::BlockNumber => T::Hash ];
RandomSeed get(random_seed): b"sys:rnd" => required T::Hash;
// The current block number being processed. Set by `execute_block`.
Number get(block_number): b"sys:num" => required T::BlockNumber;
ParentHash get(parent_hash): b"sys:pha" => required T::Hash;
ExtrinsicsRoot get(extrinsics_root): b"sys:txr" => required T::Hash;
Digest get(digest): b"sys:dig" => default T::Digest;
}
impl<T: Trait> Module<T> {
/// Start the execution of a particular block.
pub fn initialise(number: &T::BlockNumber, parent_hash: &T::Hash, txs_root: &T::Hash) {
// populate environment.
<Number<T>>::put(number);
<ParentHash<T>>::put(parent_hash);
<ExtrinsicsRoot<T>>::put(txs_root);
<RandomSeed<T>>::put(Self::calculate_random());
}
/// Remove temporary "environment" entries in storage.
pub fn finalise() -> T::Header {
<RandomSeed<T>>::kill();
let number = <Number<T>>::take();
let parent_hash = <ParentHash<T>>::take();
let digest = <Digest<T>>::take();
let extrinsics_root = <ExtrinsicsRoot<T>>::take();
let storage_root = T::Hashing::storage_root();
<T::Header as traits::Header>::new(number, extrinsics_root, storage_root, parent_hash, digest)
}
/// Deposits a log and ensures it matches the blocks log data.
pub fn deposit_log(item: <T::Digest as traits::Digest>::Item) {
let mut l = <Digest<T>>::get();
traits::Digest::push(&mut l, item);
<Digest<T>>::put(l);
}
/// Records a particular block number and hash combination.
pub fn record_block_hash<H: traits::Header<Number = T::BlockNumber>>(header: &H) {
// store the header hash in storage; we can't do it before otherwise there would be a
// cyclic dependency.
<BlockHash<T>>::insert(header.number(), &T::Hashing::hash_of(header));
}
/// Initializes the state following the determination of the genesis block.
pub fn initialise_genesis_state<H: traits::Header<Number = T::BlockNumber>>(header: &H) {
Self::record_block_hash(header);
}
/// Calculate the current block's random seed.
fn calculate_random() -> T::Hash {
(0..81)
.scan(
{ let mut n = Self::block_number().clone(); n -= T::BlockNumber::one(); n },
|c, _| { if *c > T::BlockNumber::zero() { *c -= T::BlockNumber::one() }; Some(c.clone())
})
.map(Self::block_hash)
.triplet_mix()
}
/// Get the basic externalities for this module, useful for tests.
#[cfg(any(feature = "std", test))]
pub fn externalities() -> TestExternalities {
map![
twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), // TODO: replace with Hash::default().encode
twox_128(<Number<T>>::key()).to_vec() => T::BlockNumber::one().encode(),
twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode(), // TODO: replace with Hash::default().encode
twox_128(<RandomSeed<T>>::key()).to_vec() => T::Hash::default().encode()
]
}
/// Set the block number to something in particular. Can be used as an alternative to
/// `initialise` for tests that don't need to bother with the other environment entries.
#[cfg(any(feature = "std", test))]
pub fn set_block_number(n: T::BlockNumber) {
<Number<T>>::put(n);
}
/// Increment a particular account's nonce by 1.
pub fn inc_account_index(who: &T::AccountId) {
<AccountIndex<T>>::insert(who, Self::account_index(who) + T::Index::one());
}
}
#[cfg(any(feature = "std", test))]
pub struct GenesisConfig<T: Trait>(PhantomData<T>);
#[cfg(any(feature = "std", test))]
impl<T: Trait> Default for GenesisConfig<T> {
fn default() -> Self {
GenesisConfig(PhantomData)
}
}
#[cfg(any(feature = "std", test))]
impl<T: Trait> primitives::BuildExternalities for GenesisConfig<T>
{
fn build_externalities(self) -> runtime_io::TestExternalities {
use runtime_io::twox_128;
use codec::Slicable;
map![
twox_128(&<BlockHash<T>>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(),
twox_128(<Number<T>>::key()).to_vec() => 1u64.encode(),
twox_128(<ParentHash<T>>::key()).to_vec() => [69u8; 32].encode(),
twox_128(<RandomSeed<T>>::key()).to_vec() => [0u8; 32].encode()
]
}
}
@@ -0,0 +1,25 @@
[package]
name = "substrate-runtime-timestamp"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
hex-literal = "0.1.0"
serde = { version = "1.0", default_features = false }
substrate-runtime-std = { path = "../../runtime-std", 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 }
[dev-dependencies]
substrate-runtime-io = { path = "../../runtime-io", default_features = true }
[features]
default = ["std"]
std = [
"substrate-runtime-std/std",
"substrate-runtime-support/std",
"substrate-runtime-primitives/std",
"serde/std",
"substrate-codec/std",
]
@@ -0,0 +1,93 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Substrate Demo.
// Substrate Demo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate Demo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate Demo. If not, see <http://www.gnu.org/licenses/>.
//! Timestamp manager: just handles the current timestamp.
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg_attr(test, macro_use)]
extern crate substrate_runtime_std as rstd;
#[macro_use]
extern crate substrate_runtime_support as runtime_support;
#[cfg(test)]
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_runtime_primitives as runtime_primitives;
extern crate substrate_codec as codec;
use runtime_support::{StorageValue, Parameter};
use runtime_primitives::traits::HasPublicAux;
pub trait Trait: HasPublicAux {
type Value: Parameter + Default;
}
decl_module! {
pub struct Module<T: Trait>;
pub enum Call where aux: T::PublicAux {
fn set(aux, now: T::Value) = 0;
}
}
decl_storage! {
pub trait Store for Module<T: Trait>;
pub Now get(now): b"tim:val" => required T::Value;
}
impl<T: Trait> Module<T> {
pub fn get() -> T::Value {
<Self as Store>::Now::get()
}
/// Set the current time.
fn set(_aux: &T::PublicAux, now: T::Value) {
<Self as Store>::Now::put(now);
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities};
use codec::Joiner;
use runtime_support::storage::StorageValue;
struct TraitImpl;
impl HasPublicAux for TraitImpl {
type PublicAux = u64;
}
impl Trait for TraitImpl {
type Value = u64;
}
type Timestamp = Module<TraitImpl>;
#[test]
fn timestamp_works() {
let mut t: TestExternalities = map![
twox_128(<Timestamp as Store>::Now::key()).to_vec() => vec![].and(&42u64)
];
with_externalities(&mut t, || {
assert_eq!(<Timestamp as Store>::Now::get(), 42);
Timestamp::aux_dispatch(Call::set(69), &0);
assert_eq!(Timestamp::now(), 69);
});
}
}