// This file is part of Bizinikiwi. // Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // 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. #![allow(clippy::deprecated_semver)] use super::*; use pezsp_io::{MultiRemovalResults, TestExternalities}; use pezsp_metadata_ir::{ PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR, StorageHasherIR, }; use pezsp_runtime::{generic, traits::BlakeTwo256, BuildStorage}; pub use self::pezframe_system::{pezpallet_prelude::*, Config, Pezpallet}; mod storage_alias; #[pezpallet] pub mod pezframe_system { #[allow(unused)] use super::{pezframe_system, pezframe_system::pezpallet_prelude::*}; pub use crate::dispatch::RawOrigin; use crate::{pezpallet_prelude::*, traits::tasks::Task as TaskTrait}; pub mod config_preludes { use super::{inject_runtime_type, DefaultConfig}; pub struct TestDefaultConfig; #[crate::register_default_impl(TestDefaultConfig)] impl DefaultConfig for TestDefaultConfig { type AccountId = u64; type BaseCallFilter = pezframe_support::traits::Everything; #[inject_runtime_type] type RuntimeOrigin = (); #[inject_runtime_type] type RuntimeCall = (); #[inject_runtime_type] type PalletInfo = (); #[inject_runtime_type] type RuntimeTask = (); type DbWeight = (); } } #[pezpallet::pezpallet] pub struct Pezpallet(_); #[pezpallet::config(with_default, pezframe_system_config)] #[pezpallet::disable_pezframe_system_supertrait_check] pub trait Config: 'static { #[pezpallet::no_default] type Block: Parameter + pezsp_runtime::traits::Block; type AccountId; #[pezpallet::no_default_bounds] type BaseCallFilter: crate::traits::Contains; #[pezpallet::no_default_bounds] type RuntimeOrigin; #[pezpallet::no_default_bounds] type RuntimeCall; #[pezpallet::no_default_bounds] type RuntimeTask: crate::traits::tasks::Task; #[pezpallet::no_default_bounds] type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; #[pezpallet::constant] #[pezpallet::no_default] #[deprecated = "this constant is deprecated"] #[allow(deprecated)] type ExampleConstant: Get<()>; } #[pezpallet::error] pub enum Error { /// Required by construct_runtime CallFiltered, /// Used in tasks example. NotFound, /// The specified [`Task`] is not valid. InvalidTask, /// The specified [`Task`] failed during execution. FailedTask, } #[pezpallet::origin] pub type Origin = RawOrigin<::AccountId>; #[pezpallet::call] impl Pezpallet { #[pezpallet::call_index(0)] #[pezpallet::weight(task.weight())] pub fn do_task(_origin: OriginFor, task: T::RuntimeTask) -> DispatchResultWithPostInfo { if !task.is_valid() { return Err(Error::::InvalidTask.into()); } if let Err(_err) = task.run() { return Err(Error::::FailedTask.into()); } Ok(().into()) } } #[pezpallet::storage] #[deprecated] #[allow(deprecated)] pub type Data = StorageMap<_, Twox64Concat, u32, u64, ValueQuery>; #[pezpallet::storage] #[deprecated(note = "test")] #[allow(deprecated)] pub type OptionLinkedMap = StorageMap<_, Blake2_128Concat, u32, u32, OptionQuery>; #[pezpallet::storage] #[pezpallet::getter(fn generic_data)] #[deprecated(note = "test", since = "test")] #[allow(deprecated)] pub type GenericData = StorageMap<_, Identity, BlockNumberFor, BlockNumberFor, ValueQuery>; #[pezpallet::storage] #[pezpallet::getter(fn generic_data2)] #[deprecated = "test"] #[allow(deprecated)] pub type GenericData2 = StorageMap<_, Blake2_128Concat, BlockNumberFor, BlockNumberFor, OptionQuery>; #[pezpallet::storage] pub type DataDM = StorageDoubleMap<_, Twox64Concat, u32, Blake2_128Concat, u32, u64, ValueQuery>; #[pezpallet::storage] pub type GenericDataDM = StorageDoubleMap< _, Blake2_128Concat, BlockNumberFor, Identity, BlockNumberFor, BlockNumberFor, ValueQuery, >; #[pezpallet::storage] pub type GenericData2DM = StorageDoubleMap< _, Blake2_128Concat, BlockNumberFor, Twox64Concat, BlockNumberFor, BlockNumberFor, OptionQuery, >; #[pezpallet::storage] #[pezpallet::unbounded] pub type AppendableDM = StorageDoubleMap< _, Blake2_128Concat, u32, Blake2_128Concat, BlockNumberFor, Vec, ValueQuery, >; #[pezpallet::genesis_config] pub struct GenesisConfig { pub data: Vec<(u32, u64)>, pub test_config: Vec<(u32, u32, u64)>, #[serde(skip)] pub _config: core::marker::PhantomData, } impl Default for GenesisConfig { fn default() -> Self { Self { _config: Default::default(), data: vec![(15u32, 42u64)], test_config: vec![(15u32, 16u32, 42u64)], } } } #[pezpallet::genesis_build] impl BuildGenesisConfig for GenesisConfig { #[allow(deprecated)] fn build(&self) { for (k, v) in &self.data { >::insert(k, v); } for (k1, k2, v) in &self.test_config { >::insert(k1, k2, v); } } } /// Some running total. #[pezpallet::storage] pub type Total = StorageValue<_, (u32, u32), ValueQuery>; /// Numbers to be added into the total. #[pezpallet::storage] pub type Numbers = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>; pub mod pezpallet_prelude { pub type OriginFor = ::RuntimeOrigin; pub type HeaderFor = <::Block as pezsp_runtime::traits::HeaderProvider>::HeaderT; pub type BlockNumberFor = as pezsp_runtime::traits::Header>::Number; } } type BlockNumber = u32; type AccountId = u32; type Header = generic::Header; type UncheckedExtrinsic = generic::UncheckedExtrinsic; type Block = generic::Block; #[crate::runtime] mod runtime { #[runtime::runtime] #[runtime::derive( RuntimeCall, RuntimeEvent, RuntimeError, RuntimeOrigin, RuntimeFreezeReason, RuntimeHoldReason, RuntimeSlashReason, RuntimeLockId, RuntimeTask, RuntimeViewFunction )] pub struct Runtime; #[runtime::pezpallet_index(0)] pub type System = self::pezframe_system; } #[crate::derive_impl(self::pezframe_system::config_preludes::TestDefaultConfig as self::pezframe_system::DefaultConfig)] impl Config for Runtime { type Block = Block; type AccountId = AccountId; type ExampleConstant = (); } fn new_test_ext() -> TestExternalities { RuntimeGenesisConfig::default().build_storage().unwrap().into() } trait Sorted { fn sorted(self) -> Self; } impl Sorted for Vec { fn sorted(mut self) -> Self { self.sort(); self } } #[test] fn map_issue_3318() { new_test_ext().execute_with(|| { #[allow(deprecated)] type OptionLinkedMap = self::pezframe_system::OptionLinkedMap; OptionLinkedMap::insert(1, 1); assert_eq!(OptionLinkedMap::get(1), Some(1)); OptionLinkedMap::insert(1, 2); assert_eq!(OptionLinkedMap::get(1), Some(2)); }); } #[test] fn map_swap_works() { new_test_ext().execute_with(|| { #[allow(deprecated)] type OptionLinkedMap = self::pezframe_system::OptionLinkedMap; OptionLinkedMap::insert(0, 0); OptionLinkedMap::insert(1, 1); OptionLinkedMap::insert(2, 2); OptionLinkedMap::insert(3, 3); let collect = || OptionLinkedMap::iter().collect::>().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(|| { #[allow(deprecated)] type DataDM = self::pezframe_system::DataDM; 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]); }); } #[test] fn map_basic_insert_remove_should_work() { new_test_ext().execute_with(|| { #[allow(deprecated)] type Map = self::pezframe_system::Data; // 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 map_iteration_should_work() { new_test_ext().execute_with(|| { #[allow(deprecated)] type Map = self::pezframe_system::Data; assert_eq!(Map::iter().collect::>().sorted(), vec![(15, 42)]); // insert / remove let key = 17u32; Map::insert(key, 4u64); assert_eq!(Map::iter().collect::>().sorted(), vec![(15, 42), (key, 4)]); assert_eq!(Map::take(&15), 42u64); assert_eq!(Map::take(&key), 4u64); assert_eq!(Map::iter().collect::>().sorted(), vec![]); // Add couple of more elements Map::insert(key, 42u64); assert_eq!(Map::iter().collect::>().sorted(), vec![(key, 42)]); Map::insert(key + 1, 43u64); assert_eq!(Map::iter().collect::>().sorted(), vec![(key, 42), (key + 1, 43)]); // mutate let key = key + 2; Map::mutate(&key, |val| { *val = 15; }); assert_eq!( Map::iter().collect::>().sorted(), vec![(key - 2, 42), (key - 1, 43), (key, 15)] ); Map::mutate(&key, |val| { *val = 17; }); assert_eq!( Map::iter().collect::>().sorted(), vec![(key - 2, 42), (key - 1, 43), (key, 17)] ); // remove first Map::remove(&key); assert_eq!(Map::iter().collect::>().sorted(), vec![(key - 2, 42), (key - 1, 43)]); // remove last from the list Map::remove(&(key - 2)); assert_eq!(Map::iter().collect::>().sorted(), vec![(key - 1, 43)]); // remove the last element Map::remove(&(key - 1)); assert_eq!(Map::iter().collect::>().sorted(), vec![]); }); } #[test] fn double_map_basic_insert_remove_remove_prefix_with_commit_should_work() { let key1 = 17u32; let key2 = 18u32; type DoubleMap = self::pezframe_system::DataDM; let mut e = new_test_ext(); e.execute_with(|| { // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); // get / insert / take 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); }); e.commit_all().unwrap(); e.execute_with(|| { assert!(matches!( DoubleMap::clear_prefix(&key1, u32::max_value(), None), MultiRemovalResults { maybe_cursor: None, backend: 2, unique: 2, loops: 2 } )); 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_basic_insert_remove_remove_prefix_should_work() { new_test_ext().execute_with(|| { let key1 = 17u32; let key2 = 18u32; type DoubleMap = self::pezframe_system::DataDM; // initialized during genesis assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64); // get / insert / take 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); // all in overlay assert!(matches!( DoubleMap::clear_prefix(&key1, u32::max_value(), None), MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } )); // Note this is the incorrect answer (for now), since we are using v2 of // `clear_prefix`. // When we switch to v3, then this will become: // MultiRemovalResults:: { maybe_cursor: None, backend: 0, unique: 2, loops: 2 }, assert!(matches!( DoubleMap::clear_prefix(&key1, u32::max_value(), None), MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 } )); 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() { new_test_ext().execute_with(|| { type DoubleMap = self::pezframe_system::AppendableDM; let key1 = 17u32; let key2 = 18u32; DoubleMap::insert(&key1, &key2, &vec![1]); DoubleMap::append(&key1, &key2, 2); assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2]); }); } #[test] fn double_map_mutate_exists_should_work() { new_test_ext().execute_with(|| { type DoubleMap = self::pezframe_system::DataDM; let (key1, key2) = (11, 13); // mutated DoubleMap::mutate_exists(key1, key2, |v| *v = Some(1)); assert_eq!(DoubleMap::get(&key1, key2), 1); // removed if mutated to `None` DoubleMap::mutate_exists(key1, key2, |v| *v = None); assert!(!DoubleMap::contains_key(&key1, key2)); }); } #[test] fn double_map_try_mutate_exists_should_work() { new_test_ext().execute_with(|| { type DoubleMap = self::pezframe_system::DataDM; type TestResult = Result<(), &'static str>; let (key1, key2) = (11, 13); // mutated if `Ok` assert_ok!(DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult { *v = Some(1); Ok(()) })); assert_eq!(DoubleMap::get(&key1, key2), 1); // no-op if `Err` assert_noop!( DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult { *v = Some(2); Err("nah") }), "nah" ); // removed if mutated to`None` assert_ok!(DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult { *v = None; Ok(()) })); assert!(!DoubleMap::contains_key(&key1, key2)); }); } fn expected_metadata() -> PalletStorageMetadataIR { PalletStorageMetadataIR { prefix: "System", entries: vec![ StorageEntryMetadataIR { name: "Data", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Twox64Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::DeprecatedWithoutNote, }, StorageEntryMetadataIR { name: "OptionLinkedMap", modifier: StorageEntryModifierIR::Optional, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::Deprecated { note: "test", since: None, }, }, StorageEntryMetadataIR { name: "GenericData", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Identity], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::Deprecated { note: "test", since: Some("test"), }, }, StorageEntryMetadataIR { name: "GenericData2", modifier: StorageEntryModifierIR::Optional, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::Deprecated { note: "test", since: None, }, }, StorageEntryMetadataIR { name: "DataDM", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Twox64Concat, StorageHasherIR::Blake2_128Concat], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, StorageEntryMetadataIR { name: "GenericDataDM", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Blake2_128Concat, StorageHasherIR::Identity], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0, 0, 0, 0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, StorageEntryMetadataIR { name: "GenericData2DM", modifier: StorageEntryModifierIR::Optional, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Blake2_128Concat, StorageHasherIR::Twox64Concat], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, StorageEntryMetadataIR { name: "AppendableDM", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Map { hashers: vec![ StorageHasherIR::Blake2_128Concat, StorageHasherIR::Blake2_128Concat, ], key: scale_info::meta_type::<(u32, u32)>(), value: scale_info::meta_type::>(), }, default: vec![0], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Total", modifier: StorageEntryModifierIR::Default, ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<(u32, u32)>()), default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![" Some running total."], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, StorageEntryMetadataIR { name: "Numbers", modifier: StorageEntryModifierIR::Optional, ty: StorageEntryTypeIR::Map { hashers: vec![StorageHasherIR::Twox64Concat], key: scale_info::meta_type::(), value: scale_info::meta_type::(), }, default: vec![0], docs: vec![" Numbers to be added into the total."], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated, }, ], } } #[test] fn store_metadata() { let metadata = Pezpallet::::storage_metadata(); pretty_assertions::assert_eq!(expected_metadata(), metadata); } #[test] fn constant_metadata() { let metadata: Vec = Pezpallet::::pezpallet_constants_metadata(); pretty_assertions::assert_eq!( metadata, vec![pezsp_metadata_ir::PalletConstantMetadataIR { name: "ExampleConstant", ty: scale_info::meta_type::<()>(), value: vec![], docs: vec![], deprecation_info: pezsp_metadata_ir::ItemDeprecationInfoIR::Deprecated { note: "this constant is deprecated", since: None } },] ); } parameter_types! { storage StorageParameter: u64 = 10; } #[test] fn check_storage_parameter_type_works() { TestExternalities::default().execute_with(|| { assert_eq!(pezsp_io::hashing::twox_128(b":StorageParameter:"), StorageParameter::key()); assert_eq!(10, StorageParameter::get()); StorageParameter::set(&300); assert_eq!(300, StorageParameter::get()); }) } #[test] fn derive_partial_eq_no_bound_core_mod() { mod core {} #[derive( crate::PartialEqNoBound, crate::CloneNoBound, crate::DebugNoBound, crate::DefaultNoBound, crate::EqNoBound, )] #[allow(dead_code)] struct Test; }