Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Adds support for storage parameter types #6296

Merged
5 commits merged into from
Jun 11, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
bkchr committed Jun 8, 2020
commit c73b28f155d4f4c2251ed53cf194e47b0b051fdf
112 changes: 95 additions & 17 deletions frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be good to mention how the key is generated?

///
/// # Examples
///
/// ```
/// # use frame_support::traits::Get;
Expand All @@ -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<u64>;
/// type OtherParameter: Get<u64>;
/// type Parameter: Get<u64>;
/// type OtherParameter: Get<u64>;
/// type StorageParameter: Get<u64>;
/// }
///
/// 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;
Expand All @@ -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();
/// }
/// ```

Expand All @@ -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 ] )*
Expand All @@ -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<I: From<$type>> $crate::traits::Get<I> 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<I: From<$type>> $crate::traits::Get<I> 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<I: From<$type>> $crate::traits::Get<I> for $name {
fn get() -> I {
I::from(Self::get())
}
}
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
}

Expand Down Expand Up @@ -696,4 +758,20 @@ mod tests {
let metadata = Module::<Test>::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());
})
}
}