diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 40798380f..47842fc5d 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -26,7 +26,8 @@ members = [ "build-script-utils", "weight-gen", "weight-meter", - "payments" + "payments", + "parameters", ] exclude = ["bencher/test"] diff --git a/parameters/Cargo.toml b/parameters/Cargo.toml new file mode 100644 index 000000000..23190f996 --- /dev/null +++ b/parameters/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "orml-parameters" +description = "Offer a centra place to store and configure parameters." +repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/parameters" +license = "Apache-2.0" +version = "0.4.1-dev" +authors = ["Acala Developers"] +edition = "2021" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] } +scale-info = { version = "2.1.2", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true } + +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } +sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } + +orml-traits = { path = "../traits", version = "0.4.1-dev", default-features = false } + +[dev-dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } + +[features] +default = ["std"] +std = [ + "serde", + + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + + "orml-traits/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/parameters/README.md b/parameters/README.md new file mode 100644 index 000000000..8a7fd706f --- /dev/null +++ b/parameters/README.md @@ -0,0 +1,5 @@ +# Parameters Store + +### Overview + +Offer a central place to store and configure parameters. diff --git a/parameters/src/lib.rs b/parameters/src/lib.rs new file mode 100644 index 000000000..8ef2b7137 --- /dev/null +++ b/parameters/src/lib.rs @@ -0,0 +1,102 @@ +//! # Parameters +//! Offer a central place to store and configure parameters. + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::unused_unit)] + +use frame_support::pallet_prelude::*; +use frame_system::pallet_prelude::*; + +use frame_support::traits::EnsureOriginWithArg; +use orml_traits::parameters::{AggregratedKeyValue, Into2, Key, RuntimeParameterStore, TryInto2}; + +mod mock; +mod tests; +mod weights; + +pub use module::*; +pub use weights::WeightInfo; + +#[frame_support::pallet] +pub mod module { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The key value type for parameters. Usually created by + /// orml_traits::parameters::define_aggregrated_parameters + type AggregratedKeyValue: AggregratedKeyValue; + + /// The origin which may update the parameter. + type AdminOrigin: EnsureOriginWithArg>; + + /// Weight information for extrinsics in this module. + type WeightInfo: WeightInfo; + } + + type KeyOf = <::AggregratedKeyValue as AggregratedKeyValue>::AggregratedKey; + type ValueOf = <::AggregratedKeyValue as AggregratedKeyValue>::AggregratedValue; + + #[pallet::error] + pub enum Error {} + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// Parameter is updated + Updated { key_value: T::AggregratedKeyValue }, + } + + /// Stored parameters. + /// + /// map KeyOf => Option> + #[pallet::storage] + pub type Parameters = StorageMap<_, Blake2_128Concat, KeyOf, ValueOf, OptionQuery>; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// Set parameter + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::set_parameter())] + pub fn set_parameter(origin: OriginFor, key_value: T::AggregratedKeyValue) -> DispatchResult { + let (key, value) = key_value.clone().into_parts(); + + T::AdminOrigin::ensure_origin(origin, &key)?; + + Parameters::::mutate(key, |v| *v = value); + + Self::deposit_event(Event::Updated { key_value }); + + Ok(()) + } + } +} + +impl RuntimeParameterStore for Pallet { + type AggregratedKeyValue = T::AggregratedKeyValue; + + fn get(key: K) -> Option + where + KV: AggregratedKeyValue, + K: Key + Into<::AggregratedKey>, + ::AggregratedKey: + Into2<<::AggregratedKeyValue as AggregratedKeyValue>::AggregratedKey>, + <::AggregratedKeyValue as AggregratedKeyValue>::AggregratedValue: + TryInto2<::AggregratedValue>, + ::AggregratedValue: TryInto, + { + let key: ::AggregratedKey = key.into(); + let val = Parameters::::get(key.into2()); + val.and_then(|v| { + let val: ::AggregratedValue = v.try_into2().ok()?; + let val: K::WrappedValue = val.try_into().ok()?; + let val = val.into(); + Some(val) + }) + } +} diff --git a/parameters/src/mock.rs b/parameters/src/mock.rs new file mode 100644 index 000000000..62ab382e9 --- /dev/null +++ b/parameters/src/mock.rs @@ -0,0 +1,121 @@ +#![cfg(test)] + +use frame_support::traits::EnsureOriginWithArg; +use frame_support::{ + construct_runtime, + traits::{ConstU32, ConstU64, Everything}, +}; +use orml_traits::define_aggregrated_parameters; +use sp_core::H256; +use sp_runtime::{traits::IdentityLookup, BuildStorage}; + +use super::*; + +use crate as parameters; + +pub type AccountId = u128; + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +pub mod pallet1 { + orml_traits::define_parameters! { + pub Parameters = { + Key1: u64 = 0, + Key2(u32): u32 = 1, + Key3((u8, u8)): u128 = 2, + } + } +} +pub mod pallet2 { + orml_traits::define_parameters! { + pub Parameters = { + Key1: u64 = 0, + Key2(u32): u32 = 2, + Key3((u8, u8)): u128 = 4, + } + } +} +define_aggregrated_parameters! { + pub RuntimeParameters = { + Pallet1: pallet1::Parameters = 0, + Pallet2: pallet2::Parameters = 3, + } +} + +pub struct EnsureOriginImpl; + +impl EnsureOriginWithArg for EnsureOriginImpl { + type Success = (); + + fn try_origin(origin: RuntimeOrigin, key: &RuntimeParametersKey) -> Result { + match key { + RuntimeParametersKey::Pallet1(_) => { + ensure_root(origin.clone()).map_err(|_| origin)?; + return Ok(()); + } + RuntimeParametersKey::Pallet2(_) => { + ensure_signed(origin.clone()).map_err(|_| origin)?; + return Ok(()); + } + } + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin(_key: &RuntimeParametersKey) -> Result { + Err(()) + } +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type AggregratedKeyValue = RuntimeParameters; + type AdminOrigin = EnsureOriginImpl; + type WeightInfo = (); +} + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + ModuleParameters: parameters, + } +); + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn new() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} diff --git a/parameters/src/tests.rs b/parameters/src/tests.rs new file mode 100644 index 000000000..c0dc7ec8e --- /dev/null +++ b/parameters/src/tests.rs @@ -0,0 +1,74 @@ +//! Unit tests for the non-fungible-token module. + +#![cfg(test)] + +use super::*; +use frame_support::{assert_noop, assert_ok}; +use mock::*; +use orml_traits::parameters::RuntimeParameterStore; + +#[test] +fn set_parameters() { + ExtBuilder::new().execute_with(|| { + assert_eq!( + ::get::(pallet1::Key1), + None + ); + + assert_noop!( + ModuleParameters::set_parameter( + RuntimeOrigin::signed(1), + RuntimeParameters::Pallet1(pallet1::Parameters::Key1(pallet1::Key1, Some(123))), + ), + DispatchError::BadOrigin + ); + + assert_ok!(ModuleParameters::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::Pallet1(pallet1::Parameters::Key1(pallet1::Key1, Some(123))), + )); + + assert_eq!( + ::get::(pallet1::Key1), + Some(123) + ); + + assert_ok!(ModuleParameters::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::Pallet1(pallet1::Parameters::Key2(pallet1::Key2(234), Some(345))), + )); + + assert_eq!( + ::get::(pallet1::Key2(234)), + Some(345) + ); + + assert_eq!( + ::get::(pallet1::Key2(235)), + None + ); + + assert_eq!( + ::get::(pallet2::Key3((1, 2))), + None + ); + + assert_noop!( + ModuleParameters::set_parameter( + RuntimeOrigin::root(), + RuntimeParameters::Pallet2(pallet2::Parameters::Key3(pallet2::Key3((1, 2)), Some(123))), + ), + DispatchError::BadOrigin + ); + + assert_ok!(ModuleParameters::set_parameter( + RuntimeOrigin::signed(1), + RuntimeParameters::Pallet2(pallet2::Parameters::Key3(pallet2::Key3((1, 2)), Some(456))), + )); + + assert_eq!( + ::get::(pallet2::Key3((1, 2))), + Some(456) + ); + }); +} diff --git a/parameters/src/weights.rs b/parameters/src/weights.rs new file mode 100644 index 000000000..4959e4349 --- /dev/null +++ b/parameters/src/weights.rs @@ -0,0 +1,17 @@ +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +pub trait WeightInfo { + fn set_parameter() -> Weight; +} + +impl WeightInfo for () { + fn set_parameter() -> Weight { + RocksDbWeight::get().reads_writes(2, 1) + } +} diff --git a/traits/Cargo.toml b/traits/Cargo.toml index 9003dda33..6eff83b38 100644 --- a/traits/Cargo.toml +++ b/traits/Cargo.toml @@ -13,6 +13,7 @@ serde = { version = "1.0.136", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } num-traits = { version = "0.2.14", default-features = false } impl-trait-for-tuples = "0.2.2" +paste = "1.0" sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 672c58231..3f7bb010a 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -35,6 +35,7 @@ pub mod get_by_key; pub mod location; pub mod multi_asset; pub mod nft; +pub mod parameters; pub mod price; pub mod rewards; pub mod xcm_transfer; diff --git a/traits/src/parameters.rs b/traits/src/parameters.rs new file mode 100644 index 000000000..a3c66b0f1 --- /dev/null +++ b/traits/src/parameters.rs @@ -0,0 +1,545 @@ +#[doc(hidden)] +pub use codec; +#[doc(hidden)] +pub use frame_support; +use frame_support::Parameter; +#[doc(hidden)] +pub use paste; +#[doc(hidden)] +pub use scale_info; + +pub trait RuntimeParameterStore { + type AggregratedKeyValue: AggregratedKeyValue; + + fn get(key: K) -> Option + where + KV: AggregratedKeyValue, + K: Key + Into<::AggregratedKey>, + ::AggregratedKey: + Into2<<::AggregratedKeyValue as AggregratedKeyValue>::AggregratedKey>, + <::AggregratedKeyValue as AggregratedKeyValue>::AggregratedValue: + TryInto2<::AggregratedValue>, + ::AggregratedValue: TryInto; +} + +pub trait Key { + type Value; + type WrappedValue: Into; +} + +pub trait AggregratedKeyValue: Parameter { + type AggregratedKey: Parameter + codec::MaxEncodedLen; + type AggregratedValue: Parameter + codec::MaxEncodedLen; + + fn into_parts(self) -> (Self::AggregratedKey, Option); +} + +pub trait ParameterStore { + fn get(key: K) -> Option + where + K: Key + Into<::AggregratedKey>, + ::AggregratedValue: TryInto; +} + +pub struct ParameterStoreAdapter(sp_std::marker::PhantomData<(PS, KV)>); + +impl ParameterStore for ParameterStoreAdapter +where + PS: RuntimeParameterStore, + KV: AggregratedKeyValue, + ::AggregratedKey: + Into2<<::AggregratedKeyValue as AggregratedKeyValue>::AggregratedKey>, + ::AggregratedValue: + TryFrom2<<::AggregratedKeyValue as AggregratedKeyValue>::AggregratedValue>, +{ + fn get(key: K) -> Option + where + K: Key + Into<::AggregratedKey>, + ::AggregratedValue: TryInto, + { + PS::get::(key) + } +} + +// workaround for rust bug https://github.com/rust-lang/rust/issues/51445 +mod workaround { + pub trait From2: Sized { + #[must_use] + fn from2(value: T) -> Self; + } + + pub trait Into2: Sized { + #[must_use] + fn into2(self) -> T; + } + + impl Into2 for T + where + U: From2, + { + #[inline] + fn into2(self) -> U { + U::from2(self) + } + } + + pub trait TryInto2: Sized { + type Error; + + fn try_into2(self) -> Result; + } + + pub trait TryFrom2: Sized { + type Error; + + fn try_from2(value: T) -> Result; + } + + impl TryInto2 for T + where + U: TryFrom2, + { + type Error = U::Error; + + #[inline] + fn try_into2(self) -> Result { + U::try_from2(self) + } + } +} +pub use workaround::*; + +/// Define parameters key value types. +/// Example: +/// +/// ``` +/// # #[macro_use] +/// # extern crate orml_traits; +/// # fn main() {} +/// define_parameters! { +/// pub Pallet = { +/// Key1: u64 = 0, +/// Key2(u32): u32 = 1, +/// Key3((u8, u8)): u128 = 2, +/// } +/// } +/// ``` +#[macro_export] +macro_rules! define_parameters { + ( + $vis:vis $name:ident = { + $( + $key_name:ident $( ($key_para: ty) )? : $value_type:ty = $index:expr + ),+ $(,)? + } + ) => { + $crate::parameters::paste::item! { + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum $name { + $( + #[codec(index = $index)] + $key_name($key_name, Option<$value_type>), + )* + } + + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum [<$name Key>] { + $( + #[codec(index = $index)] + $key_name($key_name), + )* + } + + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum [<$name Value>] { + $( + #[codec(index = $index)] + $key_name($value_type), + )* + } + + impl $crate::parameters::AggregratedKeyValue for $name { + type AggregratedKey = [<$name Key>]; + type AggregratedValue = [<$name Value>]; + + fn into_parts(self) -> (Self::AggregratedKey, Option) { + match self { + $( + $name::$key_name(key, value) => ([<$name Key>]::$key_name(key), value.map([<$name Value>]::$key_name)), + )* + } + } + } + + $( + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis struct $key_name $( (pub $key_para) )?; + + impl $crate::parameters::Key for $key_name { + type Value = $value_type; + type WrappedValue = [<$key_name Value>]; + } + + impl From<$key_name> for [<$name Key>] { + fn from(key: $key_name) -> Self { + [<$name Key>]::$key_name(key) + } + } + + impl TryFrom<[<$name Key>]> for $key_name { + type Error = (); + + fn try_from(key: [<$name Key>]) -> Result { + match key { + [<$name Key>]::$key_name(key) => Ok(key), + _ => Err(()), + } + } + } + + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::frame_support::RuntimeDebug + )] + $vis struct [<$key_name Value>](pub $value_type); + + impl From<[<$key_name Value>]> for [<$name Value>] { + fn from(value: [<$key_name Value>]) -> Self { + [<$name Value>]::$key_name(value.0) + } + } + + impl From<($key_name, $value_type)> for $name { + fn from((key, value): ($key_name, $value_type)) -> Self { + $name::$key_name(key, Some(value)) + } + } + + impl From<$key_name> for $name { + fn from(key: $key_name) -> Self { + $name::$key_name(key, None) + } + } + + impl TryFrom<[<$name Value>]> for [<$key_name Value>] { + type Error = (); + + fn try_from(value: [<$name Value>]) -> Result { + match value { + [<$name Value>]::$key_name(value) => Ok([<$key_name Value>](value)), + _ => Err(()), + } + } + } + + impl From<[<$key_name Value>]> for $value_type { + fn from(value: [<$key_name Value>]) -> Self { + value.0 + } + } + )* + } + }; +} + +/// Define aggregrated parameters types. +/// +/// Example: +/// ``` +/// # #[macro_use] +/// # extern crate orml_traits; +/// # fn main() {} +/// mod pallet1 { +/// define_parameters! { +/// pub Pallet = { +/// Key1: u64 = 0, +/// Key2(u32): u32 = 1, +/// Key3((u8, u8)): u128 = 2, +/// } +/// } +/// } +/// +/// mod pallet2 { +/// define_parameters! { +/// pub Pallet = { +/// Key1: u64 = 0, +/// Key2(u32): u32 = 1, +/// Key3((u8, u8)): u128 = 2, +/// } +/// } +/// } +/// +/// define_aggregrated_parameters! { +/// pub AggregratedPallet = { +/// Pallet1: pallet1::Pallet = 0, +/// Pallet2: pallet2::Pallet = 1, +/// } +/// } +/// ``` +#[macro_export] +macro_rules! define_aggregrated_parameters { + ( + $vis:vis $name:ident = { + $( + $parameter_name:ident: $parameter_type:ty = $index:expr + ),+ $(,)? + } + ) => { + $crate::parameters::paste::item! { + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum $name { + $( + #[codec(index = $index)] + $parameter_name($parameter_type), + )* + } + + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum [<$name Key>] { + $( + #[codec(index = $index)] + $parameter_name(<$parameter_type as $crate::parameters::AggregratedKeyValue>::AggregratedKey), + )* + } + + #[derive( + Clone, + PartialEq, + Eq, + $crate::parameters::codec::Encode, + $crate::parameters::codec::Decode, + $crate::parameters::codec::MaxEncodedLen, + $crate::parameters::frame_support::RuntimeDebug, + $crate::parameters::scale_info::TypeInfo + )] + $vis enum [<$name Value>] { + $( + #[codec(index = $index)] + $parameter_name(<$parameter_type as $crate::parameters::AggregratedKeyValue>::AggregratedValue), + )* + } + + impl $crate::parameters::AggregratedKeyValue for $name { + type AggregratedKey = [<$name Key>]; + type AggregratedValue = [<$name Value>]; + + fn into_parts(self) -> (Self::AggregratedKey, Option) { + match self { + $( + $name::$parameter_name(parameter) => { + let (key, value) = parameter.into_parts(); + ([<$name Key>]::$parameter_name(key), value.map([<$name Value>]::$parameter_name)) + }, + )* + } + } + } + + $( + impl $crate::parameters::From2<<$parameter_type as $crate::parameters::AggregratedKeyValue>::AggregratedKey> for [<$name Key>] { + fn from2(key: <$parameter_type as $crate::parameters::AggregratedKeyValue>::AggregratedKey) -> Self { + [<$name Key>]::$parameter_name(key) + } + } + + impl $crate::parameters::TryFrom2<[<$name Value>]> for <$parameter_type as $crate::parameters::AggregratedKeyValue>::AggregratedValue { + type Error = (); + + fn try_from2(value: [<$name Value>]) -> Result { + match value { + [<$name Value>]::$parameter_name(value) => Ok(value), + _ => Err(()), + } + } + } + )* + } + }; +} + +#[cfg(test)] +mod tests { + pub mod pallet1 { + define_parameters! { + pub Parameters = { + Key1: u64 = 0, + Key2(u32): u32 = 1, + Key3((u8, u8)): u128 = 2, + } + } + } + pub mod pallet2 { + define_parameters! { + pub Parameters = { + Key1: u64 = 0, + Key2(u32): u32 = 2, + Key3((u8, u8)): u128 = 4, + } + } + } + define_aggregrated_parameters! { + pub RuntimeParameters = { + Pallet1: pallet1::Parameters = 0, + Pallet2: pallet2::Parameters = 3, + } + } + + #[test] + fn test_define_parameters_key_convert() { + let key1 = pallet1::Key1; + let parameter_key: pallet1::ParametersKey = key1.clone().into(); + let key1_2: pallet1::Key1 = parameter_key.clone().try_into().unwrap(); + + assert_eq!(key1, key1_2); + assert_eq!(parameter_key, pallet1::ParametersKey::Key1(key1)); + + let key2 = pallet1::Key2(1); + let parameter_key: pallet1::ParametersKey = key2.clone().into(); + let key2_2: pallet1::Key2 = parameter_key.clone().try_into().unwrap(); + + assert_eq!(key2, key2_2); + assert_eq!(parameter_key, pallet1::ParametersKey::Key2(key2)); + } + + #[test] + fn test_define_parameters_value_convert() { + let value1 = pallet1::Key1Value(1); + let parameter_value: pallet1::ParametersValue = value1.clone().into(); + let value1_2: pallet1::Key1Value = parameter_value.clone().try_into().unwrap(); + + assert_eq!(value1, value1_2); + assert_eq!(parameter_value, pallet1::ParametersValue::Key1(1)); + + let value2 = pallet1::Key2Value(2); + let parameter_value: pallet1::ParametersValue = value2.clone().into(); + let value2_2: pallet1::Key2Value = parameter_value.clone().try_into().unwrap(); + + assert_eq!(value2, value2_2); + assert_eq!(parameter_value, pallet1::ParametersValue::Key2(2)); + } + + #[test] + fn test_define_parameters_aggregrated_key_value() { + use crate::parameters::AggregratedKeyValue; + + let kv1 = pallet1::Parameters::Key1(pallet1::Key1, None); + let (key1, value1) = kv1.clone().into_parts(); + + assert_eq!(key1, pallet1::ParametersKey::Key1(pallet1::Key1)); + assert_eq!(value1, None); + + let kv2 = pallet1::Parameters::Key2(pallet1::Key2(1), Some(2)); + let (key2, value2) = kv2.clone().into_parts(); + + assert_eq!(key2, pallet1::ParametersKey::Key2(pallet1::Key2(1))); + assert_eq!(value2, Some(pallet1::ParametersValue::Key2(2))); + } + + #[test] + fn test_define_aggregrated_parameters_key_convert() { + use crate::parameters::workaround::Into2; + use codec::Encode; + + let key1 = pallet1::Key1; + let parameter_key: pallet1::ParametersKey = key1.clone().into(); + let runtime_key: RuntimeParametersKey = parameter_key.clone().into2(); + + assert_eq!( + runtime_key, + RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key1(key1)) + ); + assert_eq!(runtime_key.encode(), vec![0, 0]); + + let key2 = pallet2::Key2(1); + let parameter_key: pallet2::ParametersKey = key2.clone().into(); + let runtime_key: RuntimeParametersKey = parameter_key.clone().into2(); + + assert_eq!( + runtime_key, + RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key2(key2)) + ); + assert_eq!(runtime_key.encode(), vec![3, 2, 1, 0, 0, 0]); + } + + #[test] + fn test_define_aggregrated_parameters_aggregrated_key_value() { + use crate::parameters::AggregratedKeyValue; + + let kv1 = RuntimeParameters::Pallet1(pallet1::Parameters::Key1(pallet1::Key1, None)); + let (key1, value1) = kv1.clone().into_parts(); + + assert_eq!( + key1, + RuntimeParametersKey::Pallet1(pallet1::ParametersKey::Key1(pallet1::Key1)) + ); + assert_eq!(value1, None); + + let kv2 = RuntimeParameters::Pallet2(pallet2::Parameters::Key2(pallet2::Key2(1), Some(2))); + let (key2, value2) = kv2.clone().into_parts(); + + assert_eq!( + key2, + RuntimeParametersKey::Pallet2(pallet2::ParametersKey::Key2(pallet2::Key2(1))) + ); + assert_eq!( + value2, + Some(RuntimeParametersValue::Pallet2(pallet2::ParametersValue::Key2(2))) + ); + } +}