// This file is part of Substrate. // Copyright (C) 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. use frame_support::{ dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, UnfilteredDispatchable}, pallet_prelude::ValueQuery, parameter_types, storage::unhashed, traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, weights::Weight, }; use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, TestExternalities, }; use sp_runtime::{DispatchError, ModuleError}; use sp_std::any::TypeId; #[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; type BalanceOf = >::Balance; #[pallet::config] pub trait Config: frame_system::Config { #[pallet::constant] type MyGetParam: Get; type Balance: Parameter + Default + scale_info::StaticTypeInfo; type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { fn on_initialize(_: BlockNumberFor) -> Weight { if TypeId::of::() == TypeId::of::<()>() { Self::deposit_event(Event::Something(10)); Weight::from_parts(10, 0) } else { Self::deposit_event(Event::Something(11)); Weight::from_parts(11, 0) } } fn on_finalize(_: BlockNumberFor) { if TypeId::of::() == TypeId::of::<()>() { Self::deposit_event(Event::Something(20)); } else { Self::deposit_event(Event::Something(21)); } } fn on_runtime_upgrade() -> Weight { if TypeId::of::() == TypeId::of::<()>() { Self::deposit_event(Event::Something(30)); Weight::from_parts(30, 0) } else { Self::deposit_event(Event::Something(31)); Weight::from_parts(31, 0) } } fn integrity_test() {} } #[pallet::call] impl, I: 'static> Pallet { /// Doc comment put in metadata #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(*_foo as u64, 0))] pub fn foo( origin: OriginFor, #[pallet::compact] _foo: u32, ) -> DispatchResultWithPostInfo { let _ = origin; Self::deposit_event(Event::Something(3)); Ok(().into()) } /// Doc comment put in metadata #[pallet::call_index(1)] #[pallet::weight(1)] pub fn foo_storage_layer( origin: OriginFor, #[pallet::compact] _foo: u32, ) -> DispatchResultWithPostInfo { let _ = origin; Ok(().into()) } } #[pallet::error] #[derive(PartialEq, Eq)] pub enum Error { /// doc comment put into metadata InsufficientProposersBalance, NonExistentStorageValue, } #[pallet::event] #[pallet::generate_deposit(fn deposit_event)] pub enum Event, I: 'static = ()> { /// doc comment put in metadata Proposed(::AccountId), /// doc Spending(BalanceOf), Something(u32), } #[pallet::storage] pub type Value = StorageValue<_, u32>; #[pallet::storage] pub type Map = StorageMap<_, Blake2_128Concat, u8, u16>; #[pallet::storage] pub type Map2 = StorageMap<_, Twox64Concat, u16, u32>; parameter_types! { pub const Map3Default: Result> = Ok(1337); } #[pallet::storage] pub type Map3 = StorageMap< _, Blake2_128Concat, u32, u64, ResultQuery::NonExistentStorageValue>, Map3Default, >; #[pallet::storage] pub type DoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; #[pallet::storage] pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; #[pallet::storage] pub type DoubleMap3 = StorageDoubleMap< _, Blake2_128Concat, u32, Twox64Concat, u64, u128, ResultQuery::NonExistentStorageValue>, >; #[pallet::storage] #[pallet::getter(fn nmap)] pub type NMap = StorageNMap<_, storage::Key, u32>; #[pallet::storage] #[pallet::getter(fn nmap2)] pub type NMap2 = StorageNMap<_, (storage::Key, storage::Key), u64>; #[pallet::storage] #[pallet::getter(fn nmap3)] pub type NMap3 = StorageNMap< _, (NMapKey, NMapKey), u128, ResultQuery::NonExistentStorageValue>, >; #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { _myfield: u32, } #[pallet::genesis_build] impl, I: 'static> GenesisBuild for GenesisConfig { fn build(&self) {} } #[pallet::origin] #[derive( EqNoBound, RuntimeDebugNoBound, CloneNoBound, PartialEqNoBound, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen, )] #[scale_info(skip_type_params(T, I))] pub struct Origin(PhantomData<(T, I)>); #[pallet::validate_unsigned] impl, I: 'static> ValidateUnsigned for Pallet { type Call = Call; fn validate_unsigned( _source: TransactionSource, _call: &Self::Call, ) -> TransactionValidity { Err(TransactionValidityError::Invalid(InvalidTransaction::Call)) } } #[pallet::inherent] impl, I: 'static> ProvideInherent for Pallet { type Call = Call; type Error = InherentError; const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; fn create_inherent(_data: &InherentData) -> Option { unimplemented!(); } fn is_inherent(_call: &Self::Call) -> bool { unimplemented!(); } } #[derive(codec::Encode, sp_runtime::RuntimeDebug)] #[cfg_attr(feature = "std", derive(codec::Decode))] pub enum InherentError {} impl frame_support::inherent::IsFatalError for InherentError { fn is_fatal_error(&self) -> bool { unimplemented!(); } } pub const INHERENT_IDENTIFIER: frame_support::inherent::InherentIdentifier = *b"testpall"; } // Test that a instantiable pallet with a generic genesis_config is correctly handled #[frame_support::pallet] pub mod pallet2 { use frame_support::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] pub struct Pallet(PhantomData<(T, I)>); #[pallet::event] pub enum Event, I: 'static = ()> { /// Something Something(u32), } #[pallet::genesis_config] pub struct GenesisConfig, I: 'static = ()> { phantom: PhantomData<(T, I)>, } impl, I: 'static> Default for GenesisConfig { fn default() -> Self { GenesisConfig { phantom: Default::default() } } } #[pallet::genesis_build] impl, I: 'static> GenesisBuild for GenesisConfig { fn build(&self) {} } } impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; type AccountData = (); type OnNewAccount = (); type OnKilledAccount = (); type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet::Config for Runtime { type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet2::Config for Runtime { type RuntimeEvent = RuntimeEvent; } impl pallet2::Config for Runtime { type RuntimeEvent = RuntimeEvent; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub struct Runtime where Block = Block, NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { // Exclude part `Storage` in order not to check its metadata in tests. System: frame_system exclude_parts { Storage }, Example: pallet, Instance1Example: pallet::, Example2: pallet2, Instance1Example2: pallet2::, } ); #[test] fn call_expand() { let call_foo = pallet::Call::::foo { foo: 3 }; assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes } ); assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!(pallet::Call::::get_call_names(), &["foo", "foo_storage_layer"]); let call_foo = pallet::Call::::foo { foo: 3 }; assert_eq!( call_foo.get_dispatch_info(), DispatchInfo { weight: Weight::from_parts(3, 0), class: DispatchClass::Normal, pays_fee: Pays::Yes } ); assert_eq!(call_foo.get_call_name(), "foo"); assert_eq!( pallet::Call::::get_call_names(), &["foo", "foo_storage_layer"], ); } #[test] fn error_expand() { assert_eq!( format!("{:?}", pallet::Error::::InsufficientProposersBalance), String::from("InsufficientProposersBalance"), ); assert_eq!( <&'static str>::from(pallet::Error::::InsufficientProposersBalance), "InsufficientProposersBalance", ); assert_eq!( DispatchError::from(pallet::Error::::InsufficientProposersBalance), DispatchError::Module(ModuleError { index: 1, error: [0; 4], message: Some("InsufficientProposersBalance") }), ); assert_eq!( format!("{:?}", pallet::Error::::InsufficientProposersBalance), String::from("InsufficientProposersBalance"), ); assert_eq!( <&'static str>::from( pallet::Error::::InsufficientProposersBalance ), "InsufficientProposersBalance", ); assert_eq!( DispatchError::from( pallet::Error::::InsufficientProposersBalance ), DispatchError::Module(ModuleError { index: 2, error: [0; 4], message: Some("InsufficientProposersBalance") }), ); } #[test] fn module_error_outer_enum_expand() { // assert that all variants of the Example pallet are included into the // RuntimeError definition. match RuntimeError::Example(pallet::Error::InsufficientProposersBalance) { RuntimeError::Example(example) => match example { pallet::Error::InsufficientProposersBalance => (), pallet::Error::NonExistentStorageValue => (), // Extra pattern added by `construct_runtime`. pallet::Error::__Ignore(_, _) => (), }, _ => (), }; } #[test] fn module_error_from_dispatch_error() { let dispatch_err = DispatchError::Module(ModuleError { index: 1, error: [0; 4], message: Some("InsufficientProposersBalance"), }); let err = RuntimeError::from_dispatch_error(dispatch_err).unwrap(); match err { RuntimeError::Example(pallet::Error::InsufficientProposersBalance) => (), _ => panic!("Module error constructed incorrectly"), }; // Only `ModuleError` is converted. assert!(RuntimeError::from_dispatch_error(DispatchError::BadOrigin).is_none()); } #[test] fn instance_expand() { // assert same type let _: pallet::__InherentHiddenInstance = (); } #[test] fn pallet_expand_deposit_event() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); pallet::Call::::foo { foo: 3 } .dispatch_bypass_filter(None.into()) .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, RuntimeEvent::Example(pallet::Event::Something(3)), ); }); TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); pallet::Call::::foo { foo: 3 } .dispatch_bypass_filter(None.into()) .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, RuntimeEvent::Instance1Example(pallet::Event::Something(3)), ); }); } #[test] fn storage_expand() { use frame_support::{pallet_prelude::*, storage::StoragePrefixedMap}; fn twox_64_concat(d: &[u8]) -> Vec { let mut v = twox_64(d).to_vec(); v.extend_from_slice(d); v } fn blake2_128_concat(d: &[u8]) -> Vec { let mut v = blake2_128(d).to_vec(); v.extend_from_slice(d); v } TestExternalities::default().execute_with(|| { >::put(1); let k = [twox_128(b"Example"), twox_128(b"Value")].concat(); assert_eq!(unhashed::get::(&k), Some(1u32)); >::insert(1, 2); let mut k = [twox_128(b"Example"), twox_128(b"Map")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(2u16)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(1, 2); let mut k = [twox_128(b"Example"), twox_128(b"Map2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(2u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(1, 2); let mut k = [twox_128(b"Example"), twox_128(b"Map3")].concat(); k.extend(1u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(2u64)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!(>::get(2), Ok(1337)); >::insert(&1, &2, &3); let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); k.extend(2u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(&1, &2, &3); let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(&1, &2, &3); let mut k = [twox_128(b"Example"), twox_128(b"DoubleMap3")].concat(); k.extend(1u32.using_encoded(blake2_128_concat)); k.extend(2u64.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u128)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!( >::get(2, 3), Err(pallet::Error::::NonExistentStorageValue), ); >::insert((&1,), &3); let mut k = [twox_128(b"Example"), twox_128(b"NMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert((&1, &2), &3); let mut k = [twox_128(b"Example"), twox_128(b"NMap2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); >::insert((&1, &2), &3); let mut k = [twox_128(b"Example"), twox_128(b"NMap3")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); k.extend(2u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u128)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!( >::get((2, 3)), Err(pallet::Error::::NonExistentStorageValue), ); }); TestExternalities::default().execute_with(|| { >::put(1); let k = [twox_128(b"Instance1Example"), twox_128(b"Value")].concat(); assert_eq!(unhashed::get::(&k), Some(1u32)); >::insert(1, 2); let mut k = [twox_128(b"Instance1Example"), twox_128(b"Map")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(2u16)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(1, 2); let mut k = [twox_128(b"Instance1Example"), twox_128(b"Map2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(2u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(1, 2); let mut k = [twox_128(b"Instance1Example"), twox_128(b"Map3")].concat(); k.extend(1u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(2u64)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!(>::get(2), Ok(1337)); >::insert(&1, &2, &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"DoubleMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); k.extend(2u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(&1, &2, &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"DoubleMap2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); >::insert(&1, &2, &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"DoubleMap3")].concat(); k.extend(1u32.using_encoded(blake2_128_concat)); k.extend(2u64.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u128)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!( >::get(2, 3), Err(pallet::Error::::NonExistentStorageValue), ); >::insert((&1,), &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u32)); assert_eq!(&k[..32], &>::final_prefix()); >::insert((&1, &2), &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap2")].concat(); k.extend(1u16.using_encoded(twox_64_concat)); k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); >::insert((&1, &2), &3); let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap3")].concat(); k.extend(1u8.using_encoded(blake2_128_concat)); k.extend(2u16.using_encoded(twox_64_concat)); assert_eq!(unhashed::get::(&k), Some(3u128)); assert_eq!(&k[..32], &>::final_prefix()); assert_eq!( >::get((2, 3)), Err(pallet::Error::::NonExistentStorageValue), ); }); } #[test] fn pallet_metadata_expands() { use frame_support::traits::PalletsInfoAccess; let mut infos = AllPalletsWithSystem::infos(); infos.sort_by_key(|x| x.index); assert_eq!(infos[0].index, 0); assert_eq!(infos[0].name, "System"); assert_eq!(infos[0].module_name, "frame_system"); assert_eq!(infos[1].index, 1); assert_eq!(infos[1].name, "Example"); assert_eq!(infos[1].module_name, "pallet"); assert_eq!(infos[2].index, 2); assert_eq!(infos[2].name, "Instance1Example"); assert_eq!(infos[2].module_name, "pallet"); assert_eq!(infos[3].index, 3); assert_eq!(infos[3].name, "Example2"); assert_eq!(infos[3].module_name, "pallet2"); assert_eq!(infos[4].index, 4); assert_eq!(infos[4].name, "Instance1Example2"); assert_eq!(infos[4].module_name, "pallet2"); } #[test] fn pallet_hooks_expand() { TestExternalities::default().execute_with(|| { frame_system::Pallet::::set_block_number(1); assert_eq!(AllPalletsWithoutSystem::on_initialize(1), Weight::from_parts(21, 0)); AllPalletsWithoutSystem::on_finalize(1); assert_eq!(AllPalletsWithoutSystem::on_runtime_upgrade(), Weight::from_parts(61, 0)); assert_eq!( frame_system::Pallet::::events()[0].event, RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, RuntimeEvent::Instance1Example(pallet::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, RuntimeEvent::Instance1Example(pallet::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, RuntimeEvent::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, RuntimeEvent::Instance1Example(pallet::Event::Something(31)), ); }) } #[test] fn pallet_on_genesis() { TestExternalities::default().execute_with(|| { pallet::Pallet::::on_genesis(); pallet::Pallet::::on_genesis(); }) } #[test] fn metadata() { use frame_support::metadata::{v14::*, *}; let system_pallet_metadata = PalletMetadata { index: 0, name: "System", storage: None, // The storage metadatas have been excluded. calls: Some(scale_info::meta_type::>().into()), event: Some(PalletEventMetadata { ty: scale_info::meta_type::>(), }), constants: vec![ PalletConstantMetadata { name: "BlockWeights", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, PalletConstantMetadata { name: "BlockLength", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, PalletConstantMetadata { name: "BlockHashCount", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, PalletConstantMetadata { name: "DbWeight", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, PalletConstantMetadata { name: "Version", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, PalletConstantMetadata { name: "SS58Prefix", ty: scale_info::meta_type::(), value: vec![], docs: vec![], }, ], error: Some(PalletErrorMetadata { ty: scale_info::meta_type::>(), }), }; let example_pallet_metadata = PalletMetadata { index: 1, name: "Example", storage: Some(PalletStorageMetadata { prefix: "Example", entries: vec![ StorageEntryMetadata { name: "Value", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Plain(scale_info::meta_type::()), default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "Map", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::(), value: scale_info::meta_type::(), hashers: vec![StorageHasher::Blake2_128Concat], }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "Map2", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::(), value: scale_info::meta_type::(), hashers: vec![StorageHasher::Twox64Concat], }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "Map3", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::(), value: scale_info::meta_type::(), hashers: vec![StorageHasher::Blake2_128Concat], }, default: vec![0, 57, 5, 0, 0, 0, 0, 0, 0], docs: vec![], }, StorageEntryMetadata { name: "DoubleMap", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { value: scale_info::meta_type::(), key: scale_info::meta_type::<(u8, u16)>(), hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "DoubleMap2", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { value: scale_info::meta_type::(), key: scale_info::meta_type::<(u16, u32)>(), hashers: vec![StorageHasher::Twox64Concat, StorageHasher::Blake2_128Concat], }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "DoubleMap3", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { value: scale_info::meta_type::(), key: scale_info::meta_type::<(u32, u64)>(), hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], }, default: vec![1, 1], docs: vec![], }, StorageEntryMetadata { name: "NMap", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::(), hashers: vec![StorageHasher::Blake2_128Concat], value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "NMap2", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::<(u16, u32)>(), hashers: vec![StorageHasher::Twox64Concat, StorageHasher::Blake2_128Concat], value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], }, StorageEntryMetadata { name: "NMap3", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { key: scale_info::meta_type::<(u8, u16)>(), hashers: vec![StorageHasher::Blake2_128Concat, StorageHasher::Twox64Concat], value: scale_info::meta_type::(), }, default: vec![1, 1], docs: vec![], }, ], }), calls: Some(scale_info::meta_type::>().into()), event: Some(PalletEventMetadata { ty: scale_info::meta_type::>() }), constants: vec![PalletConstantMetadata { name: "MyGetParam", ty: scale_info::meta_type::(), value: vec![10, 0, 0, 0], docs: vec![], }], error: Some(PalletErrorMetadata { ty: scale_info::meta_type::>() }), }; let mut example_pallet_instance1_metadata = example_pallet_metadata.clone(); example_pallet_instance1_metadata.name = "Instance1Example"; example_pallet_instance1_metadata.index = 2; match example_pallet_instance1_metadata.calls { Some(ref mut calls_meta) => { calls_meta.ty = scale_info::meta_type::>(); }, _ => unreachable!(), } match example_pallet_instance1_metadata.event { Some(ref mut event_meta) => { event_meta.ty = scale_info::meta_type::>(); }, _ => unreachable!(), } match example_pallet_instance1_metadata.error { Some(ref mut error_meta) => { error_meta.ty = scale_info::meta_type::>(); }, _ => unreachable!(), } match example_pallet_instance1_metadata.storage { Some(ref mut storage_meta) => { storage_meta.prefix = "Instance1Example"; }, _ => unreachable!(), } let pallets = vec![system_pallet_metadata, example_pallet_metadata, example_pallet_instance1_metadata]; let extrinsic = ExtrinsicMetadata { ty: scale_info::meta_type::(), version: 4, signed_extensions: vec![SignedExtensionMetadata { identifier: "UnitSignedExtension", ty: scale_info::meta_type::<()>(), additional_signed: scale_info::meta_type::<()>(), }], }; let expected_metadata: RuntimeMetadataPrefixed = RuntimeMetadataLastVersion::new(pallets, extrinsic, scale_info::meta_type::()) .into(); let expected_metadata = match expected_metadata.1 { RuntimeMetadata::V14(metadata) => metadata, _ => panic!("metadata has been bumped, test needs to be updated"), }; let actual_metadata = match Runtime::metadata().1 { RuntimeMetadata::V14(metadata) => metadata, _ => panic!("metadata has been bumped, test needs to be updated"), }; pretty_assertions::assert_eq!(actual_metadata.pallets[1], expected_metadata.pallets[1]); pretty_assertions::assert_eq!(actual_metadata.pallets[2], expected_metadata.pallets[2]); } #[test] fn test_pallet_info_access() { assert_eq!(::name(), "System"); assert_eq!(::name(), "Example"); assert_eq!( ::name(), "Instance1Example" ); assert_eq!(::name(), "Example2"); assert_eq!( ::name(), "Instance1Example2" ); assert_eq!(::index(), 0); assert_eq!(::index(), 1); assert_eq!(::index(), 2); assert_eq!(::index(), 3); assert_eq!(::index(), 4); } #[test] fn test_storage_alias() { #[frame_support::storage_alias] type Value, I: 'static> = StorageValue, u32, ValueQuery>; TestExternalities::default().execute_with(|| { pallet::Value::::put(10); assert_eq!(10, Value::::get()); }) }