CountedNMap implementation (#10621)

* add initial CountedDoubleMap implementation

* extend CountedDoubleMap functionality

* add some traits implementation for CountedStorageDoubleMap

* add basic tests for CountedStorageDoubleMap

* add mutate functions implementation

* add additional tests

* add test_option_query test

* add try_append_decode_len_works, append_decode_len_works tests

* add migrate_keys_works, translate_values tests

* add test_iter_drain_translate test

* add test_metadata test

* add remove_prefix implementation,  add test_iter_drain_prefix test

* update

* refactor PrefixIterator usage

* Fix CI build

* fix storage_ensure_span_are_ok_wrong_gen.rs storage_ensure_span_are_ok_wrong_gen_unnamed.rs

* add counted_nmap implementation

* add tests, fixes

* remove counted double map impl

* fix metadata checks

* update clear func

* fix clear, clear with prefix

* fix set function

* update

* final fix

* Update frame/support/src/storage/types/counted_nmap.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Update frame/support/src/storage/types/counted_nmap.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* Update frame/support/src/storage/types/counted_nmap.rs

Co-authored-by: Anton <anton.kalyaev@gmail.com>

* fix comments

* fix suggestion

* cargo update

* Relocate impl of Sealed for Ref to module root

* fix StorageEntryMetadata type

* Update frame/support/src/storage/types/nmap.rs

Co-authored-by: Guillaume Yu Thiolliere <gui.thiolliere@gmail.com>

* removed StorageNMap and StoragePrefixedMap traits impl

* fix tests

* Update frame/support/src/storage/types/counted_nmap.rs

Co-authored-by: Guillaume Yu Thiolliere <gui.thiolliere@gmail.com>

* extend pallet::storage macro with CountedStorageNMap usage

* fix

* add tests

* fix

* fix

* Add counter_storage_final_key(), map_storage_final_prefix() functions

* update tests

* fix

* fix

* fix

* update tests

* fix fmt

* fix fmt

---------

Co-authored-by: Anton <anton.kalyaev@gmail.com>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Guillaume Yu Thiolliere <gui.thiolliere@gmail.com>
Co-authored-by: parity-processbot <>
This commit is contained in:
Alex Pozhylenkov
2023-08-04 18:06:08 +03:00
committed by GitHub
parent 08f680e281
commit ef0238dd29
11 changed files with 1840 additions and 59 deletions
@@ -194,18 +194,7 @@ pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMet
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value)); let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty)); args.args.push(syn::GenericArgument::Type(on_empty));
}, },
StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } => { StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } |
args.args.push(syn::GenericArgument::Type(hasher));
args.args.push(syn::GenericArgument::Type(key));
args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
set_result_query_type_parameter(&mut query_kind)?;
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty));
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
args.args.push(syn::GenericArgument::Type(max_values));
},
StorageGenerics::CountedMap { StorageGenerics::CountedMap {
hasher, hasher,
key, key,
@@ -248,7 +237,14 @@ pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMet
let max_values = max_values.unwrap_or_else(|| default_max_values.clone()); let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
args.args.push(syn::GenericArgument::Type(max_values)); args.args.push(syn::GenericArgument::Type(max_values));
}, },
StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } => { StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } |
StorageGenerics::CountedNMap {
keygen,
value,
query_kind,
on_empty,
max_values,
} => {
args.args.push(syn::GenericArgument::Type(keygen)); args.args.push(syn::GenericArgument::Type(keygen));
args.args.push(syn::GenericArgument::Type(value.clone())); args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone()); let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
@@ -265,7 +261,7 @@ pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMet
let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata { let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata {
Metadata::Value { .. } => (1, 2, 3), Metadata::Value { .. } => (1, 2, 3),
Metadata::NMap { .. } => (2, 3, 4), Metadata::NMap { .. } | Metadata::CountedNMap { .. } => (2, 3, 4),
Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5), Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5),
Metadata::DoubleMap { .. } => (5, 6, 7), Metadata::DoubleMap { .. } => (5, 6, 7),
}; };
@@ -359,6 +355,17 @@ fn augment_final_docs(def: &mut Def) {
); );
push_string_literal(&doc_line, storage); push_string_literal(&doc_line, storage);
}, },
Metadata::CountedNMap { keys, value, .. } => {
let doc_line = format!(
"Storage type is [`CountedStorageNMap`] with keys type ({}) and value type {}.",
keys.iter()
.map(|k| k.to_token_stream().to_string())
.collect::<Vec<_>>()
.join(", "),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::CountedMap { key, value } => { Metadata::CountedMap { key, value } => {
let doc_line = format!( let doc_line = format!(
"Storage type is [`CountedStorageMap`] with key type {} and value type {}.", "Storage type is [`CountedStorageMap`] with key type {} and value type {}.",
@@ -579,6 +586,36 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
} }
) )
}, },
Metadata::CountedNMap { keygen, value, .. } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg>(key: KArg) -> #query
where
KArg: #frame_support::storage::types::EncodeLikeTuple<
<#keygen as #frame_support::storage::types::KeyGenerator>::KArg
>
+ #frame_support::storage::types::TupleToEncodedIter,
{
// NOTE: we can't use any trait here because CountedStorageNMap
// doesn't implement any.
<#full_ident>::get(key)
}
}
)
},
} }
} else { } else {
Default::default() Default::default()
@@ -595,40 +632,72 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
let cfg_attrs = &storage_def.cfg_attrs; let cfg_attrs = &storage_def.cfg_attrs;
let maybe_counter = if let Metadata::CountedMap { .. } = storage_def.metadata { let maybe_counter = match storage_def.metadata {
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident); Metadata::CountedMap { .. } => {
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const); let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span => quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)* #(#cfg_attrs)*
#[doc(hidden)] #[doc(hidden)]
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>( #prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)> core::marker::PhantomData<(#type_use_gen,)>
); );
#(#cfg_attrs)* #(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::traits::StorageInstance impl<#type_impl_gen> #frame_support::traits::StorageInstance
for #counter_prefix_struct_ident<#type_use_gen> for #counter_prefix_struct_ident<#type_use_gen>
#config_where_clause #config_where_clause
{ {
fn pallet_prefix() -> &'static str { fn pallet_prefix() -> &'static str {
< <
<T as #frame_system::Config>::PalletInfo <T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo as #frame_support::traits::PalletInfo
>::name::<Pallet<#type_use_gen>>() >::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.") .expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
} }
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const; #(#cfg_attrs)*
} impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance
#(#cfg_attrs)* for #prefix_struct_ident<#type_use_gen>
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance #config_where_clause
for #prefix_struct_ident<#type_use_gen> {
#config_where_clause type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
{ }
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>; )
} },
) Metadata::CountedNMap { .. } => {
} else { let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
proc_macro2::TokenStream::default() let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)*
#[doc(hidden)]
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)>
);
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::traits::StorageInstance
for #counter_prefix_struct_ident<#type_use_gen>
#config_where_clause
{
fn pallet_prefix() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
}
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageNMapInstance
for #prefix_struct_ident<#type_use_gen>
#config_where_clause
{
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
}
)
},
_ => proc_macro2::TokenStream::default(),
}; };
quote::quote_spanned!(storage_def.attr_span => quote::quote_spanned!(storage_def.attr_span =>
@@ -138,6 +138,7 @@ pub enum Metadata {
CountedMap { value: syn::Type, key: syn::Type }, CountedMap { value: syn::Type, key: syn::Type },
DoubleMap { value: syn::Type, key1: syn::Type, key2: syn::Type }, DoubleMap { value: syn::Type, key1: syn::Type, key2: syn::Type },
NMap { keys: Vec<syn::Type>, keygen: syn::Type, value: syn::Type }, NMap { keys: Vec<syn::Type>, keygen: syn::Type, value: syn::Type },
CountedNMap { keys: Vec<syn::Type>, keygen: syn::Type, value: syn::Type },
} }
pub enum QueryKind { pub enum QueryKind {
@@ -230,6 +231,13 @@ pub enum StorageGenerics {
on_empty: Option<syn::Type>, on_empty: Option<syn::Type>,
max_values: Option<syn::Type>, max_values: Option<syn::Type>,
}, },
CountedNMap {
keygen: syn::Type,
value: syn::Type,
query_kind: Option<syn::Type>,
on_empty: Option<syn::Type>,
max_values: Option<syn::Type>,
},
} }
impl StorageGenerics { impl StorageGenerics {
@@ -242,6 +250,8 @@ impl StorageGenerics {
Self::Value { value, .. } => Metadata::Value { value }, Self::Value { value, .. } => Metadata::Value { value },
Self::NMap { keygen, value, .. } => Self::NMap { keygen, value, .. } =>
Metadata::NMap { keys: collect_keys(&keygen)?, keygen, value }, Metadata::NMap { keys: collect_keys(&keygen)?, keygen, value },
Self::CountedNMap { keygen, value, .. } =>
Metadata::CountedNMap { keys: collect_keys(&keygen)?, keygen, value },
}; };
Ok(res) Ok(res)
@@ -254,7 +264,8 @@ impl StorageGenerics {
Self::Map { query_kind, .. } | Self::Map { query_kind, .. } |
Self::CountedMap { query_kind, .. } | Self::CountedMap { query_kind, .. } |
Self::Value { query_kind, .. } | Self::Value { query_kind, .. } |
Self::NMap { query_kind, .. } => query_kind.clone(), Self::NMap { query_kind, .. } |
Self::CountedNMap { query_kind, .. } => query_kind.clone(),
} }
} }
} }
@@ -265,6 +276,7 @@ enum StorageKind {
CountedMap, CountedMap,
DoubleMap, DoubleMap,
NMap, NMap,
CountedNMap,
} }
/// Check the generics in the `map` contains the generics in `gen` may contains generics in /// Check the generics in the `map` contains the generics in `gen` may contains generics in
@@ -493,6 +505,29 @@ fn process_named_generics(
max_values: parsed.remove("MaxValues").map(|binding| binding.ty), max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
} }
}, },
StorageKind::CountedNMap => {
check_generics(
&parsed,
&["Key", "Value"],
&["QueryKind", "OnEmpty", "MaxValues"],
"CountedStorageNMap",
args_span,
)?;
StorageGenerics::CountedNMap {
keygen: parsed
.remove("Key")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
value: parsed
.remove("Value")
.map(|binding| binding.ty)
.expect("checked above as mandatory generic"),
query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
}
},
}; };
let metadata = generics.metadata()?; let metadata = generics.metadata()?;
@@ -578,6 +613,16 @@ fn process_unnamed_generics(
false, false,
) )
}, },
StorageKind::CountedNMap => {
let keygen = retrieve_arg(1)?;
let keys = collect_keys(&keygen)?;
(
None,
Metadata::CountedNMap { keys, keygen, value: retrieve_arg(2)? },
retrieve_arg(3).ok(),
false,
)
},
}; };
Ok(res) Ok(res)
@@ -594,10 +639,11 @@ fn process_generics(
"CountedStorageMap" => StorageKind::CountedMap, "CountedStorageMap" => StorageKind::CountedMap,
"StorageDoubleMap" => StorageKind::DoubleMap, "StorageDoubleMap" => StorageKind::DoubleMap,
"StorageNMap" => StorageKind::NMap, "StorageNMap" => StorageKind::NMap,
"CountedStorageNMap" => StorageKind::CountedNMap,
found => { found => {
let msg = format!( let msg = format!(
"Invalid pallet::storage, expected ident: `StorageValue` or \ "Invalid pallet::storage, expected ident: `StorageValue` or \
`StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` \ `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` or `CountedStorageNMap` \
in order to expand metadata, found `{}`.", in order to expand metadata, found `{}`.",
found, found,
); );
+2 -2
View File
@@ -1545,8 +1545,8 @@ pub mod pallet_prelude {
storage::{ storage::{
bounded_vec::BoundedVec, bounded_vec::BoundedVec,
types::{ types::{
CountedStorageMap, Key as NMapKey, OptionQuery, ResultQuery, StorageDoubleMap, CountedStorageMap, CountedStorageNMap, Key as NMapKey, OptionQuery, ResultQuery,
StorageMap, StorageNMap, StorageValue, ValueQuery, StorageDoubleMap, StorageMap, StorageNMap, StorageValue, ValueQuery,
}, },
StorageList, StorageList,
}, },
@@ -1428,6 +1428,7 @@ mod private {
impl<K, V, S> Sealed for bounded_btree_map::BoundedBTreeMap<K, V, S> {} impl<K, V, S> Sealed for bounded_btree_map::BoundedBTreeMap<K, V, S> {}
impl<T, S> Sealed for bounded_btree_set::BoundedBTreeSet<T, S> {} impl<T, S> Sealed for bounded_btree_set::BoundedBTreeSet<T, S> {}
impl<T: Encode> Sealed for BTreeSet<T> {} impl<T: Encode> Sealed for BTreeSet<T> {}
impl<'a, T: EncodeLike<U>, U: Encode> Sealed for codec::Ref<'a, T, U> {}
macro_rules! impl_sealed_for_tuple { macro_rules! impl_sealed_for_tuple {
($($elem:ident),+) => { ($($elem:ident),+) => {
@@ -612,8 +612,9 @@ mod test {
assert_eq!(A::count(), 2); assert_eq!(A::count(), 2);
// Insert an existing key, shouldn't increment counted values. // Insert an existing key, shouldn't increment counted values.
A::insert(3, 11); A::insert(3, 12);
assert_eq!(A::try_get(3), Ok(12));
assert_eq!(A::count(), 2); assert_eq!(A::count(), 2);
// Remove non-existing. // Remove non-existing.
@@ -706,17 +707,17 @@ mod test {
// Try succeed mutate existing to existing. // Try succeed mutate existing to existing.
A::try_mutate_exists(1, |query| { A::try_mutate_exists(1, |query| {
assert_eq!(*query, Some(43)); assert_eq!(*query, Some(43));
*query = Some(43); *query = Some(45);
Result::<(), ()>::Ok(()) Result::<(), ()>::Ok(())
}) })
.unwrap(); .unwrap();
assert_eq!(A::try_get(1), Ok(43)); assert_eq!(A::try_get(1), Ok(45));
assert_eq!(A::count(), 4); assert_eq!(A::count(), 4);
// Try succeed mutate existing to non-existing. // Try succeed mutate existing to non-existing.
A::try_mutate_exists(1, |query| { A::try_mutate_exists(1, |query| {
assert_eq!(*query, Some(43)); assert_eq!(*query, Some(45));
*query = None; *query = None;
Result::<(), ()>::Ok(()) Result::<(), ()>::Ok(())
}) })
File diff suppressed because it is too large Load Diff
@@ -37,7 +37,7 @@ pub struct Key<Hasher, KeyType>(core::marker::PhantomData<(Hasher, KeyType)>);
/// A trait that contains the current key as an associated type. /// A trait that contains the current key as an associated type.
pub trait KeyGenerator { pub trait KeyGenerator {
type Key: EncodeLike<Self::Key> + StaticTypeInfo; type Key: EncodeLike<Self::Key> + StaticTypeInfo;
type KArg: Encode; type KArg: Encode + EncodeLike<Self::KArg>;
type HashFn: FnOnce(&[u8]) -> Vec<u8>; type HashFn: FnOnce(&[u8]) -> Vec<u8>;
type HArg; type HArg;
@@ -196,6 +196,11 @@ impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q); impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q);
impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R); impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R);
impl<'a, T: EncodeLike<U> + EncodeLikeTuple<U>, U: Encode> EncodeLikeTuple<U>
for codec::Ref<'a, T, U>
{
}
/// Trait to indicate that a tuple can be converted into an iterator of a vector of encoded bytes. /// Trait to indicate that a tuple can be converted into an iterator of a vector of encoded bytes.
pub trait TupleToEncodedIter { pub trait TupleToEncodedIter {
fn to_encoded_iter(&self) -> sp_std::vec::IntoIter<Vec<u8>>; fn to_encoded_iter(&self) -> sp_std::vec::IntoIter<Vec<u8>>;
@@ -215,6 +220,15 @@ impl<T: TupleToEncodedIter> TupleToEncodedIter for &T {
} }
} }
impl<'a, T: EncodeLike<U> + TupleToEncodedIter, U: Encode> TupleToEncodedIter
for codec::Ref<'a, T, U>
{
fn to_encoded_iter(&self) -> sp_std::vec::IntoIter<Vec<u8>> {
use core::ops::Deref as _;
self.deref().to_encoded_iter()
}
}
/// A trait that indicates the hashers for the keys generated are all reversible. /// A trait that indicates the hashers for the keys generated are all reversible.
pub trait ReversibleKeyGenerator: KeyGenerator { pub trait ReversibleKeyGenerator: KeyGenerator {
type ReversibleHasher; type ReversibleHasher;
@@ -23,6 +23,7 @@ use codec::FullCodec;
use sp_std::prelude::*; use sp_std::prelude::*;
mod counted_map; mod counted_map;
mod counted_nmap;
mod double_map; mod double_map;
mod key; mod key;
mod map; mod map;
@@ -30,6 +31,7 @@ mod nmap;
mod value; mod value;
pub use counted_map::{CountedStorageMap, CountedStorageMapInstance}; pub use counted_map::{CountedStorageMap, CountedStorageMapInstance};
pub use counted_nmap::{CountedStorageNMap, CountedStorageNMapInstance};
pub use double_map::StorageDoubleMap; pub use double_map::StorageDoubleMap;
pub use key::{ pub use key::{
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator,
@@ -15,8 +15,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//! Storage map type. Implements StorageDoubleMap, StorageIterableDoubleMap, //! Storage n-map type. Particularly implements `StorageNMap` and `StoragePrefixedMap`
//! StoragePrefixedDoubleMap traits and their methods directly. //! traits and their methods directly.
use crate::{ use crate::{
metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR}, metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR},
@@ -368,6 +368,27 @@ pub mod pallet {
ResultQuery<Error<T>::NonExistentStorageValue>, ResultQuery<Error<T>::NonExistentStorageValue>,
>; >;
#[pallet::storage]
#[pallet::getter(fn counted_nmap)]
pub type CountedNMap<T> = CountedStorageNMap<_, storage::Key<Blake2_128Concat, u8>, u32>;
#[pallet::storage]
#[pallet::getter(fn counted_nmap2)]
pub type CountedNMap2<T> = CountedStorageNMap<
Key = (NMapKey<Twox64Concat, u16>, NMapKey<Blake2_128Concat, u32>),
Value = u64,
MaxValues = ConstU32<11>,
>;
#[pallet::storage]
#[pallet::getter(fn counted_nmap3)]
pub type CountedNMap3<T> = CountedStorageNMap<
_,
(NMapKey<Blake2_128Concat, u8>, NMapKey<Twox64Concat, u16>),
u128,
ResultQuery<Error<T>::NonExistentStorageValue>,
>;
#[pallet::storage] #[pallet::storage]
#[pallet::getter(fn conditional_value)] #[pallet::getter(fn conditional_value)]
#[cfg(feature = "frame-feature-testing")] #[cfg(feature = "frame-feature-testing")]
@@ -391,6 +412,15 @@ pub mod pallet {
pub type ConditionalNMap<T> = pub type ConditionalNMap<T> =
StorageNMap<_, (storage::Key<Blake2_128Concat, u8>, storage::Key<Twox64Concat, u16>), u32>; StorageNMap<_, (storage::Key<Blake2_128Concat, u8>, storage::Key<Twox64Concat, u16>), u32>;
#[cfg(feature = "frame-feature-testing")]
#[pallet::storage]
#[pallet::getter(fn conditional_counted_nmap)]
pub type ConditionalCountedNMap<T> = CountedStorageNMap<
_,
(storage::Key<Blake2_128Concat, u8>, storage::Key<Twox64Concat, u16>),
u32,
>;
#[pallet::storage] #[pallet::storage]
#[pallet::storage_prefix = "RenamedCountedMap"] #[pallet::storage_prefix = "RenamedCountedMap"]
#[pallet::getter(fn counted_storage_map)] #[pallet::getter(fn counted_storage_map)]
@@ -1125,6 +1155,7 @@ fn storage_expand() {
k.extend(2u32.using_encoded(blake2_128_concat)); k.extend(2u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u64>(&k), Some(3u64)); assert_eq!(unhashed::get::<u64>(&k), Some(3u64));
assert_eq!(&k[..32], &<pallet::NMap2<Runtime>>::final_prefix()); assert_eq!(&k[..32], &<pallet::NMap2<Runtime>>::final_prefix());
assert_eq!(pallet::Pallet::<Runtime>::nmap2((1, 2)), Some(3u64));
pallet::NMap3::<Runtime>::insert((&1, &2), &3); pallet::NMap3::<Runtime>::insert((&1, &2), &3);
let mut k = [twox_128(b"Example"), twox_128(b"NMap3")].concat(); let mut k = [twox_128(b"Example"), twox_128(b"NMap3")].concat();
@@ -1132,11 +1163,56 @@ fn storage_expand() {
k.extend(2u16.using_encoded(twox_64_concat)); k.extend(2u16.using_encoded(twox_64_concat));
assert_eq!(unhashed::get::<u128>(&k), Some(3u128)); assert_eq!(unhashed::get::<u128>(&k), Some(3u128));
assert_eq!(&k[..32], &<pallet::NMap3<Runtime>>::final_prefix()); assert_eq!(&k[..32], &<pallet::NMap3<Runtime>>::final_prefix());
assert_eq!(pallet::Pallet::<Runtime>::nmap3((1, 2)), Ok(3u128));
assert_eq!( assert_eq!(
pallet::NMap3::<Runtime>::get((2, 3)), pallet::NMap3::<Runtime>::get((2, 3)),
Err(pallet::Error::<Runtime>::NonExistentStorageValue), Err(pallet::Error::<Runtime>::NonExistentStorageValue),
); );
pallet::CountedNMap::<Runtime>::insert((&1,), &3);
let mut k = [twox_128(b"Example"), twox_128(b"CountedNMap")].concat();
k.extend(1u8.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
assert_eq!(pallet::CountedNMap::<Runtime>::count(), 1);
assert_eq!(
unhashed::get::<u32>(
&[twox_128(b"Example"), twox_128(b"CounterForCountedNMap")].concat()
),
Some(1u32)
);
pallet::CountedNMap2::<Runtime>::insert((&1, &2), &3);
let mut k = [twox_128(b"Example"), twox_128(b"CountedNMap2")].concat();
k.extend(1u16.using_encoded(twox_64_concat));
k.extend(2u32.using_encoded(blake2_128_concat));
assert_eq!(unhashed::get::<u64>(&k), Some(3u64));
assert_eq!(pallet::CountedNMap2::<Runtime>::count(), 1);
assert_eq!(
unhashed::get::<u32>(
&[twox_128(b"Example"), twox_128(b"CounterForCountedNMap2")].concat()
),
Some(1u32)
);
assert_eq!(pallet::Pallet::<Runtime>::counted_nmap2((1, 2)), Some(3u64));
pallet::CountedNMap3::<Runtime>::insert((&1, &2), &3);
let mut k = [twox_128(b"Example"), twox_128(b"CountedNMap3")].concat();
k.extend(1u8.using_encoded(blake2_128_concat));
k.extend(2u16.using_encoded(twox_64_concat));
assert_eq!(pallet::CountedNMap3::<Runtime>::count(), 1);
assert_eq!(unhashed::get::<u128>(&k), Some(3u128));
assert_eq!(pallet::Pallet::<Runtime>::counted_nmap3((1, 2)), Ok(3u128));
assert_eq!(
pallet::CountedNMap3::<Runtime>::get((2, 3)),
Err(pallet::Error::<Runtime>::NonExistentStorageValue),
);
assert_eq!(
unhashed::get::<u32>(
&[twox_128(b"Example"), twox_128(b"CounterForCountedNMap3")].concat()
),
Some(1u32)
);
#[cfg(feature = "frame-feature-testing")] #[cfg(feature = "frame-feature-testing")]
{ {
pallet::ConditionalValue::<Runtime>::put(1); pallet::ConditionalValue::<Runtime>::put(1);
@@ -1457,6 +1533,66 @@ fn metadata() {
default: vec![1, 1], default: vec![1, 1],
docs: vec![], docs: vec![],
}, },
StorageEntryMetadata {
name: "CountedNMap",
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
key: meta_type::<u8>(),
hashers: vec![StorageHasher::Blake2_128Concat],
value: meta_type::<u32>(),
},
default: vec![0],
docs: vec![],
},
StorageEntryMetadata {
name: "CounterForCountedNMap",
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Plain(meta_type::<u32>()),
default: vec![0, 0, 0, 0],
docs: maybe_docs(vec!["Counter for the related counted storage map"]),
},
StorageEntryMetadata {
name: "CountedNMap2",
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
key: meta_type::<(u16, u32)>(),
hashers: vec![
StorageHasher::Twox64Concat,
StorageHasher::Blake2_128Concat,
],
value: meta_type::<u64>(),
},
default: vec![0],
docs: vec![],
},
StorageEntryMetadata {
name: "CounterForCountedNMap2",
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Plain(meta_type::<u32>()),
default: vec![0, 0, 0, 0],
docs: maybe_docs(vec!["Counter for the related counted storage map"]),
},
StorageEntryMetadata {
name: "CountedNMap3",
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
key: meta_type::<(u8, u16)>(),
hashers: vec![
StorageHasher::Blake2_128Concat,
StorageHasher::Twox64Concat,
],
value: meta_type::<u128>(),
},
default: vec![1, 1],
docs: vec![],
},
StorageEntryMetadata {
name: "CounterForCountedNMap3",
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Plain(meta_type::<u32>()),
default: vec![0, 0, 0, 0],
docs: maybe_docs(vec!["Counter for the related counted storage map"]),
},
#[cfg(feature = "frame-feature-testing")] #[cfg(feature = "frame-feature-testing")]
StorageEntryMetadata { StorageEntryMetadata {
name: "ConditionalValue", name: "ConditionalValue",
@@ -1507,6 +1643,29 @@ fn metadata() {
default: vec![0], default: vec![0],
docs: vec![], docs: vec![],
}, },
#[cfg(feature = "frame-feature-testing")]
StorageEntryMetadata {
name: "ConditionalCountedNMap",
modifier: StorageEntryModifier::Optional,
ty: StorageEntryType::Map {
key: meta_type::<(u8, u16)>(),
hashers: vec![
StorageHasher::Blake2_128Concat,
StorageHasher::Twox64Concat,
],
value: meta_type::<u32>(),
},
default: vec![0],
docs: vec![],
},
#[cfg(feature = "frame-feature-testing")]
StorageEntryMetadata {
name: "CounterForConditionalCountedNMap",
modifier: StorageEntryModifier::Default,
ty: StorageEntryType::Plain(meta_type::<u32>()),
default: vec![0, 0, 0, 0],
docs: maybe_docs(vec!["Counter for the related counted storage map"]),
},
StorageEntryMetadata { StorageEntryMetadata {
name: "RenamedCountedMap", name: "RenamedCountedMap",
modifier: StorageEntryModifier::Optional, modifier: StorageEntryModifier::Optional,
@@ -1873,6 +2032,48 @@ fn test_storage_info() {
max_values: None, max_values: None,
max_size: Some(16 + 1 + 8 + 2 + 16), max_size: Some(16 + 1 + 8 + 2 + 16),
}, },
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CountedNMap".to_vec(),
prefix: prefix(b"Example", b"CountedNMap").to_vec(),
max_values: None,
max_size: Some(16 + 1 + 4),
},
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CounterForCountedNMap".to_vec(),
prefix: prefix(b"Example", b"CounterForCountedNMap").to_vec(),
max_values: Some(1),
max_size: Some(4),
},
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CountedNMap2".to_vec(),
prefix: prefix(b"Example", b"CountedNMap2").to_vec(),
max_values: Some(11),
max_size: Some(8 + 2 + 16 + 4 + 8),
},
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CounterForCountedNMap2".to_vec(),
prefix: prefix(b"Example", b"CounterForCountedNMap2").to_vec(),
max_values: Some(1),
max_size: Some(4),
},
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CountedNMap3".to_vec(),
prefix: prefix(b"Example", b"CountedNMap3").to_vec(),
max_values: None,
max_size: Some(16 + 1 + 8 + 2 + 16),
},
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CounterForCountedNMap3".to_vec(),
prefix: prefix(b"Example", b"CounterForCountedNMap3").to_vec(),
max_values: Some(1),
max_size: Some(4),
},
#[cfg(feature = "frame-feature-testing")] #[cfg(feature = "frame-feature-testing")]
{ {
StorageInfo { StorageInfo {
@@ -1913,6 +2114,26 @@ fn test_storage_info() {
max_size: Some(16 + 1 + 8 + 2 + 4), max_size: Some(16 + 1 + 8 + 2 + 4),
} }
}, },
#[cfg(feature = "frame-feature-testing")]
{
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"ConditionalCountedNMap".to_vec(),
prefix: prefix(b"Example", b"ConditionalCountedNMap").to_vec(),
max_values: None,
max_size: Some(16 + 1 + 8 + 2 + 4),
}
},
#[cfg(feature = "frame-feature-testing")]
{
StorageInfo {
pallet_name: b"Example".to_vec(),
storage_name: b"CounterForConditionalCountedNMap".to_vec(),
prefix: prefix(b"Example", b"CounterForConditionalCountedNMap").to_vec(),
max_values: Some(1),
max_size: Some(4),
}
},
StorageInfo { StorageInfo {
pallet_name: b"Example".to_vec(), pallet_name: b"Example".to_vec(),
storage_name: b"RenamedCountedMap".to_vec(), storage_name: b"RenamedCountedMap".to_vec(),
@@ -1,4 +1,4 @@
error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8`. error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` or `CountedStorageNMap` in order to expand metadata, found `u8`.
--> $DIR/storage_not_storage_type.rs:19:16 --> $DIR/storage_not_storage_type.rs:19:16
| |
19 | type Foo<T> = u8; 19 | type Foo<T> = u8;