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,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![],
});
});
}
}