// 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 . //! Support code for the runtime. #![cfg_attr(not(feature = "std"), no_std)] /// Export ourself as `srml_support` to make tests happy. extern crate self as srml_support; #[macro_use] extern crate bitmask; #[cfg(feature = "std")] pub use serde; #[doc(hidden)] pub use rstd; #[doc(hidden)] pub use codec; #[cfg(feature = "std")] #[doc(hidden)] pub use once_cell; #[doc(hidden)] pub use paste; #[cfg(feature = "std")] #[doc(hidden)] pub use runtime_io::with_storage; pub use self::storage::hashed::{Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat}; #[macro_use] pub mod dispatch; #[macro_use] pub mod storage; mod hashable; #[macro_use] pub mod event; #[macro_use] mod origin; #[macro_use] pub mod metadata; #[macro_use] mod runtime; #[macro_use] pub mod inherent; #[macro_use] pub mod unsigned; mod double_map; pub mod traits; pub use self::storage::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::double_map::StorageDoubleMapWithHasher; pub use runtime_io::{print, storage_root}; pub use sr_primitives::{self, ConsensusEngineId}; /// Macro for easily creating a new implementation of the `Get` trait. Use similarly to /// how you would declare a `const`: /// /// ```no_compile /// parameter_types! { /// pub const Argument: u64 = 42; /// } /// trait Config { /// type Parameter: Get; /// } /// struct Runtime; /// impl Config for Runtime { /// type Parameter = Argument; /// } /// ``` #[macro_export] macro_rules! parameter_types { ( $( #[ $attr:meta ] )* $vis:vis const $name:ident: $type:ty = $value:expr; $( $rest:tt )* ) => ( $( #[ $attr ] )* $vis struct $name; $crate::parameter_types!{IMPL $name , $type , $value} $crate::parameter_types!{ $( $rest )* } ); () => (); (IMPL $name:ident , $type:ty , $value:expr) => { impl $name { pub fn get() -> $type { $value } } impl> $crate::traits::Get for $name { fn get() -> I { I::from($value) } } } } #[doc(inline)] pub use srml_support_procedural::decl_storage; /// Return Err of the expression: `return Err($expression);`. /// /// Used as `fail!(expression)`. #[macro_export] macro_rules! fail { ( $y:expr ) => {{ return Err($y); }} } /// Evaluate `$x:expr` and if not true return `Err($y:expr)`. /// /// Used as `ensure!(expression_to_ensure, expression_to_return_on_false)`. #[macro_export] macro_rules! ensure { ( $x:expr, $y:expr ) => {{ if !$x { $crate::fail!($y); } }} } /// Evaluate an expression, assert it returns an expected `Err` value and that /// runtime storage has not been mutated (i.e. expression is a no-operation). /// /// Used as `assert_noop(expression_to_assert, expected_error_expression)`. #[macro_export] #[cfg(feature = "std")] macro_rules! assert_noop { ( $x:expr , $y:expr ) => { let h = $crate::storage_root(); $crate::assert_err!($x, $y); assert_eq!(h, $crate::storage_root()); } } /// Panic if an expression doesn't evaluate to an `Err`. /// /// Used as `assert_err!(expression_to_assert, expected_err_expression)`. /// Assert an expression returns an error specified. /// /// Used as `assert_err!(expression_to_assert, expected_error_expression)` #[macro_export] #[cfg(feature = "std")] macro_rules! assert_err { ( $x:expr , $y:expr ) => { assert_eq!($x, Err($y)); } } /// Panic if an expression doesn't evaluate to `Ok`. /// /// Used as `assert_ok!(expression_to_assert, expected_ok_expression)`, /// or `assert_ok!(expression_to_assert)` which would assert against `Ok(())`. #[macro_export] #[cfg(feature = "std")] macro_rules! assert_ok { ( $x:expr ) => { assert_eq!($x, Ok(())); }; ( $x:expr, $y:expr ) => { assert_eq!($x, Ok($y)); } } /// Panic when the vectors are different, without taking the order into account. /// /// # Examples /// /// ```rust /// #[macro_use] /// # extern crate srml_support; /// # use srml_support::{assert_eq_uvec}; /// # fn main() { /// assert_eq_uvec!(vec![1,2], vec![2,1]); /// # } /// ``` /// /// ```rust,should_panic /// #[macro_use] /// # extern crate srml_support; /// # use srml_support::{assert_eq_uvec}; /// # fn main() { /// assert_eq_uvec!(vec![1,2,3], vec![2,1]); /// # } /// ``` #[macro_export] #[cfg(feature = "std")] macro_rules! assert_eq_uvec { ( $x:expr, $y:expr ) => { $crate::__assert_eq_uvec!($x, $y); $crate::__assert_eq_uvec!($y, $x); } } #[macro_export] #[doc(hidden)] #[cfg(feature = "std")] macro_rules! __assert_eq_uvec { ( $x:expr, $y:expr ) => { $x.iter().for_each(|e| { if !$y.contains(e) { panic!(format!("vectors not equal: {:?} != {:?}", $x, $y)); } }); } } /// Checks that `$x` is equal to `$y` with an error rate of `$error`. /// /// # Example /// /// ```rust /// # fn main() { /// srml_support::assert_eq_error_rate!(10, 10, 0); /// srml_support::assert_eq_error_rate!(10, 11, 1); /// srml_support::assert_eq_error_rate!(12, 10, 2); /// # } /// ``` /// /// ```rust,should_panic /// # fn main() { /// srml_support::assert_eq_error_rate!(12, 10, 1); /// # } /// ``` #[macro_export] #[cfg(feature = "std")] macro_rules! assert_eq_error_rate { ($x:expr, $y:expr, $error:expr) => { assert!( ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)), "{:?} != {:?} (with error rate {:?})", $x, $y, $error, ); }; } /// The void type - it cannot exist. // Oh rust, you crack me up... #[derive(Clone, Eq, PartialEq)] #[cfg_attr(feature = "std", derive(Debug))] pub enum Void {} #[cfg(feature = "std")] #[doc(hidden)] pub use serde::{Serialize, Deserialize}; /// Programatically create derivations for tuples of up to 19 elements. You provide a second macro /// which is called once per tuple size, along with a number of identifiers, one for each element /// of the tuple. #[macro_export] macro_rules! for_each_tuple { ($m:ident) => { for_each_tuple! { @IMPL $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, } }; (@IMPL $m:ident !!) => { $m! { } }; (@IMPL $m:ident !! $h:ident, $($t:ident,)*) => { $m! { $h $($t)* } for_each_tuple! { @IMPL $m !! $($t,)* } } } #[cfg(test)] mod tests { use super::*; use codec::Codec; use runtime_io::{with_externalities, Blake2Hasher}; pub use srml_metadata::{ DecodeDifferent, StorageEntryMetadata, StorageMetadata, StorageEntryType, StorageEntryModifier, DefaultByte, DefaultByteGetter, StorageHasher }; pub use rstd::marker::PhantomData; pub trait Trait { type BlockNumber: Codec + Default; type Origin; } mod module { #![allow(dead_code)] use super::Trait; decl_module! { pub struct Module for enum Call where origin: T::Origin {} } } use self::module::Module; decl_storage! { trait Store for Module as Example { pub Data get(data) build(|_| vec![(15u32, 42u64)]): linked_map hasher(twox_64_concat) u32 => u64; pub OptionLinkedMap: linked_map u32 => Option; pub GenericData get(generic_data): linked_map hasher(twox_128) T::BlockNumber => T::BlockNumber; pub GenericData2 get(generic_data2): linked_map T::BlockNumber => Option; pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): double_map hasher(twox_64_concat) u32, blake2_256(u32) => u64; pub GenericDataDM: double_map T::BlockNumber, twox_128(T::BlockNumber) => T::BlockNumber; pub GenericData2DM: double_map T::BlockNumber, twox_256(T::BlockNumber) => Option; pub AppendableDM: double_map u32, blake2_256(T::BlockNumber) => Vec; } } struct Test; impl Trait for Test { type BlockNumber = u32; type Origin = u32; } fn new_test_ext() -> runtime_io::TestExternalities { GenesisConfig::default().build_storage().unwrap().into() } type Map = Data; #[test] fn linked_map_issue_3318() { with_externalities(&mut new_test_ext(), || { OptionLinkedMap::insert(1, 1); assert_eq!(OptionLinkedMap::get(1), Some(1)); OptionLinkedMap::insert(1, 2); assert_eq!(OptionLinkedMap::get(1), Some(2)); }); } #[test] fn linked_map_swap_works() { with_externalities(&mut new_test_ext(), || { OptionLinkedMap::insert(0, 0); OptionLinkedMap::insert(1, 1); OptionLinkedMap::insert(2, 2); OptionLinkedMap::insert(3, 3); let collect = || OptionLinkedMap::enumerate().collect::>(); assert_eq!(collect(), vec![(3, 3), (2, 2), (1, 1), (0, 0)]); // Two existing OptionLinkedMap::swap(1, 2); assert_eq!(collect(), vec![(3, 3), (2, 1), (1, 2), (0, 0)]); // Back to normal OptionLinkedMap::swap(2, 1); assert_eq!(collect(), vec![(3, 3), (2, 2), (1, 1), (0, 0)]); // Left existing OptionLinkedMap::swap(2, 5); assert_eq!(collect(), vec![(5, 2), (3, 3), (1, 1), (0, 0)]); // Right existing OptionLinkedMap::swap(5, 2); assert_eq!(collect(), vec![(2, 2), (3, 3), (1, 1), (0, 0)]); }); } #[test] fn linked_map_basic_insert_remove_should_work() { with_externalities(&mut new_test_ext(), || { // initialized during genesis assert_eq!(Map::get(&15u32), 42u64); // get / insert / take let key = 17u32; assert_eq!(Map::get(&key), 0u64); Map::insert(key, 4u64); assert_eq!(Map::get(&key), 4u64); assert_eq!(Map::take(&key), 4u64); assert_eq!(Map::get(&key), 0u64); // mutate Map::mutate(&key, |val| { *val = 15; }); assert_eq!(Map::get(&key), 15u64); // remove Map::remove(&key); assert_eq!(Map::get(&key), 0u64); }); } #[test] fn linked_map_enumeration_and_head_should_work() { with_externalities(&mut new_test_ext(), || { assert_eq!(Map::head(), Some(15)); assert_eq!(Map::enumerate().collect::>(), vec![(15, 42)]); // insert / remove let key = 17u32; Map::insert(key, 4u64); assert_eq!(Map::head(), Some(key)); assert_eq!(Map::enumerate().collect::>(), vec![(key, 4), (15, 42)]); assert_eq!(Map::take(&15), 42u64); assert_eq!(Map::take(&key), 4u64); assert_eq!(Map::head(), None); assert_eq!(Map::enumerate().collect::>(), vec![]); // Add couple of more elements Map::insert(key, 42u64); assert_eq!(Map::head(), Some(key)); assert_eq!(Map::enumerate().collect::>(), vec![(key, 42)]); Map::insert(key + 1, 43u64); assert_eq!(Map::head(), Some(key + 1)); assert_eq!(Map::enumerate().collect::>(), vec![(key + 1, 43), (key, 42)]); // mutate let key = key + 2; Map::mutate(&key, |val| { *val = 15; }); assert_eq!(Map::enumerate().collect::>(), vec![(key, 15), (key - 1, 43), (key - 2, 42)]); assert_eq!(Map::head(), Some(key)); Map::mutate(&key, |val| { *val = 17; }); assert_eq!(Map::enumerate().collect::>(), vec![(key, 17), (key - 1, 43), (key - 2, 42)]); // remove first Map::remove(&key); assert_eq!(Map::head(), Some(key - 1)); assert_eq!(Map::enumerate().collect::>(), vec![(key - 1, 43), (key - 2, 42)]); // remove last from the list Map::remove(&(key - 2)); assert_eq!(Map::head(), Some(key - 1)); assert_eq!(Map::enumerate().collect::>(), vec![(key - 1, 43)]); // remove the last element Map::remove(&(key - 1)); assert_eq!(Map::head(), None); assert_eq!(Map::enumerate().collect::>(), vec![]); }); } #[test] fn double_map_basic_insert_remove_remove_prefix_should_work() { with_externalities(&mut new_test_ext(), || { type DoubleMap = DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); // get / insert / take let key1 = 17u32; let key2 = 18u32; assert_eq!(DoubleMap::get(&key1, &key2), 0u64); DoubleMap::insert(&key1, &key2, &4u64); assert_eq!(DoubleMap::get(&key1, &key2), 4u64); assert_eq!(DoubleMap::take(&key1, &key2), 4u64); assert_eq!(DoubleMap::get(&key1, &key2), 0u64); // mutate DoubleMap::mutate(&key1, &key2, |val| { *val = 15; }); assert_eq!(DoubleMap::get(&key1, &key2), 15u64); // remove DoubleMap::remove(&key1, &key2); assert_eq!(DoubleMap::get(&key1, &key2), 0u64); // remove prefix DoubleMap::insert(&key1, &key2, &4u64); DoubleMap::insert(&key1, &(key2 + 1), &4u64); DoubleMap::insert(&(key1 + 1), &key2, &4u64); DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64); DoubleMap::remove_prefix(&key1); assert_eq!(DoubleMap::get(&key1, &key2), 0u64); assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64); assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64); assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64); }); } #[test] fn double_map_append_should_work() { with_externalities(&mut new_test_ext(), || { type DoubleMap = AppendableDM; let key1 = 17u32; let key2 = 18u32; DoubleMap::insert(&key1, &key2, &vec![1]); DoubleMap::append(&key1, &key2, &[2, 3]).unwrap(); assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2, 3]); }); } const EXPECTED_METADATA: StorageMetadata = StorageMetadata { prefix: DecodeDifferent::Encode("Example"), entries: DecodeDifferent::Encode( &[ StorageEntryMetadata { name: DecodeDifferent::Encode("Data"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map{ hasher: StorageHasher::Twox64Concat, key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructData(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("OptionLinkedMap"), modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { hasher: StorageHasher::Blake2_256, key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u32"), is_linked: true, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructOptionLinkedMap(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("GenericData"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::Map{ hasher: StorageHasher::Twox128, key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGenericData(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("GenericData2"), modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map{ hasher: StorageHasher::Blake2_256, key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGenericData2(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("DataDM"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::DoubleMap{ hasher: StorageHasher::Twox64Concat, key1: DecodeDifferent::Encode("u32"), key2: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), key2_hasher: StorageHasher::Blake2_256, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructDataDM(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("GenericDataDM"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::DoubleMap{ hasher: StorageHasher::Blake2_256, key1: DecodeDifferent::Encode("T::BlockNumber"), key2: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), key2_hasher: StorageHasher::Twox128, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGenericDataDM(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("GenericData2DM"), modifier: StorageEntryModifier::Optional, ty: StorageEntryType::DoubleMap{ hasher: StorageHasher::Blake2_256, key1: DecodeDifferent::Encode("T::BlockNumber"), key2: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), key2_hasher: StorageHasher::Twox256, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, StorageEntryMetadata { name: DecodeDifferent::Encode("AppendableDM"), modifier: StorageEntryModifier::Default, ty: StorageEntryType::DoubleMap{ hasher: StorageHasher::Blake2_256, key1: DecodeDifferent::Encode("u32"), key2: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("Vec"), key2_hasher: StorageHasher::Blake2_256, }, default: DecodeDifferent::Encode( DefaultByteGetter(&__GetByteStructGenericData2DM(PhantomData::)) ), documentation: DecodeDifferent::Encode(&[]), }, ] ), }; #[test] fn store_metadata() { let metadata = Module::::storage_metadata(); pretty_assertions::assert_eq!(EXPECTED_METADATA, metadata); } }