From c73b28f155d4f4c2251ed53cf194e47b0b051fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 9 Jun 2020 01:37:39 +0200 Subject: [PATCH 1/4] Adds support for storage parameter types This pr adds a new parameter types type, the storage parameter types. This parameter type supports loading the value from the storage or returning the given default value. --- frame/support/src/lib.rs | 112 +++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 17 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 471dd72a748df..cf926cf153132 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -84,8 +84,21 @@ pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable}; #[derive(Debug)] pub enum Never {} -/// Macro for easily creating a new implementation of the `Get` trait. If `const` token is used, the -/// rhs of the expression must be `const`-only, and get is implemented as `const`: +/// Create new implementations of the [`Get`](crate::traits::Get) trait. +/// +/// The so-called parameter type can be created in three 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). +/// +/// # Examples /// /// ``` /// # use frame_support::traits::Get; @@ -95,23 +108,27 @@ pub enum Never {} /// /// const FIXED_VALUE: u64 = 10; /// parameter_types! { -/// pub const Argument: u64 = 42 + FIXED_VALUE; -/// pub OtherArgument: u64 = non_const_expression(); +/// pub const Argument: u64 = 42 + FIXED_VALUE; +/// /// Visibility of the type is optional +/// OtherArgument: u64 = non_const_expression(); +/// pub storage StorageArgument: u64 = 5; /// } /// /// trait Config { -/// type Parameter: Get; -/// type OtherParameter: Get; +/// type Parameter: Get; +/// type OtherParameter: Get; +/// type StorageParameter: Get; /// } /// /// struct Runtime; /// impl Config for Runtime { -/// type Parameter = Argument; -/// type OtherParameter = OtherArgument; +/// type Parameter = Argument; +/// type OtherParameter = OtherArgument; +/// type StorageParameter = StorageArgument; /// } /// ``` /// -/// Invalid example: +/// # Invalid example: /// /// ```compile_fail /// # use frame_support::traits::Get; @@ -120,7 +137,7 @@ pub enum Never {} /// fn non_const_expression() -> u64 { 99 } /// /// parameter_types! { -/// pub const Argument: u64 = non_const_expression(); +/// pub const Argument: u64 = non_const_expression(); /// } /// ``` @@ -133,8 +150,8 @@ macro_rules! parameter_types { ) => ( $( #[ $attr ] )* $vis struct $name; - $crate::parameter_types!{IMPL_CONST $name , $type , $value} - $crate::parameter_types!{ $( $rest )* } + $crate::parameter_types!(IMPL_CONST $name , $type , $value); + $crate::parameter_types!( $( $rest )* ); ); ( $( #[ $attr:meta ] )* @@ -143,33 +160,77 @@ macro_rules! parameter_types { ) => ( $( #[ $attr ] )* $vis struct $name; - $crate::parameter_types!{IMPL $name , $type , $value} - $crate::parameter_types!{ $( $rest )* } + $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_CONST $name:ident, $type:ty, $value:expr) => { impl $name { + /// Returns the value of this parameter type. pub const fn get() -> $type { $value } } + impl> $crate::traits::Get for $name { fn get() -> I { I::from($value) } } }; - (IMPL $name:ident , $type:ty , $value:expr) => { + (IMPL $name:ident, $type:ty, $value:expr) => { impl $name { + /// Returns the value of this parameter type. pub fn get() -> $type { $value } } + impl> $crate::traits::Get for $name { fn get() -> I { I::from($value) } } + }; + (IMPL_STORAGE $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the key for this parameter type. + pub fn key() -> &'static [u8] { + concat!(":", stringify!($name), ":").as_bytes() + } + + /// Set the value of this parameter type in the storage. + /// + /// This needs to be executed in an externalities provided + /// environment. + 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. + pub fn get() -> $type { + $crate::storage::unhashed::get(Self::key()).unwrap_or_else(|| $value) + } + } + + impl> $crate::traits::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } } } @@ -316,6 +377,7 @@ mod tests { StorageEntryModifier, DefaultByteGetter, StorageHasher, }; use sp_std::marker::PhantomData; + use sp_io::TestExternalities; pub trait Trait { type BlockNumber: Codec + EncodeLike + Default; @@ -361,7 +423,7 @@ mod tests { type Origin = u32; } - fn new_test_ext() -> sp_io::TestExternalities { + fn new_test_ext() -> TestExternalities { GenesisConfig::default().build_storage().unwrap().into() } @@ -696,4 +758,20 @@ mod tests { let metadata = Module::::storage_metadata(); pretty_assertions::assert_eq!(EXPECTED_METADATA, metadata); } + + parameter_types! { + storage StorageParameter: u64 = 10; + } + + #[test] + fn check_storage_parameter_type_works() { + TestExternalities::default().execute_with(|| { + assert_eq!(b":StorageParameter:", StorageParameter::key()); + + assert_eq!(10, StorageParameter::get()); + + StorageParameter::set(&300); + assert_eq!(300, StorageParameter::get()); + }) + } } From 701bd887541dcf2d49dc28ed991daec7ea0a4ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Tue, 9 Jun 2020 21:56:31 +0200 Subject: [PATCH 2/4] Use twox_128 --- frame/support/src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index cf926cf153132..132a933e8d20f 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -44,7 +44,7 @@ pub use paste; #[doc(hidden)] pub use sp_state_machine::BasicExternalities; #[doc(hidden)] -pub use sp_io::storage::root as storage_root; +pub use sp_io::{storage::root as storage_root, self}; #[doc(hidden)] pub use sp_runtime::RuntimeDebug; @@ -205,8 +205,10 @@ macro_rules! parameter_types { (IMPL_STORAGE $name:ident, $type:ty, $value:expr) => { impl $name { /// Returns the key for this parameter type. - pub fn key() -> &'static [u8] { - concat!(":", stringify!($name), ":").as_bytes() + pub fn key() -> [u8; 16] { + $crate::sp_io::hashing::twox_128( + concat!(":", stringify!($name), ":").as_bytes() + ) } /// Set the value of this parameter type in the storage. @@ -214,7 +216,7 @@ macro_rules! parameter_types { /// This needs to be executed in an externalities provided /// environment. pub fn set(value: &$type) { - $crate::storage::unhashed::put(Self::key(), value); + $crate::storage::unhashed::put(&Self::key(), value); } /// Returns the value of this parameter type. @@ -222,7 +224,7 @@ macro_rules! parameter_types { /// This needs to be executed in an externalities provided /// environment. pub fn get() -> $type { - $crate::storage::unhashed::get(Self::key()).unwrap_or_else(|| $value) + $crate::storage::unhashed::get(&Self::key()).unwrap_or_else(|| $value) } } @@ -766,7 +768,7 @@ mod tests { #[test] fn check_storage_parameter_type_works() { TestExternalities::default().execute_with(|| { - assert_eq!(b":StorageParameter:", StorageParameter::key()); + assert_eq!(sp_io::hashing::twox_128(b":StorageParameter:"), StorageParameter::key()); assert_eq!(10, StorageParameter::get()); From 37c26c857be043b90590256ac1f7559a6569866a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 11 Jun 2020 12:21:55 +0200 Subject: [PATCH 3/4] Update docs --- frame/support/src/lib.rs | 5 ++++- frame/support/src/traits.rs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 132a933e8d20f..42801465a1e92 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -96,7 +96,10 @@ pub enum Never {} /// - 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). +/// [`Encode`](codec::Encode) and [`Decode`](codec::Decode). The key for looking up the value +/// in the storage is build using the following formular: +/// +/// `twox_128(":" ++ NAME ++ ":")` where `NAME` is the name that is passed as type name. /// /// # Examples /// diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index 519164027b721..5199456807e57 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -450,9 +450,11 @@ impl Len for T where ::IntoIter: Ex } } -/// A trait for querying a single fixed value from a type. +/// A trait for querying a single value from a type. +/// +/// It is not required that the value is constant. pub trait Get { - /// Return a constant value. + /// Return the current value. fn get() -> T; } From c4c6c8d287b5440a0dcaf8ef6a21befa4a347c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Thu, 11 Jun 2020 12:49:48 +0200 Subject: [PATCH 4/4] Update frame/support/src/lib.rs Co-authored-by: Alexander Popiak --- frame/support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 42801465a1e92..316e356759a17 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -97,7 +97,7 @@ pub enum Never {} /// 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 build using the following formular: +/// in the storage is built using the following formular: /// /// `twox_128(":" ++ NAME ++ ":")` where `NAME` is the name that is passed as type name. ///