// Copyright 2017 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! 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(any(feature = "std", test))] extern crate substrate_primitives; #[cfg_attr(any(feature = "std", test), macro_use)] extern crate sr_std as rstd; #[macro_use] extern crate srml_support as runtime_support; #[cfg(feature = "std")] extern crate serde; #[cfg(feature = "std")] #[macro_use] extern crate serde_derive; #[macro_use] extern crate parity_codec_derive; extern crate parity_codec as codec; extern crate sr_io as runtime_io; extern crate sr_primitives as primitives; extern crate safe_mix; use rstd::prelude::*; use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, One, Bounded, Hash, Member, MaybeDisplay, EnsureOrigin}; 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::Encode; #[cfg(any(feature = "std", test))] use runtime_io::{twox_128, TestExternalities, Blake2Hasher}; /// Compute the extrinsics root of a list of extrinsics. pub fn extrinsics_root(extrinsics: &[E]) -> H::Output { extrinsics_data_root::(extrinsics.iter().map(codec::Encode::encode).collect()) } /// Compute the extrinsics root of a list of extrinsics. pub fn extrinsics_data_root(xts: Vec>) -> H::Output { let xts = xts.iter().map(Vec::as_slice).collect::>(); H::enumerated_trie_root(&xts) } pub trait Trait: Eq + Clone { type Origin: Into>> + From>; type Index: Parameter + Member + Default + MaybeDisplay + SimpleArithmetic + Copy; type BlockNumber: Parameter + Member + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy + rstd::hash::Hash; type Hash: Parameter + Member + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]>; type Hashing: Hash; type Digest: Parameter + Member + Default + traits::Digest; type AccountId: Parameter + Member + MaybeDisplay + Ord + Default; type Header: Parameter + traits::Header< Number = Self::BlockNumber, Hash = Self::Hash, Digest = Self::Digest >; type Event: Parameter + Member + From; } pub type DigestItemOf = <::Digest as traits::Digest>::Item; decl_module! { pub struct Module for enum Call where origin: T::Origin {} } /// A phase of a block's execution. #[derive(Encode, Decode)] #[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone, Debug))] pub enum Phase { /// Applying an extrinsic. ApplyExtrinsic(u32), /// The end. Finalization, } /// Record of an event happening. #[derive(Encode, Decode)] #[cfg_attr(feature = "std", derive(Serialize, PartialEq, Eq, Clone, Debug))] pub struct EventRecord { /// The phase of the block it happened in. pub phase: Phase, /// The event itself. pub event: E, } /// Event for the system module. decl_event!( pub enum Event { /// An extrinsic completed successfully. ExtrinsicSuccess, /// An extrinsic failed. ExtrinsicFailed, } ); /// Origin for the system module. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug))] pub enum RawOrigin { /// The system itself ordained this dispatch to happen: this is the highest privilege level. Root, /// It is signed by some public key and we provide the AccountId. Signed(AccountId), /// It is signed by nobody but included and agreed upon by the validators anyway: it's "inherently" true. Inherent, } impl From> for RawOrigin { fn from(s: Option) -> RawOrigin { match s { Some(who) => RawOrigin::Signed(who), None => RawOrigin::Inherent, } } } /// Exposed trait-generic origin type. pub type Origin = RawOrigin<::AccountId>; decl_storage! { trait Store for Module as System { pub AccountNonce get(account_nonce): default map [ T::AccountId => T::Index ]; ExtrinsicCount: u32; pub BlockHash get(block_hash): required map [ T::BlockNumber => T::Hash ]; pub ExtrinsicIndex get(extrinsic_index): u32; ExtrinsicData get(extrinsic_data): required map [ u32 => Vec ]; RandomSeed get(random_seed): required T::Hash; /// The current block number being processed. Set by `execute_block`. Number get(block_number): required T::BlockNumber; ParentHash get(parent_hash): required T::Hash; ExtrinsicsRoot get(extrinsics_root): required T::Hash; Digest get(digest): default T::Digest; Events get(events): default Vec>; } } pub struct EnsureRoot(::rstd::marker::PhantomData); impl>>, AccountId> EnsureOrigin for EnsureRoot { type Success = (); fn ensure_origin(o: O) -> Result { ensure_root(o) } } /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed(o: OuterOrigin) -> Result where OuterOrigin: Into>> { match o.into() { Some(RawOrigin::Signed(t)) => Ok(t), _ => Err("bad origin: expected to be a signed origin"), } } /// Ensure that the origin `o` represents the root. Returns `Ok` or an `Err` otherwise. pub fn ensure_root(o: OuterOrigin) -> Result<(), &'static str> where OuterOrigin: Into>> { match o.into() { Some(RawOrigin::Root) => Ok(()), _ => Err("bad origin: expected to be a root origin"), } } /// Ensure that the origin `o` represents an unsigned extrinsic. Returns `Ok` or an `Err` otherwise. pub fn ensure_inherent(o: OuterOrigin) -> Result<(), &'static str> where OuterOrigin: Into>> { match o.into() { Some(RawOrigin::Inherent) => Ok(()), _ => Err("bad origin: expected to be an inherent origin"), } } impl Module { /// Start the execution of a particular block. pub fn initialise(number: &T::BlockNumber, parent_hash: &T::Hash, txs_root: &T::Hash) { // populate environment. >::put(number); >::put(parent_hash); >::insert(*number - One::one(), parent_hash); >::put(txs_root); >::put(Self::calculate_random()); >::put(0u32); >::kill(); } /// Remove temporary "environment" entries in storage. pub fn finalise() -> T::Header { >::kill(); >::kill(); let number = >::take(); let parent_hash = >::take(); let digest = >::take(); let extrinsics_root = >::take(); let storage_root = T::Hashing::storage_root(); // > stays to be inspected by the client. ::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: ::Item) { let mut l = >::get(); traits::Digest::push(&mut l, item); >::put(l); } /// Deposits an event onto this block's event record. pub fn deposit_event(event: T::Event) { let phase = >::get().map_or(Phase::Finalization, |c| Phase::ApplyExtrinsic(c)); let mut events = Self::events(); events.push(EventRecord { phase, event }); >::put(events); } /// Calculate the current block's random seed. fn calculate_random() -> T::Hash { assert!(Self::block_number() > Zero::zero(), "Block number may never be zero"); (0..81) .scan( Self::block_number() - One::one(), |c, _| { if *c > Zero::zero() { *c -= One::one() }; Some(*c) }) .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(&>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), // TODO: replace with Hash::default().encode twox_128(>::key()).to_vec() => T::BlockNumber::one().encode(), twox_128(>::key()).to_vec() => [69u8; 32].encode(), // TODO: replace with Hash::default().encode twox_128(>::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) { >::put(n); } /// Set the parent hash 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_parent_hash(n: T::Hash) { >::put(n); } /// Set the random seed 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_random_seed(seed: T::Hash) { >::put(seed); } /// Increment a particular account's nonce by 1. pub fn inc_account_nonce(who: &T::AccountId) { >::insert(who, Self::account_nonce(who) + T::Index::one()); } /// Note what the extrinsic data of the current extrinsic index is. If this is called, then /// ensure `derive_extrinsics` is also called before block-building is completed. pub fn note_extrinsic(encoded_xt: Vec) { >::insert(>::get().unwrap_or_default(), encoded_xt); } /// To be called immediately after an extrinsic has been applied. pub fn note_applied_extrinsic(r: &Result<(), &'static str>) { Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess, Err(_) => Event::ExtrinsicFailed, }.into()); >::put(>::get().unwrap_or_default() + 1u32); } /// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block /// has been called. pub fn note_finished_extrinsics() { >::put(>::get().unwrap_or_default()); >::kill(); } /// Remove all extrinsics data and save the extrinsics trie root. pub fn derive_extrinsics() { let extrinsics = (0..>::get().unwrap_or_default()).map(>::take).collect(); let xts_root = extrinsics_data_root::(extrinsics); >::put(xts_root); } } #[cfg(any(feature = "std", test))] #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct GenesisConfig(PhantomData); #[cfg(any(feature = "std", test))] impl Default for GenesisConfig { fn default() -> Self { GenesisConfig(PhantomData) } } #[cfg(any(feature = "std", test))] impl primitives::BuildStorage for GenesisConfig { fn build_storage(self) -> Result { use codec::Encode; Ok(map![ Self::hash(&>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), Self::hash(>::key()).to_vec() => 1u64.encode(), Self::hash(>::key()).to_vec() => [69u8; 32].encode(), Self::hash(>::key()).to_vec() => [0u8; 32].encode(), Self::hash(>::key()).to_vec() => [0u8; 4].encode() ]) } } #[cfg(test)] mod tests { use super::*; use runtime_io::with_externalities; use substrate_primitives::H256; use primitives::BuildStorage; use primitives::traits::BlakeTwo256; use primitives::testing::{Digest, Header}; impl_outer_origin!{ pub enum Origin for Test where system = super {} } #[derive(Clone, Eq, PartialEq)] pub struct Test; impl Trait for Test { type Origin = Origin; type Index = u64; type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; type Digest = Digest; type AccountId = u64; type Header = Header; type Event = u16; } impl From for u16 { fn from(e: Event) -> u16 { match e { Event::ExtrinsicSuccess => 100, Event::ExtrinsicFailed => 101, } } } type System = Module; fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::::default().build_storage().unwrap().into() } #[test] fn deposit_event_should_work() { with_externalities(&mut new_test_ext(), || { System::initialise(&1, &[0u8; 32].into(), &[0u8; 32].into()); System::note_finished_extrinsics(); System::deposit_event(1u16); System::finalise(); assert_eq!(System::events(), vec![EventRecord { phase: Phase::Finalization, event: 1u16 }]); System::initialise(&2, &[0u8; 32].into(), &[0u8; 32].into()); System::deposit_event(42u16); System::note_applied_extrinsic(&Ok(())); System::note_applied_extrinsic(&Err("")); System::note_finished_extrinsics(); System::deposit_event(3u16); System::finalise(); assert_eq!(System::events(), vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: 42u16 }, EventRecord { phase: Phase::ApplyExtrinsic(0), event: 100u16 }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: 101u16 }, EventRecord { phase: Phase::Finalization, event: 3u16 } ]); }); } }