// Copyright 2017-2018 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 . //! The Example: A simple example of a runtime module demonstrating //! concepts, APIs and structures common to most runtime modules. // Ensure we're `no_std` when compiling for Wasm. #![cfg_attr(not(feature = "std"), no_std)] // Assert macros used in tests. extern crate sr_std; // Needed for tests (`with_externalities`). #[cfg(test)] extern crate sr_io; // Needed for the set of mock primitives used in our tests. #[cfg(test)] extern crate substrate_primitives; // Needed for various traits. In our case, `OnFinalise`. extern crate sr_primitives; // Needed for deriving `Encode` and `Decode` for `RawEvent`. #[macro_use] extern crate parity_codec_derive; extern crate parity_codec as codec; // Needed for type-safe access to storage DB. #[macro_use] extern crate srml_support as support; // `system` module provides us with all sorts of useful stuff and macros // depend on it being around. extern crate srml_system as system; // `balances` module is needed for our little example. It's not required in // general (though if you want your module to be able to work with tokens, then you // might find it useful). extern crate srml_balances as balances; use support::{StorageValue, dispatch::Result}; use system::ensure_signed; /// Our module's configuration trait. All our types and consts go in here. If the /// module is dependent on specific other modules, then their configuration traits /// should be added to our implied traits list. /// /// `system::Trait` should always be included in our implied traits. pub trait Trait: balances::Trait { /// The overarching event type. type Event: From> + Into<::Event>; } // The module declaration. This states the entry points that we handle. The // macro takes care of the marshalling of arguments and dispatch. // // Anyone can have these functions execute by signing and submitting // an extrinsic. Ensure that calls into each of these execute in a time, memory and // using storage space proportional to any costs paid for by the caller or otherwise the // difficulty of forcing the call to happen. // // Generally you'll want to split these into three groups: // - Public calls that are signed by an external account. // - Root calls that are allowed to be made only by the governance system. // - Inherent calls that are allowed to be made only by the block authors and validators. // // Information about where this dispatch initiated from is provided as the first argument // "origin". As such functions must always look like: // // `fn foo(origin, bar: Bar, baz: Baz) -> Result;` // // The `Result` is required as part of the syntax (and expands to the conventional dispatch // result of `Result<(), &'static str>`). // // When you come to `impl` them later in the module, you must specify the full type for `origin`: // // `fn foo(origin: T::Origin, bar: Bar, baz: Baz) { ... }` // // There are three entries in the `system::Origin` enum that correspond // to the above bullets: `::Signed(AccountId)`, `::Root` and `::Inherent`. You should always match // against them as the first thing you do in your function. There are three convenience calls // in system that do the matching for you and return a convenient result: `ensure_signed`, // `ensure_root` and `ensure_inherent`. decl_module! { // Simple declaration of the `Module` type. Lets the macro know what its working on. pub struct Module for enum Call where origin: T::Origin { /// Deposit one of this module's events by using the default implementation. /// It is also possible to provide a custom implementation. fn deposit_event() = default; /// This is your public interface. Be extremely careful. /// This is just a simple example of how to interact with the module from the external /// world. // This just increases the value of `Dummy` by `increase_by`. // // Since this is a dispatched function there are two extremely important things to // remember: // // - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an // irreparably damaged state) must this function panic. // - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return // `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`. // // The first is relatively easy to audit for - just ensure all panickers are removed from // logic that executes in production (which you do anyway, right?!). To ensure the second // is followed, you should do all tests for validity at the top of your function. This // is stuff like checking the sender (`origin`) or that state is such that the operation // makes sense. // // Once you've determined that it's all good, then enact the operation and change storage. // If you can't be certain that the operation will succeed without substantial computation // then you have a classic blockchain attack scenario. The normal way of managing this is // to attach a bond to the operation. As the first major alteration of storage, reserve // some value from the sender's account (`Balances` module has a `reserve` function for // exactly this scenario). This amount should be enough to cover any costs of the // substantial execution in case it turns out that you can't proceed with the operation. // // If it eventually transpires that the operation is fine and, therefore, that the // expense of the checks should be borne by the network, then you can refund the reserved // deposit. If, however, the operation turns out to be invalid and the computation is // wasted, then you can burn it or repatriate elsewhere. // // Security bonds ensure that attackers can't game it by ensuring that anyone interacting // with the system either progresses it or pays for the trouble of faffing around with // no progress. // // If you don't respect these rules, it is likely that your chain will be attackable. fn accumulate_dummy(origin, increase_by: T::Balance) -> Result { // This is a public call, so we ensure that the origin is some signed account. let _sender = ensure_signed(origin)?; // Read the value of dummy from storage. // let dummy = Self::dummy(); // Will also work using the `::get` on the storage item type itself: // let dummy = >::get(); // Calculate the new value. // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); // Put the new value into storage. // >::put(new_dummy); // Will also work with a reference: // >::put(&new_dummy); // Here's the new one of read and then modify the value. >::mutate(|dummy| { let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by); *dummy = Some(new_dummy); }); // Let's deposit an event to let the outside world know this happened. Self::deposit_event(RawEvent::Dummy(increase_by)); // All good. Ok(()) } /// A privileged call; in this case it resets our dummy value to something new. // Implementation of a privileged call. This doesn't have an `origin` parameter because // it's not (directly) from an extrinsic, but rather the system as a whole has decided // to execute it. Different runtimes have different reasons for allow privileged // calls to be executed - we don't need to care why. Because it's privileged, we can // assume it's a one-off operation and substantial processing/storage/memory can be used // without worrying about gameability or attack scenarios. fn set_dummy(new_value: T::Balance) -> Result { // Put the new value into storage. >::put(new_value); // All good. Ok(()) } // The signature could also look like: `fn on_finalise()` fn on_finalise(_n: T::BlockNumber) { // Anything that needs to be done at the end of the block. // We just kill our dummy storage item. >::kill(); } } } /// An event in this module. Events are simple means of reporting specific conditions and /// circumstances that have happened that users, Dapps and/or chain explorers would find /// interesting and otherwise difficult to detect. decl_event!( pub enum Event where B = ::Balance { // Just a normal `enum`, here's a dummy event to ensure it compiles. /// Dummy event, just here so there's a generic type that's used. Dummy(B), } ); decl_storage! { // A macro for the Storage trait, and its implementation, for this module. // This allows for type-safe usage of the Substrate storage database, so you can // keep things around between blocks. trait Store for Module as Example { // Any storage declarations of the form: // `pub? Name get(getter_name)? [config()|config(myname)] [build(|_| {...})] : (= )?;` // where `` is either: // - `Type` (a basic value item); or // - `map KeyType => ValueType` (a map item). // // Note that there are two optional modifiers for the storage type declaration. // - `Foo: Option`: // - `Foo::put(1); Foo::get()` returns `Some(1)`; // - `Foo::kill(); Foo::get()` returns `None`. // - `Foo: u32`: // - `Foo::put(1); Foo::get()` returns `1`; // - `Foo::kill(); Foo::get()` returns `0` (u32::default()). // e.g. Foo: u32; // e.g. pub Bar get(bar): map T::AccountId => Vec<(T::Balance, u64)>; // // For basic value items, you'll get a type which implements // `support::StorageValue`. For map items, you'll get a type which // implements `support::StorageMap`. // // If they have a getter (`get(getter_name)`), then your module will come // equipped with `fn getter_name() -> Type` for basic value items or // `fn getter_name(key: KeyType) -> ValueType` for map items. Dummy get(dummy) config(): Option; // this one uses the default, we'll demonstrate the usage of 'mutate' API. Foo get(foo) config(): T::Balance; } } // The main implementation block for the module. Functions here fall into three broad // categories: // - Public interface. These are functions that are `pub` and generally fall into inspector // functions that do not write to storage and operation functions that do. // - Private functions. These are your usual private utilities unavailable to other modules. impl Module { // Add public immutables and private mutables. #[allow(dead_code)] fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> Result { let _sender = ensure_signed(origin)?; let prev = >::get(); // Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an Option<> type. let result = >::mutate(|foo| { *foo = *foo + increase_by; *foo }); assert!(prev + increase_by == result); Ok(()) } } #[cfg(test)] mod tests { use super::*; use sr_io::with_externalities; use substrate_primitives::{H256, Blake2Hasher}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried. use sr_primitives::{ BuildStorage, traits::{BlakeTwo256, OnFinalise}, testing::{Digest, DigestItem, Header} }; impl_outer_origin! { pub enum Origin for Test {} } // For testing the module, we construct most of a mock runtime. This means // first constructing a configuration type (`Test`) which `impl`s each of the // configuration traits of modules we want to use. #[derive(Clone, Eq, PartialEq)] pub struct Test; impl system::Trait for Test { type 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 = (); type Log = DigestItem; } impl balances::Trait for Test { type Balance = u64; type AccountIndex = u64; type OnFreeBalanceZero = (); type EnsureAccountLiquid = (); type Event = (); } impl Trait for Test { type Event = (); } type Example = Module; // This function basically just builds a genesis storage key/value store according to // our desired mockup. fn new_test_ext() -> sr_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap().0; // We use default for brevity, but you can configure as desired if needed. t.extend(balances::GenesisConfig::::default().build_storage().unwrap().0); t.extend(GenesisConfig::{ dummy: 42, foo: 24, }.build_storage().unwrap().0); t.into() } #[test] fn it_works_for_optional_value() { with_externalities(&mut new_test_ext(), || { // Check that GenesisBuilder works properly. assert_eq!(Example::dummy(), Some(42)); // Check that accumulate works when we have Some value in Dummy already. assert_ok!(Example::accumulate_dummy(Origin::signed(1), 27)); assert_eq!(Example::dummy(), Some(69)); // Check that finalising the block removes Dummy from storage. >::on_finalise(1); assert_eq!(Example::dummy(), None); // Check that accumulate works when we Dummy has None in it. assert_ok!(Example::accumulate_dummy(Origin::signed(1), 42)); assert_eq!(Example::dummy(), Some(42)); }); } #[test] fn it_works_for_default_value() { with_externalities(&mut new_test_ext(), || { assert_eq!(Example::foo(), 24); assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); assert_eq!(Example::foo(), 25); }); } }