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

Commit

Permalink
Adds ability to use default hasher in dev_mode for explicit key bin…
Browse files Browse the repository at this point in the history
…ding (#14164)

* Initial setup

* Minor update

* Minor update

* Addresses review comments

* Addresses review comments

* Updates doc

* ".git/.scripts/commands/fmt/fmt.sh"

* Renames file

* Updates path in test

---------

Co-authored-by: command-bot <>
  • Loading branch information
gupnik authored and gpestana committed May 27, 2023
1 parent f18ab13 commit 9dcdd84
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 12 deletions.
3 changes: 2 additions & 1 deletion frame/support/procedural/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,8 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream {
/// storage types. This is equivalent to specifying `#[pallet::unbounded]` on all storage type
/// definitions.
/// * Storage hashers no longer need to be specified and can be replaced by `_`. In dev mode, these
/// will be replaced by `Blake2_128Concat`.
/// will be replaced by `Blake2_128Concat`. In case of explicit key-binding, `Hasher` can simply
/// be ignored when in `dev_mode`.
///
/// Note that the `dev_mode` argument can only be supplied to the `#[pallet]` or
/// `#[frame_support::pallet]` attribute macro that encloses your pallet module. This argument
Expand Down
38 changes: 27 additions & 11 deletions frame/support/procedural/src/pallet/parse/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ fn process_named_generics(
storage: &StorageKind,
args_span: proc_macro2::Span,
args: &[syn::AssocType],
dev_mode: bool,
) -> syn::Result<(Option<StorageGenerics>, Metadata, Option<syn::Type>, bool)> {
let mut parsed = HashMap::<String, syn::AssocType>::new();

Expand All @@ -346,6 +347,14 @@ fn process_named_generics(
parsed.insert(arg.ident.to_string(), arg.clone());
}

let mut map_mandatory_generics = vec!["Key", "Value"];
let mut map_optional_generics = vec!["QueryKind", "OnEmpty", "MaxValues"];
if dev_mode {
map_optional_generics.push("Hasher");
} else {
map_mandatory_generics.push("Hasher");
}

let generics = match storage {
StorageKind::Value => {
check_generics(
Expand All @@ -368,8 +377,8 @@ fn process_named_generics(
StorageKind::Map => {
check_generics(
&parsed,
&["Hasher", "Key", "Value"],
&["QueryKind", "OnEmpty", "MaxValues"],
&map_mandatory_generics,
&map_optional_generics,
"StorageMap",
args_span,
)?;
Expand All @@ -378,7 +387,7 @@ fn process_named_generics(
hasher: parsed
.remove("Hasher")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
key: parsed
.remove("Key")
.map(|binding| binding.ty)
Expand All @@ -395,8 +404,8 @@ fn process_named_generics(
StorageKind::CountedMap => {
check_generics(
&parsed,
&["Hasher", "Key", "Value"],
&["QueryKind", "OnEmpty", "MaxValues"],
&map_mandatory_generics,
&map_optional_generics,
"CountedStorageMap",
args_span,
)?;
Expand All @@ -405,7 +414,7 @@ fn process_named_generics(
hasher: parsed
.remove("Hasher")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
.unwrap_or(syn::Type::Verbatim(quote::quote! { Blake2_128Concat })),
key: parsed
.remove("Key")
.map(|binding| binding.ty)
Expand All @@ -420,10 +429,17 @@ fn process_named_generics(
}
},
StorageKind::DoubleMap => {
let mut double_map_mandatory_generics = vec!["Key1", "Key2", "Value"];
if dev_mode {
map_optional_generics.extend(["Hasher1", "Hasher2"]);
} else {
double_map_mandatory_generics.extend(["Hasher1", "Hasher2"]);
}

check_generics(
&parsed,
&["Hasher1", "Key1", "Hasher2", "Key2", "Value"],
&["QueryKind", "OnEmpty", "MaxValues"],
&double_map_mandatory_generics,
&map_optional_generics,
"StorageDoubleMap",
args_span,
)?;
Expand All @@ -432,15 +448,15 @@ fn process_named_generics(
hasher1: parsed
.remove("Hasher1")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
key1: parsed
.remove("Key1")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
hasher2: parsed
.remove("Hasher2")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
key2: parsed
.remove("Key2")
.map(|binding| binding.ty)
Expand Down Expand Up @@ -619,7 +635,7 @@ fn process_generics(
_ => unreachable!("It is asserted above that all generics are bindings"),
})
.collect::<Vec<_>>();
process_named_generics(&storage_kind, args_span, &args)
process_named_generics(&storage_kind, args_span, &args, dev_mode)
} else {
let msg = "Invalid pallet::storage, invalid generic declaration for storage. Expect only \
type generics or binding generics, e.g. `<Name1 = Gen1, Name2 = Gen2, ..>` or \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#![cfg_attr(not(feature = "std"), no_std)]

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;

// The struct on which we build all of our Pallet logic.
#[pallet::pallet]
pub struct Pallet<T>(_);

// Your Pallet's configuration trait, representing custom external types and interfaces.
#[pallet::config]
pub trait Config: frame_system::Config {}

#[pallet::storage]
type MyStorage<T: Config> = StorageValue<_, Vec<u8>>;

#[pallet::storage]
type MyStorageMap<T: Config> = StorageMap<Key = u32, Value = u64>;

#[pallet::storage]
type MyStorageDoubleMap<T: Config> = StorageDoubleMap<Key1 = u32, Key2 = u64, Value = u64>;

#[pallet::storage]
type MyCountedStorageMap<T: Config> = CountedStorageMap<Key = u32, Value = u64>;

// Your Pallet's internal functions.
impl<T: Config> Pallet<T> {}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: Invalid pallet::storage, cannot find `Hasher` generic, required for `StorageMap`.
--> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:21:43
|
21 | type MyStorageMap<T: Config> = StorageMap<Key = u32, Value = u64>;
| ^

error[E0432]: unresolved import `pallet`
--> tests/pallet_ui/non_dev_mode_storage_map_explicit_key_default_hasher.rs:3:9
|
3 | pub use pallet::*;
| ^^^^^^ help: a similar path exists: `test_pallet::pallet`
9 changes: 9 additions & 0 deletions frame/support/test/tests/pallet_ui/pass/dev_mode_valid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ pub mod pallet {
#[pallet::storage]
type MyCountedStorageMap<T: Config> = CountedStorageMap<_, _, u32, u64>;

#[pallet::storage]
pub type MyStorageMap2<T: Config> = StorageMap<Key = u32, Value = u64>;

#[pallet::storage]
type MyStorageDoubleMap2<T: Config> = StorageDoubleMap<Key1 = u32, Key2 = u64, Value = u64>;

#[pallet::storage]
type MyCountedStorageMap2<T: Config> = CountedStorageMap<Key = u32, Value = u64>;

// Your Pallet's callable functions.
#[pallet::call]
impl<T: Config> Pallet<T> {
Expand Down

0 comments on commit 9dcdd84

Please sign in to comment.