// Copyright 2017-2019 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 module //! //! The system module provides low-level access to core types and cross-cutting utilities. //! It acts as the base layer for other SRML modules to interact with the Substrate framework components. //! To use it in your module, you should ensure your module's trait implies the system [`Trait`]. //! //! ## Overview //! //! The system module defines the core data types used in a Substrate runtime. //! It also provides several utility functions (see [`Module`]) for other runtime modules. //! //! In addition, it manages the storage items for extrinsics data, indexes, event record and digest items, //! among other things that support the execution of the current block. //! //! It also handles low level tasks like depositing logs, basic set up and take down of //! temporary storage entries and access to previous block hashes. //! //! ## Interface //! //! ### Dispatchable functions //! //! The system module does not implement any dispatchable functions. //! //! ### Public functions //! //! All public functions are available as part of the [`Module`] type. //! //! ## Usage //! //! ### Prerequisites //! //! Import the system module and derive your module's configuration trait from the system trait. //! //! ### Example - Get random seed and extrinsic count for the current block //! //! ``` //! use srml_support::{decl_module, dispatch::Result}; //! use srml_system::{self as system, ensure_signed}; //! //! pub trait Trait: system::Trait {} //! //! decl_module! { //! pub struct Module for enum Call where origin: T::Origin { //! pub fn system_module_example(origin) -> Result { //! let _sender = ensure_signed(origin)?; //! let _random_seed = >::random_seed(); //! let _extrinsic_count = >::extrinsic_count(); //! Ok(()) //! } //! } //! } //! # fn main() { } //! ``` #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] use serde_derive::Serialize; use rstd::prelude::*; #[cfg(any(feature = "std", test))] use rstd::map; use primitives::traits::{self, CheckEqual, SimpleArithmetic, SimpleBitOps, Zero, One, Bounded, Lookup, Hash, Member, MaybeDisplay, EnsureOrigin, Digest as DigestT, As, CurrentHeight, BlockNumberToHash, MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup}; use substrate_primitives::storage::well_known_keys; use srml_support::{storage, StorageValue, StorageMap, Parameter, decl_module, decl_event, decl_storage}; use safe_mix::TripletMix; use parity_codec::{Encode, Decode}; #[cfg(any(feature = "std", test))] use runtime_io::{twox_128, TestExternalities, Blake2Hasher}; #[cfg(any(feature = "std", test))] use substrate_primitives::ChangesTrieConfiguration; /// Handler for when a new account has been created. pub trait OnNewAccount { /// A new account `who` has been registered. fn on_new_account(who: &AccountId); } impl OnNewAccount for () { fn on_new_account(_who: &AccountId) {} } /// Determinator to say whether a given account is unused. pub trait IsDeadAccount { /// Is the given account dead? fn is_dead_account(who: &AccountId) -> bool; } impl IsDeadAccount for () { fn is_dead_account(_who: &AccountId) -> bool { true } } /// Compute the trie root of a list of extrinsics. pub fn extrinsics_root(extrinsics: &[E]) -> H::Output { extrinsics_data_root::(extrinsics.iter().map(parity_codec::Encode::encode).collect()) } /// Compute the trie 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: 'static + Eq + Clone { /// The aggregated `Origin` type used by dispatchable calls. type Origin: Into>> + From>; /// Account index (aka nonce) type. This stores the number of previous transactions associated with a sender /// account. type Index: Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + MaybeDisplay + SimpleArithmetic + Copy; /// The block number type used by the runtime. type BlockNumber: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleArithmetic + Default + Bounded + Copy + rstd::hash::Hash; /// The output of the `Hashing` function. type Hash: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + SimpleBitOps + Default + Copy + CheckEqual + rstd::hash::Hash + AsRef<[u8]> + AsMut<[u8]>; /// The hashing system (algorithm) being used in the runtime (e.g. Blake2). type Hashing: Hash; /// Collection of (light-client-relevant) logs for a block to be included verbatim in the block header. type Digest: Parameter + Member + MaybeSerializeDebugButNotDeserialize + Default + traits::Digest; /// The user account identifier type for the runtime. type AccountId: Parameter + Member + MaybeSerializeDebug + MaybeDisplay + Ord + Default; /// Converting trait to take a source type and convert to `AccountId`. /// /// Used to define the type and conversion mechanism for referencing accounts in transactions. It's perfectly /// reasonable for this to be an identity conversion (with the source type being `AccountId`), but other modules /// (e.g. Indices module) may provide more functional/efficient alternatives. type Lookup: StaticLookup; /// The block header. type Header: Parameter + traits::Header< Number = Self::BlockNumber, Hash = Self::Hash, Digest = Self::Digest >; /// The aggregated event type of the runtime. type Event: Parameter + Member + From; /// A piece of information which can be part of the digest (as a digest item). type Log: From> + Into>; } pub type DigestItemOf = <::Digest as traits::Digest>::Item; decl_module! { pub struct Module for enum Call where origin: T::Origin { /// Deposits an event onto this block's event record. pub fn deposit_event(event: T::Event) { let extrinsic_index = Self::extrinsic_index(); let phase = extrinsic_index.map_or(Phase::Finalization, |c| Phase::ApplyExtrinsic(c)); let mut events = Self::events(); events.push(EventRecord { phase, event }); >::put(events); } } } /// 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, } decl_event!( /// Event for the system module. 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>; pub type Log = RawLog< ::Hash, >; /// A logs in this module. #[cfg_attr(feature = "std", derive(Serialize, Debug))] #[derive(Encode, Decode, PartialEq, Eq, Clone)] pub enum RawLog { /// Changes trie has been computed for this block. Contains the root of /// changes trie. ChangesTrieRoot(Hash), } impl RawLog { /// Try to cast the log entry as ChangesTrieRoot log entry. pub fn as_changes_trie_root(&self) -> Option<&Hash> { match *self { RawLog::ChangesTrieRoot(ref item) => Some(item), } } } // Implementation for tests outside of this crate. #[cfg(any(feature = "std", test))] impl From> for primitives::testing::DigestItem { fn from(log: RawLog) -> primitives::testing::DigestItem { match log { RawLog::ChangesTrieRoot(root) => primitives::generic::DigestItem::ChangesTrieRoot(root), } } } // Create a Hash with 69 for each byte, // only used to build genesis config. #[cfg(feature = "std")] fn hash69 + Default>() -> T { let mut h = T::default(); h.as_mut().iter_mut().for_each(|byte| *byte = 69); h } decl_storage! { trait Store for Module as System { /// Extrinsics nonce for accounts. pub AccountNonce get(account_nonce): map T::AccountId => T::Index; /// Total extrinsics count for the current block. ExtrinsicCount: Option; /// Total length in bytes for all extrinsics put together, for the current block. AllExtrinsicsLen: Option; /// Map of block numbers to block hashes. pub BlockHash get(block_hash) build(|_| vec![(T::BlockNumber::zero(), hash69())]): map T::BlockNumber => T::Hash; /// Extrinsics data for the current block (maps extrinsic's index to its data). ExtrinsicData get(extrinsic_data): map u32 => Vec; /// Random seed of the current block. RandomSeed get(random_seed) build(|_| T::Hash::default()): T::Hash; /// The current block number being processed. Set by `execute_block`. Number get(block_number) build(|_| T::BlockNumber::sa(1u64)): T::BlockNumber; /// Hash of the previous block. ParentHash get(parent_hash) build(|_| hash69()): T::Hash; /// Extrinsics root of the current block, also part of the block header. ExtrinsicsRoot get(extrinsics_root): T::Hash; /// Digest of the current block, also part of the block header. Digest get(digest): T::Digest; /// Events deposited for the current block. Events get(events): Vec>; } add_extra_genesis { config(changes_trie_config): Option; build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig| { use parity_codec::Encode; storage.insert(well_known_keys::EXTRINSIC_INDEX.to_vec(), 0u32.encode()); if let Some(ref changes_trie_config) = config.changes_trie_config { storage.insert( well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), changes_trie_config.encode()); } }); } } 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 { /// Gets the index of extrinsic that is currenty executing. pub fn extrinsic_index() -> Option { storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX) } /// Gets extrinsics count. pub fn extrinsic_count() -> u32 { >::get().unwrap_or_default() } /// Gets a total length of all executed extrinsics. pub fn all_extrinsics_len() -> u32 { >::get().unwrap_or_default() } /// Start the execution of a particular block. pub fn initialize(number: &T::BlockNumber, parent_hash: &T::Hash, txs_root: &T::Hash) { // populate environment. storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32); >::put(number); >::put(parent_hash); >::insert(*number - One::one(), parent_hash); >::put(txs_root); >::put(Self::calculate_random()); >::kill(); } /// Remove temporary "environment" entries in storage. pub fn finalize() -> T::Header { >::kill(); >::kill(); >::kill(); let number = >::take(); let parent_hash = >::take(); let mut digest = >::take(); let extrinsics_root = >::take(); let storage_root = T::Hashing::storage_root(); let storage_changes_root = T::Hashing::storage_changes_root(parent_hash, number.as_() - 1); // we can't compute changes trie root earlier && put it to the Digest // because it will include all currently existing temporaries if let Some(storage_changes_root) = storage_changes_root { let item = RawLog::ChangesTrieRoot(storage_changes_root); let item = ::Log::from(item).into(); digest.push(item); } // > 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); } /// 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 { TestExternalities::new(map![ twox_128(&>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), twox_128(>::key()).to_vec() => T::BlockNumber::one().encode(), twox_128(>::key()).to_vec() => [69u8; 32].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 /// `initialize` 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); } /// Sets the index of extrinsic that is currenty executing. #[cfg(any(feature = "std", test))] pub fn set_extrinsic_index(extrinsic_index: u32) { storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &extrinsic_index) } /// Set the parent hash number to something in particular. Can be used as an alternative to /// `initialize` 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 /// `initialize` 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. /// /// NOTE this function is called only when the block is being constructed locally. /// `execute_block` doesn't note any extrinsics. pub fn note_extrinsic(encoded_xt: Vec) { >::insert(Self::extrinsic_index().unwrap_or_default(), encoded_xt); } /// To be called immediately after an extrinsic has been applied. pub fn note_applied_extrinsic(r: &Result<(), &'static str>, encoded_len: u32) { Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess, Err(_) => Event::ExtrinsicFailed, }.into()); let next_extrinsic_index = Self::extrinsic_index().unwrap_or_default() + 1u32; let total_length = encoded_len.saturating_add(Self::all_extrinsics_len()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &next_extrinsic_index); >::put(&total_length); } /// To be called immediately after `note_applied_extrinsic` of the last extrinsic of the block /// has been called. pub fn note_finished_extrinsics() { let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap_or_default(); >::put(extrinsic_index); } /// 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); } } pub struct ChainContext(::rstd::marker::PhantomData); impl Default for ChainContext { fn default() -> Self { ChainContext(::rstd::marker::PhantomData) } } impl Lookup for ChainContext { type Source = ::Source; type Target = ::Target; fn lookup(&self, s: Self::Source) -> rstd::result::Result { ::lookup(s) } } impl CurrentHeight for ChainContext { type BlockNumber = T::BlockNumber; fn current_height(&self) -> Self::BlockNumber { >::block_number() } } impl BlockNumberToHash for ChainContext { type BlockNumber = T::BlockNumber; type Hash = T::Hash; fn block_number_to_hash(&self, n: Self::BlockNumber) -> Option { Some(>::block_hash(n)) } } #[cfg(test)] mod tests { use super::*; use runtime_io::with_externalities; use substrate_primitives::H256; use primitives::BuildStorage; use primitives::traits::{BlakeTwo256, IdentityLookup}; use primitives::testing::{Digest, DigestItem, Header}; use srml_support::impl_outer_origin; 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 Lookup = IdentityLookup; type Header = Header; type Event = u16; type Log = DigestItem; } 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().0.into() } #[test] fn deposit_event_should_work() { with_externalities(&mut new_test_ext(), || { System::initialize(&1, &[0u8; 32].into(), &[0u8; 32].into()); System::note_finished_extrinsics(); System::deposit_event(1u16); System::finalize(); assert_eq!(System::events(), vec![EventRecord { phase: Phase::Finalization, event: 1u16 }]); System::initialize(&2, &[0u8; 32].into(), &[0u8; 32].into()); System::deposit_event(42u16); System::note_applied_extrinsic(&Ok(()), 0); System::note_applied_extrinsic(&Err(""), 0); System::note_finished_extrinsics(); System::deposit_event(3u16); System::finalize(); 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 } ]); }); } }