Newer
Older
Guanqun Lu
committed
// This file is part of Substrate.
// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]
/// Export ourself as `frame_support` to make tests happy.
extern crate self as frame_support;
#[doc(hidden)]
pub use frame_metadata as metadata;
#[doc(hidden)]
pub use log;
#[cfg(feature = "std")]
#[doc(hidden)]
pub use once_cell;
#[doc(hidden)]
pub use paste;
#[doc(hidden)]
pub use scale_info;
pub use serde;
pub use sp_core::Void;
pub use sp_core_hashing_proc_macro;
#[doc(hidden)]
pub use sp_io::{self, storage::root as storage_root};
pub use sp_runtime::{RuntimeDebug, StateVersion};
#[doc(hidden)]
pub use sp_state_machine::BasicExternalities;
#[doc(hidden)]
pub use tt_call::*;
pub mod event;
pub mod migrations;
pub mod weights;
#[doc(hidden)]
pub mod unsigned {
#[doc(hidden)]
pub use crate::sp_runtime::traits::ValidateUnsigned;
#[doc(hidden)]
pub use crate::sp_runtime::transaction_validity::{
TransactionSource, TransactionValidity, TransactionValidityError, UnknownTransaction,
pub use self::{
dispatch::{Callable, Parameter},
hash::{
Blake2_128, Blake2_128Concat, Blake2_256, Hashable, Identity, ReversibleStorageHasher,
StorageHasher, Twox128, Twox256, Twox64Concat,
},
storage::{
bounded_vec::{BoundedSlice, BoundedVec},
migration,
weak_bounded_vec::WeakBoundedVec,
IterableStorageDoubleMap, IterableStorageMap, IterableStorageNMap, StorageDoubleMap,
StorageMap, StorageNMap, StoragePrefixedMap, StorageValue,
},
pub use sp_runtime::{self, print, traits::Printable, ConsensusEngineId};
use codec::{Decode, Encode};
use sp_runtime::TypeId;
/// A unified log target for support operations.
pub const LOG_TARGET: &'static str = "runtime::frame-support";
/// A type that cannot be instantiated.
#[derive(Debug, PartialEq, Eq, Clone, TypeInfo)]
pub enum Never {}
/// A pallet identifier. These are per pallet and should be stored in a registry somewhere.
#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode, TypeInfo)]
pub struct PalletId(pub [u8; 8]);
impl TypeId for PalletId {
const TYPE_ID: [u8; 4] = *b"modl";
}
/// Generate a new type alias for [`storage::types::StorageValue`],
/// [`storage::types::StorageMap`], [`storage::types::StorageDoubleMap`]
/// and [`storage::types::StorageNMap`].
///
/// Useful for creating a *storage-like* struct for test and migrations.
///
/// # use frame_support::generate_storage_alias;
/// use frame_support::codec;
/// use frame_support::Twox64Concat;
/// // generate a storage value with type u32.
/// generate_storage_alias!(Prefix, StorageName => Value<u32>);
///
/// // generate a double map from `(u32, u32)` (with hashers `Twox64Concat` for each key)
/// generate_storage_alias!(
/// OtherPrefix, OtherStorageName => DoubleMap<
/// (u32, Twox64Concat),
/// (u32, Twox64Concat),
/// // optionally specify the query type
/// use frame_support::pallet_prelude::{ValueQuery, OptionQuery};
/// generate_storage_alias!(Prefix, ValueName => Value<u32, OptionQuery>);
/// generate_storage_alias!(
/// Prefix, SomeStorageName => DoubleMap<
/// (u32, Twox64Concat),
/// (u32, Twox64Concat),
/// Vec<u8>,
/// ValueQuery
/// >
/// );
///
/// // generate a map from `Config::AccountId` (with hasher `Twox64Concat`) to `Vec<u8>`
/// trait Config { type AccountId: codec::FullCodec; }
/// generate_storage_alias!(
/// Prefix, GenericStorage<T: Config> => Map<(T::AccountId, Twox64Concat), Vec<u8>>
/// );
/// # fn main() {}
#[macro_export]
macro_rules! generate_storage_alias {
// without generic for $name.
($pallet:ident, $name:ident => Map<($key:ty, $hasher:ty), $value:ty $(, $querytype:ty)?>) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
type $name = $crate::storage::types::StorageMap<
[<$name Instance>],
$hasher,
$key,
$value,
(
$pallet:ident,
$name:ident
=> DoubleMap<($key1:ty, $hasher1:ty), ($key2:ty, $hasher2:ty), $value:ty $(, $querytype:ty)?>
) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
type $name = $crate::storage::types::StorageDoubleMap<
[<$name Instance>],
$hasher1,
$key1,
$hasher2,
$key2,
$value,
(
$pallet:ident,
$name:ident
=> NMap<Key<$(($key:ty, $hasher:ty)),+>, $value:ty $(, $querytype:ty)?>
) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
type $name = $crate::storage::types::StorageNMap<
[<$name Instance>],
(
$( $crate::storage::types::Key<$hasher, $key>, )+
),
$value,
($pallet:ident, $name:ident => Value<$value:ty $(, $querytype:ty)?>) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
type $name = $crate::storage::types::StorageValue<
[<$name Instance>],
$value,
>;
}
};
// with generic for $name.
(
$pallet:ident,
$name:ident<$t:ident : $bounds:tt>
=> Map<($key:ty, $hasher:ty), $value:ty $(, $querytype:ty)?>
) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
#[allow(type_alias_bounds)]
type $name<$t : $bounds> = $crate::storage::types::StorageMap<
[<$name Instance>],
$key,
$hasher,
$value,
>;
}
};
(
$pallet:ident,
$name:ident<$t:ident : $bounds:tt>
=> DoubleMap<($key1:ty, $hasher1:ty), ($key2:ty, $hasher2:ty), $value:ty $(, $querytype:ty)?>
) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
#[allow(type_alias_bounds)]
type $name<$t : $bounds> = $crate::storage::types::StorageDoubleMap<
[<$name Instance>],
$key1,
$hasher1,
$key2,
$hasher2,
$value,
$name:ident<$t:ident : $bounds:tt>
=> NMap<$(($key:ty, $hasher:ty),)+ $value:ty $(, $querytype:ty)?>
) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
#[allow(type_alias_bounds)]
type $name<$t : $bounds> = $crate::storage::types::StorageNMap<
[<$name Instance>],
(
$( $crate::storage::types::Key<$hasher, $key>, )+
),
$value,
($pallet:ident, $name:ident<$t:ident : $bounds:tt> => Value<$value:ty $(, $querytype:ty)?>) => {
$crate::paste::paste! {
$crate::generate_storage_alias!(@GENERATE_INSTANCE_STRUCT $pallet, $name);
#[allow(type_alias_bounds)]
type $name<$t : $bounds> = $crate::storage::types::StorageValue<
[<$name Instance>],
$value,
>;
}
};
// helper used in all arms.
(@GENERATE_INSTANCE_STRUCT $pallet:ident, $name:ident) => {
$crate::paste::paste! {
struct [<$name Instance>];
impl $crate::traits::StorageInstance for [<$name Instance>] {
fn pallet_prefix() -> &'static str { stringify!($pallet) }
const STORAGE_PREFIX: &'static str = stringify!($name);
}
}
/// Create new implementations of the [`Get`](crate::traits::Get) trait.
///
/// The so-called parameter type can be created in four different ways:
/// - Using `const` to create a parameter type that provides a `const` getter. It is required that
/// the `value` is const.
///
/// - Declare the parameter type without `const` to have more freedom when creating the value.
///
/// - Using `storage` to create a storage parameter type. This type is special as it tries to load
/// the value from the storage under a fixed key. If the value could not be found in the storage,
/// the given default value will be returned. It is required that the value implements
/// [`Encode`](codec::Encode) and [`Decode`](codec::Decode). The key for looking up the value in
/// the storage is built using the following formula:
///
/// `twox_128(":" ++ NAME ++ ":")` where `NAME` is the name that is passed as type name.
///
/// - Using `static` to create a static parameter type. Its value is being provided by a static
/// variable with the equivalent name in `UPPER_SNAKE_CASE`. An additional `set` function is
/// provided in this case to alter the static variable. **This is intended for testing ONLY and is
/// ONLY available when `std` is enabled.**
/// ```
/// # use frame_support::traits::Get;
/// # use frame_support::parameter_types;
/// // This function cannot be used in a const context.
/// fn non_const_expression() -> u64 { 99 }
///
/// const FIXED_VALUE: u64 = 10;
/// pub const Argument: u64 = 42 + FIXED_VALUE;
/// /// Visibility of the type is optional
/// OtherArgument: u64 = non_const_expression();
/// pub storage StorageArgument: u64 = 5;
/// pub static StaticArgument: u32 = 7;
/// type Parameter: Get<u64>;
/// type OtherParameter: Get<u64>;
/// type StorageParameter: Get<u64>;
/// type StaticParameter: Get<u32>;
/// struct Runtime;
/// impl Config for Runtime {
/// type Parameter = Argument;
/// type OtherParameter = OtherArgument;
/// type StorageParameter = StorageArgument;
/// type StaticParameter = StaticArgument;
/// }
///
/// // In testing, `StaticArgument` can be altered later: `StaticArgument::set(8)`.
/// ```
///
/// # Invalid example:
///
/// ```compile_fail
/// # use frame_support::traits::Get;
/// # use frame_support::parameter_types;
/// // This function cannot be used in a const context.
/// fn non_const_expression() -> u64 { 99 }
///
/// parameter_types! {
/// pub const Argument: u64 = non_const_expression();
/// }
/// ```
#[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_CONST $name , $type , $value);
$crate::parameter_types!( $( $rest )* );
);
(
$( #[ $attr:meta ] )*
$vis:vis $name:ident: $type:ty = $value:expr;
$( $rest:tt )*
) => (
$( #[ $attr ] )*
$vis struct $name;
$crate::parameter_types!(IMPL $name, $type, $value);
$crate::parameter_types!( $( $rest )* );
);
(
$( #[ $attr:meta ] )*
$vis:vis storage $name:ident: $type:ty = $value:expr;
$( $rest:tt )*
) => (
$( #[ $attr ] )*
$vis struct $name;
$crate::parameter_types!(IMPL_STORAGE $name, $type, $value);
$crate::parameter_types!( $( $rest )* );
(IMPL_CONST $name:ident, $type:ty, $value:expr) => {
impl $name {
/// Returns the value of this parameter type.
pub const fn get() -> $type {
$value
}
}
impl<I: From<$type>> $crate::traits::Get<I> for $name {
fn get() -> I {
I::from(Self::get())
}
}
};
(IMPL $name:ident, $type:ty, $value:expr) => {
/// Returns the value of this parameter type.
pub fn get() -> $type {
$value
}
}
impl<I: From<$type>> $crate::traits::Get<I> for $name {
fn get() -> I {
I::from(Self::get())
};
(IMPL_STORAGE $name:ident, $type:ty, $value:expr) => {
impl $name {
/// Returns the key for this parameter type.
#[allow(unused)]
pub fn key() -> [u8; 16] {
$crate::sp_core_hashing_proc_macro::twox_128!(b":", $name, b":")
}
/// Set the value of this parameter type in the storage.
///
/// This needs to be executed in an externalities provided
/// environment.
#[allow(unused)]
pub fn set(value: &$type) {
$crate::storage::unhashed::put(&Self::key(), value);
}
/// Returns the value of this parameter type.
///
/// This needs to be executed in an externalities provided
/// environment.
#[allow(unused)]
pub fn get() -> $type {
$crate::storage::unhashed::get(&Self::key()).unwrap_or_else(|| $value)
}
}
impl<I: From<$type>> $crate::traits::Get<I> for $name {
fn get() -> I {
I::from(Self::get())
}
}
$( #[ $attr:meta ] )*
$vis:vis static $name:ident: $type:ty = $value:expr;
$( $rest:tt )*
) => (
$crate::parameter_types_impl_thread_local!(
$( #[ $attr ] )*
$vis static $name: $type = $value;
$crate::parameter_types!( $( $rest )* );
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
);
}
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! parameter_types_impl_thread_local {
( $( $any:tt )* ) => {
compile_error!("static parameter types is only available in std and for testing.");
};
}
#[cfg(feature = "std")]
#[macro_export]
macro_rules! parameter_types_impl_thread_local {
(
$(
$( #[ $attr:meta ] )*
$vis:vis static $name:ident: $type:ty = $value:expr;
)*
) => {
$crate::parameter_types_impl_thread_local!(
IMPL_THREAD_LOCAL $( $vis, $name, $type, $value, )*
);
$crate::paste::item! {
$crate::parameter_types!(
$(
$( #[ $attr ] )*
$vis $name: $type = [<$name:snake:upper>].with(|v| v.borrow().clone());
)*
);
$(
impl $name {
/// Set the internal value.
pub fn set(t: $type) {
[<$name:snake:upper>].with(|v| *v.borrow_mut() = t);
}
}
)*
}
};
(IMPL_THREAD_LOCAL $( $vis:vis, $name:ident, $type:ty, $value:expr, )* ) => {
$crate::paste::item! {
thread_local! {
$(
pub static [<$name:snake:upper>]: std::cell::RefCell<$type> =
std::cell::RefCell::new($value);
)*
}
}
};
/// Macro for easily creating a new implementation of both the `Get` and `Contains` traits. Use
/// exactly as with `parameter_types`, only the type must be `Ord`.
#[macro_export]
macro_rules! ord_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::ord_parameter_types!{IMPL $name , $type , $value}
$crate::ord_parameter_types!{ $( $rest )* }
);
() => ();
(IMPL $name:ident , $type:ty , $value:expr) => {
impl $crate::traits::SortedMembers<$type> for $name {
fn contains(t: &$type) -> bool { &$value == t }
fn sorted_members() -> $crate::sp_std::prelude::Vec<$type> { vec![$value] }
fn count() -> usize { 1 }
#[cfg(feature = "runtime-benchmarks")]
fn add(_: &$type) {}
impl $crate::traits::Contains<$type> for $name {
fn contains(t: &$type) -> bool { &$value == t }
}
/// Print out a formatted message.
///
/// # Example
///
/// ```
/// frame_support::runtime_print!("my value is {}", 3);
/// ```
#[macro_export]
macro_rules! runtime_print {
($($arg:tt)+) => {
{
use core::fmt::Write;
let mut w = $crate::sp_std::Writer::default();
let _ = core::write!(&mut w, $($arg)+);
$crate::sp_io::misc::print_utf8(&w.inner())
}
}
}
/// Print out the debuggable type.
pub fn debug(data: &impl sp_std::fmt::Debug) {
runtime_print!("{:?}", data);
}
pub use frame_support_procedural::{
construct_runtime, decl_storage, match_and_insert, transactional, RuntimeDebugNoBound,
#[doc(hidden)]
pub use frame_support_procedural::__generate_dummy_part_checker;
/// Derive [`Clone`] but do not bound any generic.
///
/// This is useful for type generic over runtime:
/// ```
/// # use frame_support::CloneNoBound;
/// }
///
/// // Foo implements [`Clone`] because `C` bounds [`Clone`].
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Clone`].
/// #[derive(CloneNoBound)]
/// struct Foo<T: Config> {
/// }
/// ```
pub use frame_support_procedural::CloneNoBound;
/// Derive [`Eq`] but do not bound any generic.
///
/// This is useful for type generic over runtime:
/// ```
/// # use frame_support::{EqNoBound, PartialEqNoBound};
/// }
///
/// // Foo implements [`Eq`] because `C` bounds [`Eq`].
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Eq`].
/// #[derive(PartialEqNoBound, EqNoBound)]
/// struct Foo<T: Config> {
/// }
/// ```
pub use frame_support_procedural::EqNoBound;
/// Derive [`PartialEq`] but do not bound any generic.
///
/// This is useful for type generic over runtime:
/// ```
/// # use frame_support::PartialEqNoBound;
/// }
///
/// // Foo implements [`PartialEq`] because `C` bounds [`PartialEq`].
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`PartialEq`].
/// #[derive(PartialEqNoBound)]
/// struct Foo<T: Config> {
/// }
/// ```
pub use frame_support_procedural::PartialEqNoBound;
/// Derive [`Debug`] but do not bound any generic.
///
/// This is useful for type generic over runtime:
/// ```
/// # use frame_support::DebugNoBound;
/// # use core::fmt::Debug;
/// }
///
/// // Foo implements [`Debug`] because `C` bounds [`Debug`].
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Debug`].
/// #[derive(DebugNoBound)]
/// struct Foo<T: Config> {
/// }
/// ```
pub use frame_support_procedural::DebugNoBound;
/// Derive [`Default`] but do not bound any generic.
///
/// This is useful for type generic over runtime:
/// ```
/// # use frame_support::DefaultNoBound;
/// # use core::default::Default;
/// trait Config {
/// }
///
/// // Foo implements [`Default`] because `C` bounds [`Default`].
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Default`].
/// #[derive(DefaultNoBound)]
/// struct Foo<T: Config> {
/// }
/// ```
pub use frame_support_procedural::DefaultNoBound;
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
/// Assert the annotated function is executed within a storage transaction.
///
/// The assertion is enabled for native execution and when `debug_assertions` are enabled.
///
/// # Example
///
/// ```
/// # use frame_support::{
/// # require_transactional, transactional, dispatch::DispatchResult
/// # };
///
/// #[require_transactional]
/// fn update_all(value: u32) -> DispatchResult {
/// // Update multiple storages.
/// // Return `Err` to indicate should revert.
/// Ok(())
/// }
///
/// #[transactional]
/// fn safe_update(value: u32) -> DispatchResult {
/// // This is safe
/// update_all(value)
/// }
///
/// fn unsafe_update(value: u32) -> DispatchResult {
/// // this may panic if unsafe_update is not called within a storage transaction
/// update_all(value)
/// }
/// ```
pub use frame_support_procedural::require_transactional;
/// Convert the current crate version into a [`CrateVersion`](crate::traits::CrateVersion).
///
/// It uses the `CARGO_PKG_VERSION_MAJOR`, `CARGO_PKG_VERSION_MINOR` and
/// `CARGO_PKG_VERSION_PATCH` environment variables to fetch the crate version.
/// This means that the [`CrateVersion`](crate::traits::CrateVersion)
/// object will correspond to the version of the crate the macro is called in!
///
/// # Example
///
/// ```
/// # use frame_support::{traits::CrateVersion, crate_to_crate_version};
/// const Version: CrateVersion = crate_to_crate_version!();
/// ```
pub use frame_support_procedural::crate_to_crate_version;
/// Return Err of the expression: `return Err($expression);`.
///
/// Used as `fail!(expression)`.
#[macro_export]
macro_rules! fail {
( $y:expr ) => {{
return Err($y.into())
}};
/// 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 {
$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)`.
(
$x:expr,
$y:expr $(,)?
) => {
let h = $crate::storage_root($crate::StateVersion::V1);
$crate::assert_err!($x, $y);
assert_eq!(h, $crate::storage_root($crate::StateVersion::V1));
/// Evaluate any expression and assert that runtime storage has not been mutated
/// (i.e. expression is a storage no-operation).
///
/// Used as `assert_storage_noop(expression_to_assert)`.
#[macro_export]
macro_rules! assert_storage_noop {
(
$x:expr
) => {
let h = $crate::storage_root($crate::StateVersion::V1);
assert_eq!(h, $crate::storage_root($crate::StateVersion::V1));
/// Assert an expression returns an error specified.
///
/// Used as `assert_err!(expression_to_assert, expected_error_expression)`
assert_eq!($x, Err($y.into()));
/// Assert an expression returns an error specified.
///
/// This can be used on`DispatchResultWithPostInfo` when the post info should
/// be ignored.
#[macro_export]
macro_rules! assert_err_ignore_postinfo {
( $x:expr , $y:expr $(,)? ) => {
$crate::assert_err!($x.map(|_| ()).map_err(|e| e.error), $y);
/// Assert an expression returns error with the given weight.
#[macro_export]
macro_rules! assert_err_with_weight {
($call:expr, $err:expr, $weight:expr $(,)? ) => {
if let Err(dispatch_err_with_post) = $call {
$crate::assert_err!($call.map(|_| ()).map_err(|e| e.error), $err);
assert_eq!(dispatch_err_with_post.post_info.actual_weight, $weight.into());
} else {
panic!("expected Err(_), got Ok(_).")
}
/// 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(())`.
( $x:expr $(,)? ) => {
let is = $x;
match is {
Ok(_) => (),
_ => assert!(false, "Expected Ok(_). Got {:#?}", is),
}
( $x:expr, $y:expr $(,)? ) => {
Bastian Köcher
committed
#[doc(hidden)]
pub use serde::{Deserialize, Serialize};
Drew Stone
committed
pub mod tests {
use crate::metadata::{
PalletStorageMetadata, StorageEntryMetadata, StorageEntryModifier, StorageEntryType,
StorageHasher,
use codec::{Codec, EncodeLike};
use frame_support::traits::CrateVersion;
use sp_io::TestExternalities;
/// A PalletInfo implementation which just panics.
pub struct PanicPalletInfo;
impl crate::traits::PalletInfo for PanicPalletInfo {
fn index<P: 'static>() -> Option<usize> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn name<P: 'static>() -> Option<&'static str> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn module_name<P: 'static>() -> Option<&'static str> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn crate_version<P: 'static>() -> Option<CrateVersion> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
pub trait Config: 'static {
type BlockNumber: Codec + EncodeLike + Default + TypeInfo;
type PalletInfo: crate::traits::PalletInfo;
type DbWeight: crate::traits::Get<crate::weights::RuntimeDbWeight>;
}
mod module {
#![allow(dead_code)]
pub struct Module<T: Config> for enum Call where origin: T::Origin, system=self {}
}
}
use self::module::Module;
decl_storage! {
trait Store for Module<T: Config> as Test {
pub Data get(fn data) build(|_| vec![(15u32, 42u64)]):
map hasher(twox_64_concat) u32 => u64;
pub OptionLinkedMap: map hasher(blake2_128_concat) u32 => Option<u32>;
pub GenericData get(fn generic_data):
map hasher(identity) T::BlockNumber => T::BlockNumber;
pub GenericData2 get(fn generic_data2):
map hasher(blake2_128_concat) T::BlockNumber => Option<T::BlockNumber>;
pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]):
double_map hasher(twox_64_concat) u32, hasher(blake2_128_concat) u32 => u64;
double_map hasher(blake2_128_concat) T::BlockNumber, hasher(identity) T::BlockNumber
double_map hasher(blake2_128_concat) T::BlockNumber, hasher(twox_64_concat) T::BlockNumber
=> Option<T::BlockNumber>;
pub AppendableDM:
double_map hasher(blake2_128_concat) u32, hasher(blake2_128_concat) T::BlockNumber => Vec<u32>;
type BlockNumber = u32;
type Origin = u32;
type PalletInfo = PanicPalletInfo;
fn new_test_ext() -> TestExternalities {
GenesisConfig::default().build_storage().unwrap().into()
type Map = Data;
trait Sorted {
fn sorted(self) -> Self;
}
impl<T: Ord> Sorted for Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
new_test_ext().execute_with(|| {
OptionLinkedMap::insert(1, 1);
assert_eq!(OptionLinkedMap::get(1), Some(1));
OptionLinkedMap::insert(1, 2);
assert_eq!(OptionLinkedMap::get(1), Some(2));
});
}
new_test_ext().execute_with(|| {
OptionLinkedMap::insert(0, 0);
OptionLinkedMap::insert(1, 1);
OptionLinkedMap::insert(2, 2);
OptionLinkedMap::insert(3, 3);
let collect = || OptionLinkedMap::iter().collect::<Vec<_>>().sorted();
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
// Two existing
OptionLinkedMap::swap(1, 2);
assert_eq!(collect(), vec![(0, 0), (1, 2), (2, 1), (3, 3)]);
// Back to normal
OptionLinkedMap::swap(2, 1);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
// Left existing
OptionLinkedMap::swap(2, 5);
assert_eq!(collect(), vec![(0, 0), (1, 1), (3, 3), (5, 2)]);
// Right existing
OptionLinkedMap::swap(5, 2);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
#[test]
fn double_map_swap_works() {
new_test_ext().execute_with(|| {
DataDM::insert(0, 1, 1);
DataDM::insert(1, 0, 2);
DataDM::insert(1, 1, 3);
let get_all = || {
vec![
DataDM::get(0, 1),
DataDM::get(1, 0),
DataDM::get(1, 1),
DataDM::get(2, 0),
DataDM::get(2, 1),
]
};
assert_eq!(get_all(), vec![1, 2, 3, 0, 0]);
// Two existing
DataDM::swap(0, 1, 1, 0);
assert_eq!(get_all(), vec![2, 1, 3, 0, 0]);
// Left existing
DataDM::swap(1, 0, 2, 0);
assert_eq!(get_all(), vec![2, 0, 3, 1, 0]);
// Right existing
DataDM::swap(2, 1, 1, 1);
assert_eq!(get_all(), vec![2, 0, 0, 1, 3]);
});
}
fn map_basic_insert_remove_should_work() {
new_test_ext().execute_with(|| {