From 845658352748e13f328abed969a7de128554c8d1 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 5 Apr 2021 06:07:49 -0700 Subject: [PATCH 01/34] Implement StorageNMap --- frame/support/src/storage/generator/mod.rs | 2 + frame/support/src/storage/generator/nmap.rs | 342 ++++++++ frame/support/src/storage/mod.rs | 140 ++++ frame/support/src/storage/types/key.rs | 158 ++++ frame/support/src/storage/types/mod.rs | 3 + frame/support/src/storage/types/nmap.rs | 813 ++++++++++++++++++++ 6 files changed, 1458 insertions(+) create mode 100755 frame/support/src/storage/generator/nmap.rs create mode 100755 frame/support/src/storage/types/key.rs create mode 100755 frame/support/src/storage/types/nmap.rs diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index 86eafe86f43f4..578831314c1f6 100644 --- a/frame/support/src/storage/generator/mod.rs +++ b/frame/support/src/storage/generator/mod.rs @@ -25,10 +25,12 @@ //! This is internal api and is subject to change. mod map; +mod nmap; mod double_map; mod value; pub use map::StorageMap; +pub use nmap::StorageNMap; pub use double_map::StorageDoubleMap; pub use value::StorageValue; diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs new file mode 100755 index 0000000000000..43ddc6cfc3055 --- /dev/null +++ b/frame/support/src/storage/generator/nmap.rs @@ -0,0 +1,342 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[cfg(not(feature = "std"))] +use sp_std::prelude::*; +use sp_std::borrow::Borrow; +use codec::{FullCodec, Decode, Encode, EncodeLike}; +use crate::{ + storage::{ + self, unhashed, + types::{KeyGenerator, KeyHasherGenerator, ReversibleKeyGenerator}, + StorageAppend, PrefixIterator + }, + Never, hash::{StorageHasher, Twox128}, +}; + +/// Generator for `StorageNMap` used by `decl_storage`. +/// +/// By default each key value is stored at: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(storage_prefix) +/// ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) ++ ... ++ HasherN(encode(keyN)) +/// ``` +/// +/// # Warning +/// +/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as +/// `blake2_256` must be used. Otherwise, other values in storage with the same prefix can +/// be compromised. +pub trait StorageNMap { + /// The type that get/take returns. + type Query; + + /// Module prefix. Used for generating final key. + fn module_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final key. + fn storage_prefix() -> &'static [u8]; + + /// The full prefix; just the hash of `module_prefix` concatenated to the hash of + /// `storage_prefix`. + fn prefix_hash() -> Vec { + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + + let mut result = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + ); + + result.extend_from_slice(&module_prefix_hashed[..]); + result.extend_from_slice(&storage_prefix_hashed[..]); + + result + } + + /// Convert an optional value retrieved from storage to the type queried. + fn from_optional_value_to_query(v: Option) -> Self::Query; + + /// Convert a query to an optional value into storage. + fn from_query_to_optional_value(v: Self::Query) -> Option; + + /// Generate a partial key used in top storage. + fn storage_n_map_partial_key(key: (KArg, KG::NextKey)) -> Vec + where + KG: KeyGenerator, + KArg: EncodeLike, + { + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = KG::final_key(&key); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key + } + + /// Generate the full key used in top storage. + fn storage_n_map_final_key>(key: &(KArg, K::NextKey)) -> Vec { + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = K::final_key(key); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key + } +} + +impl storage::StorageNMap for G +where + K: KeyGenerator, + V: FullCodec, + G: StorageNMap, +{ + type Query = G::Query; + + fn hashed_key_for>(key: (KArg, K::NextKey)) -> Vec { + Self::storage_n_map_final_key(&key) + } + + fn contains_key>(key: (KArg, K::NextKey)) -> bool { + unhashed::exists(&Self::storage_n_map_final_key(&key)) + } + + fn get>(key: (KArg, K::NextKey)) -> Self::Query { + G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key(&key))) + } + + fn try_get>(key: (KArg, K::NextKey)) -> Result { + unhashed::get(&Self::storage_n_map_final_key(&key)).ok_or(()) + } + + fn take>(key: (KArg, K::NextKey)) -> Self::Query { + let final_key = Self::storage_n_map_final_key(&key); + + let value = unhashed::take(&final_key); + G::from_optional_value_to_query(value) + } + + fn swap(key1: (KArg1, K::NextKey), key2: (KArg2, KOther::NextKey)) + where + KOther: KeyGenerator, + KArg1: EncodeLike, + KArg2: EncodeLike, + { + let final_x_key = Self::storage_n_map_final_key(&key1); + // Not really a partial key, but only this function allows us to specify a foreign key generator + let final_y_key = Self::storage_n_map_partial_key::(key2); + + let v1 = unhashed::get_raw(&final_x_key); + if let Some(val) = unhashed::get_raw(&final_y_key) { + unhashed::put_raw(&final_x_key, &val); + } else { + unhashed::kill(&final_x_key); + } + if let Some(val) = v1 { + unhashed::put_raw(&final_y_key, &val); + } else { + unhashed::kill(&final_y_key); + } + } + + fn insert(key: (KArg, K::NextKey), val: VArg) + where + KArg: EncodeLike, + VArg: EncodeLike, + { + unhashed::put(&Self::storage_n_map_final_key(&key), &val.borrow()); + } + + fn remove>(key: (KArg, K::NextKey)) { + unhashed::kill(&Self::storage_n_map_final_key(&key)); + } + + fn remove_prefix(partial_key: (KArg, KG::NextKey)) + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike, + { + unhashed::kill_prefix(&Self::storage_n_map_partial_key::(partial_key)); + } + + fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike, + { + let prefix = Self::storage_n_map_partial_key::(partial_key); + PrefixIterator { + prefix: prefix.clone(), + previous_key: prefix, + drain: false, + closure: |_raw_key, mut raw_value| V::decode(&mut raw_value), + } + } + + fn mutate, R, F: FnOnce(&mut Self::Query) -> R>( + key: (KArg, K::NextKey), + f: F, + ) -> R { + Self::try_mutate(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") + } + + fn try_mutate, R, E, F: FnOnce(&mut Self::Query) -> Result>( + key: (KArg, K::NextKey), + f: F, + ) -> Result { + let final_key = Self::storage_n_map_final_key(&key); + let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref())); + + let ret = f(&mut val); + if ret.is_ok() { + match G::from_query_to_optional_value(val) { + Some(ref val) => unhashed::put(final_key.as_ref(), val), + None => unhashed::kill(final_key.as_ref()), + } + } + ret + } + + fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( + key: (KArg, K::NextKey), + f: F, + ) -> R { + Self::try_mutate_exists(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") + } + + fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( + key: (KArg, K::NextKey), + f: F, + ) -> Result { + let final_key = Self::storage_n_map_final_key(&key); + let mut val = unhashed::get(final_key.as_ref()); + + let ret = f(&mut val); + if ret.is_ok() { + match val { + Some(ref val) => unhashed::put(final_key.as_ref(), val), + None => unhashed::kill(final_key.as_ref()), + } + } + ret + } + + fn append(key: (KArg, K::NextKey), item: EncodeLikeItem) + where + KArg: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + V: StorageAppend + { + let final_key = Self::storage_n_map_final_key(&key); + sp_io::storage::append(&final_key, item.encode()); + } + + fn migrate_keys(key: (KArg, K::NextKey)) -> Option + where + OldHasher: KeyHasherGenerator, + KArg: EncodeLike + { + let old_key = { + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = K::final_hash::(&key); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + + storage_prefix_hashed.len() + + key_hashed.len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key + }; + unhashed::take(old_key.as_ref()).map(|value| { + unhashed::put(Self::storage_n_map_final_key(&key).as_ref(), &value); + value + }) + } +} + +impl> storage::IterableStorageNMap for G { + type Iterator = PrefixIterator<((K::CurrentKey, K::NextKey), V)>; + + fn iter() -> Self::Iterator { + let prefix = G::prefix_hash(); + Self::Iterator { + prefix: prefix.clone(), + previous_key: prefix, + drain: false, + closure: |raw_key_without_prefix, mut raw_value| { + let final_key = K::decode_final_key(raw_key_without_prefix)?; + Ok((final_key, V::decode(&mut raw_value)?)) + } + } + } + + fn drain() -> Self::Iterator { + let mut iterator = Self::iter(); + iterator.drain = true; + iterator + } + + fn translate Option>(mut f: F) { + let prefix = G::prefix_hash(); + let mut previous_key = prefix.clone(); + while let Some(next) = sp_io::storage::next_key(&previous_key) + .filter(|n| n.starts_with(&prefix)) + { + previous_key = next; + let value = match unhashed::get::(&previous_key) { + Some(value) => value, + None => { + log::error!("Invalid translate: fail to decode old value"); + continue + }, + }; + + let final_key = match K::decode_final_key(&previous_key[prefix.len()..]) { + Ok(final_key) => final_key, + Err(_) => { + log::error!("Invalid translate: fail to decode key"); + continue + } + }; + + match f(final_key, value) { + Some(new) => unhashed::put::(&previous_key, &new), + None => unhashed::kill(&previous_key), + } + } + } +} diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index adcf44a64620e..07f3aae9f8ae7 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -22,6 +22,7 @@ use sp_std::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, + storage::types::{KeyGenerator, KeyHasherGenerator, ReversibleKeyGenerator}, traits::Get, }; use sp_runtime::generic::{Digest, DigestItem}; @@ -360,6 +361,26 @@ pub trait IterableStorageDoubleMap< fn translate Option>(f: F); } +/// A strongly-typed map with arbitrary number of keys in storage whose keys and values can be iterated over. +pub trait IterableStorageNMap: StorageNMap { + /// The type that iterates over all `(key1, (key2, (key3, ... (keyN, ()))), value)` tuples + type Iterator: Iterator; + + /// Enumerate all elements in the map in no particular order. If you add or remove values to + /// the map while doing this, you'll get undefined results. + fn iter() -> Self::Iterator; + + /// Remove all elements from the map and iterate through them in no particular order. If you + /// add elements to the map while doing this, you'll get undefined results. + fn drain() -> Self::Iterator; + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + fn translate Option>(f: F); +} + /// An implementation of a map with a two keys. /// /// It provides an important ability to efficiently remove all entries @@ -511,6 +532,125 @@ pub trait StorageDoubleMap { >(key1: KeyArg1, key2: KeyArg2) -> Option; } +/// An implementation of a map with an arbitrary number of keys. +/// +/// Details of implementation can be found at [`generator::StorageNMap`]. +pub trait StorageNMap { + /// The type that get/take returns. + type Query; + + /// Get the storage key used to fetch a value corresponding to a specific key. + fn hashed_key_for>(key: (KArg, K::NextKey)) -> Vec; + + /// Does the value (explicitly) exist in storage? + fn contains_key>(key: (KArg, K::NextKey)) -> bool; + + /// Load the value associated with the given key from the map. + fn get>(key: (KArg, K::NextKey)) -> Self::Query; + + /// Try to get the value for the given key from the map. + /// + /// Returns `Ok` if it exists, `Err` if not. + fn try_get>(key: (KArg, K::NextKey)) -> Result; + + /// Swap the values of two keys. + fn swap(key1: (KArg1, K::NextKey), key2: (KArg2, KOther::NextKey)) + where + KOther: KeyGenerator, + KArg1: EncodeLike, + KArg2: EncodeLike; + + /// Store a value to be associated with the given key from the map. + fn insert, VArg: EncodeLike>(key: (KArg, K::NextKey), val: VArg); + + /// Remove the value under a key. + fn remove>(key: (KArg, K::NextKey)); + + /// Remove all values under the partial prefix key. + fn remove_prefix(partial_key: (KArg, KG::NextKey)) + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike; + + /// Iterate over values that share the partial prefix key. + fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike; + + /// Mutate the value under a key. + fn mutate, R, F: FnOnce(&mut Self::Query) -> R>( + key: (KArg, K::NextKey), + f: F, + ) -> R; + + /// Mutate the item, only if an `Ok` value is returned. + fn try_mutate, R, E, F: FnOnce(&mut Self::Query) -> Result>( + key: (KArg, K::NextKey), + f: F, + ) -> Result; + + /// Mutate the value under a key. + /// + /// Deletes the item if mutated to a `None`. + fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( + key: (KArg, K::NextKey), + f: F, + ) -> R; + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( + key: (KArg, K::NextKey), + f: F, + ) -> Result; + + /// Take the value under a key. + fn take>(key: (KArg, K::NextKey)) -> Self::Query; + + /// Append the given items to the value in the storage. + /// + /// `V` is required to implement `codec::EncodeAppend`. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + fn append(key: (KArg, K::NextKey), item: EncodeLikeItem) + where + KArg: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + V: StorageAppend; + + /// Read the length of the storage value without decoding the entire value under the + /// given `key`. + /// + /// `V` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + fn decode_len>(key: (KArg, K::NextKey)) -> Option + where + V: StorageDecodeLength, + { + V::decode_len(&Self::hashed_key_for(key)) + } + + /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + fn migrate_keys(key: (KArg, K::NextKey)) -> Option + where + OldHasher: KeyHasherGenerator, + KArg: EncodeLike; +} + /// Iterate over a prefix and decode raw_key and raw_value into `T`. /// /// If any decoding fails it skips it and continues to the next key. diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs new file mode 100755 index 0000000000000..f029b6042c759 --- /dev/null +++ b/frame/support/src/storage/types/key.rs @@ -0,0 +1,158 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage key type. + +use crate::hash::{ReversibleStorageHasher, StorageHasher, Identity}; +use codec::{EncodeLike, FullCodec}; +use sp_std::prelude::*; + +/// A type used exclusively by storage maps as their key type. +/// +/// The final key generated has the following form: +/// ```nocompile +/// Hasher1(encode(key1)) +/// ++ Hasher2(encode(key2)) +/// ++ ... +/// ++ HasherN(encode(keyN)) +/// ``` +pub struct Key( + core::marker::PhantomData<(Hasher, KeyType, NextKeyGenerator)>, +); + +/// A type to chain arbitrary number of hashers. Primarily used for +/// migrating old hashers to new hashers in StorageNMap. +pub struct KeyHasher( + core::marker::PhantomData<(Hasher, NextHasherGenerator)>, +); + +pub trait KeyHasherGenerator { + /// The current hasher generated by this type + type CurrentHasher: StorageHasher; + /// The next chained key hasher + type NextHasher: KeyHasherGenerator; +} + +impl KeyHasherGenerator for KeyHasher<(), ()> { + type CurrentHasher = Identity; + type NextHasher = KeyHasher<(), ()>; +} + +impl KeyHasherGenerator for KeyHasher { + type CurrentHasher = H; + type NextHasher = KeyHasher<(), ()>; +} + +impl KeyHasherGenerator for KeyHasher { + type CurrentHasher = H; + type NextHasher = KeyHasher; +} + +/// A trait that contains the current key as an associated type and generates the next key. +pub trait KeyGenerator { + type CurrentKey: EncodeLike; + type NextKey; + + fn final_key>(k: &(KArg, Self::NextKey)) -> Vec; + fn final_hash(k: &(KArg, Self::NextKey)) -> Vec + where + KArg: EncodeLike, + KHG: KeyHasherGenerator; +} + +impl KeyGenerator for Key { + type CurrentKey = K; + type NextKey = (); + + fn final_key>((k, _): &(KArg, Self::NextKey)) -> Vec { + k.using_encoded(H::hash).as_ref().to_vec() + } + + fn final_hash((k, _): &(KArg, Self::NextKey)) -> Vec + where + KArg: EncodeLike, + KHG: KeyHasherGenerator, + { + k.using_encoded(KHG::CurrentHasher::hash).as_ref().to_vec() + } +} + +impl KeyGenerator for Key +where + H: StorageHasher, + K: FullCodec, + KG: KeyGenerator, +{ + type CurrentKey = K; + type NextKey = (KG::CurrentKey, KG::NextKey); + + fn final_key>((kh, kt): &(KArg, Self::NextKey)) -> Vec { + let kh_hashed = kh.using_encoded(H::hash); + let kt_hashed = KG::final_key(kt); + + let mut final_key = Vec::with_capacity(kh_hashed.as_ref().len() + kt_hashed.len()); + final_key.extend_from_slice(kh_hashed.as_ref()); + final_key.extend_from_slice(kt_hashed.as_ref()); + final_key + } + + fn final_hash((kh, kt): &(KArg, Self::NextKey)) -> Vec + where + KArg: EncodeLike, + KHG: KeyHasherGenerator, + { + let kh_hashed = kh.using_encoded(KHG::CurrentHasher::hash); + let kt_hashed = KG::final_hash::(kt); + + let mut final_key = Vec::with_capacity(kh_hashed.as_ref().len() + kt_hashed.len()); + final_key.extend_from_slice(kh_hashed.as_ref()); + final_key.extend_from_slice(kt_hashed.as_ref()); + final_key + } +} + +/// A trait that indicates the hashers for the keys generated are all reversible. +pub trait ReversibleKeyGenerator: KeyGenerator { + type CurrentHasher: ReversibleStorageHasher; + fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error>; +} + +impl ReversibleKeyGenerator for Key { + type CurrentHasher = H; + + fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error> { + let mut current_key_material = Self::CurrentHasher::reverse(key_material); + let key = K::decode(&mut current_key_material)?; + Ok((key, ())) + } +} + +impl ReversibleKeyGenerator for Key +where + H: ReversibleStorageHasher, + K: FullCodec, + RKG: ReversibleKeyGenerator, +{ + type CurrentHasher = H; + + fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error> { + let mut current_key_material = Self::CurrentHasher::reverse(key_material); + let key = K::decode(&mut current_key_material)?; + let next_key = RKG::decode_final_key(current_key_material)?; + Ok((key, next_key)) + } +} diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 5bb6684b79259..cd03339f75cb0 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -21,10 +21,13 @@ use codec::FullCodec; use frame_metadata::{DefaultByte, StorageEntryModifier}; +mod key; mod value; mod map; +mod nmap; mod double_map; +pub use key::{Key, KeyGenerator, KeyHasher, KeyHasherGenerator, ReversibleKeyGenerator}; pub use value::{StorageValue, StorageValueMetadata}; pub use map::{StorageMap, StorageMapMetadata}; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs new file mode 100755 index 0000000000000..afa23f4de4c47 --- /dev/null +++ b/frame/support/src/storage/types/nmap.rs @@ -0,0 +1,813 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage map type. Implements StorageDoubleMap, StorageIterableDoubleMap, +//! StoragePrefixedDoubleMap traits and their methods directly. + +use codec::{Decode, Encode, EncodeLike, FullCodec}; +use crate::{ + storage::{ + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + KeyGenerator, KeyHasherGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, + }, + traits::{GetDefault, StorageInstance}, +}; +use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; +use sp_std::prelude::*; + +/// A type that allow to store values for an arbitrary number of keys in the form of `(key1, (key2, (..., (keyN, ()))))`. +/// +/// Each value is stored at: +/// ```nocompile +/// Twox128(Prefix::pallet_prefix()) +/// ++ Twox128(Prefix::STORAGE_PREFIX) +/// ++ Hasher1(encode(key1)) +/// ++ Hasher2(encode(key2)) +/// ++ ... +/// ++ HasherN(encode(keyN)) +/// ``` +/// +/// # Warning +/// +/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` +/// such as `blake2_128_concat` must be used for the key hashers. Otherwise, other values +/// in storage can be compromised. +pub struct StorageNMap( + core::marker::PhantomData<(Prefix, Key, Value, QueryKind, OnEmpty)>, +); + +impl + crate::storage::generator::StorageNMap for + StorageNMap +where + Prefix: StorageInstance, + Key: super::key::KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, +{ + type Query = QueryKind::Query; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } +} + +impl + crate::storage::StoragePrefixedMap for + StorageNMap +where + Prefix: StorageInstance, + Key: super::key::KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, +{ + fn module_prefix() -> &'static [u8] { + >::module_prefix() + } + fn storage_prefix() -> &'static [u8] { + >::storage_prefix() + } +} + +impl + StorageNMap +where + Prefix: StorageInstance, + Key: super::key::KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, +{ + /// Get the storage key used to fetch a value corresponding to a specific key. + pub fn hashed_key_for>(key: (KArg, Key::NextKey)) -> Vec { + >::hashed_key_for(key) + } + + /// Does the value (explicitly) exist in storage? + pub fn contains_key>(key: (KArg, Key::NextKey)) -> bool { + >::contains_key(key) + } + + /// Load the value associated with the given key from the map. + pub fn get>(key: (KArg, Key::NextKey)) -> QueryKind::Query { + >::get(key) + } + + /// Try to get the value for the given key from the map. + /// + /// Returns `Ok` if it exists, `Err` if not. + pub fn try_get>(key: (KArg, Key::NextKey)) -> Result { + >::try_get(key) + } + + /// Take a value from storage, removing it afterwards. + pub fn take>(key: (KArg, Key::NextKey)) -> QueryKind::Query { + >::take(key) + } + + /// Swap the values of two key-pairs. + pub fn swap(key1: (KArg1, Key::NextKey), key2: (KArg2, KOther::NextKey)) + where + KOther: KeyGenerator, + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::swap::<_, _, KOther>(key1, key2) + } + + /// Store a value to be associated with the given keys from the map. + pub fn insert(key: (KArg, Key::NextKey), val: VArg) + where + KArg: EncodeLike, + VArg: EncodeLike, + { + >::insert(key, val) + } + + /// Remove the value under the given keys. + pub fn remove>(key: (KArg, Key::NextKey)) { + >::remove(key) + } + + /// Remove all values under the first key. + pub fn remove_prefix(partial_key: (KArg, KG::NextKey)) + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike, + { + >::remove_prefix::(partial_key) + } + + /// Iterate over values that share the first key. + pub fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator + where + KG: KeyGenerator, + KArg: ?Sized + EncodeLike, + { + >::iter_prefix_values::(partial_key) + } + + /// Mutate the value under the given keys. + pub fn mutate(key: (KArg, Key::NextKey), f: F) -> R + where + KArg: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> R, + { + >::mutate(key, f) + } + + /// Mutate the value under the given keys when the closure returns `Ok`. + pub fn try_mutate(key: (KArg, Key::NextKey), f: F) -> Result + where + KArg: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> Result, + { + >::try_mutate(key, f) + } + + /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. + pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( + key: (KArg, Key::NextKey), + f: F, + ) -> R { + >::mutate_exists(key, f) + } + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( + key: (KArg, Key::NextKey), + f: F, + ) -> Result { + >::try_mutate_exists(key, f) + } + + /// Append the given item to the value in the storage. + /// + /// `Value` is required to implement [`StorageAppend`]. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(key: (KArg, Key::NextKey), item: EncodeLikeItem) + where + KArg: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend + { + >::append(key, item) + } + + /// Read the length of the storage value without decoding the entire value under the + /// given `key1` and `key2`. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len>(key: (KArg, Key::NextKey)) -> Option + where + Value: StorageDecodeLength, + { + >::decode_len(key) + } + + /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and + /// `OldHasher2` to the current hashers. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_keys(key: (KArg, Key::NextKey)) -> Option + where + OldHasher: KeyHasherGenerator, + KArg: EncodeLike + { + < + Self as crate::storage::StorageNMap + >::migrate_keys::(key) + } + + /// Remove all value of the storage. + pub fn remove_all() { + >::remove_all() + } + + /// Iter over all value of the storage. + /// + /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. + pub fn iter_values() -> crate::storage::PrefixIterator { + >::iter_values() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade. + pub fn translate_values Option>(f: F) { + >::translate_values(f) + } +} + +impl StorageNMap +where + Prefix: StorageInstance, + Key: super::key::ReversibleKeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static +{ + /// Enumerate all elements in the map in no particular order. + /// + /// If you add or remove values to the map while doing this, you'll get undefined results. + pub fn iter() -> crate::storage::PrefixIterator<((Key::CurrentKey, Key::NextKey), Value)> { + >::iter() + } + + /// Remove all elements from the map and iterate through them in no particular order. + /// + /// If you add elements to the map while doing this, you'll get undefined results. + pub fn drain() -> crate::storage::PrefixIterator<((Key::CurrentKey, Key::NextKey), Value)> { + >::drain() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + pub fn translate Option>(f: F) { + >::translate(f) + } +} + +/// Part of storage metadata for a storage n map. +/// +/// NOTE: Generic hashers is supported. +pub trait StorageNMapMetadata { + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; +} + +impl StorageNMapMetadata + for StorageNMap +where + Prefix: StorageInstance, + Key: super::key::KeyGenerator, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, +{ + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = + DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); +} + +#[cfg(test)] +mod test { + use super::*; + use sp_io::{TestExternalities, hashing::twox_128}; + use crate::hash::*; + use crate::storage::types::{Key, KeyHasher, ValueQuery}; + use frame_metadata::StorageEntryModifier; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { "test" } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 98 + } + } + + #[test] + fn test_1_key() { + type A = StorageNMap, u32, OptionQuery>; + type AValueQueryWithAnOnEmpty = StorageNMap< + Prefix, Key, u32, ValueQuery, ADefault + >; + type B = StorageNMap, u32, ValueQuery>; + type C = StorageNMap, u8, ValueQuery>; + type WithLen = StorageNMap, Vec>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + assert_eq!(A::hashed_key_for((3, ())).to_vec(), k); + + assert_eq!(A::contains_key((3, ())), false); + assert_eq!(A::get((3, ())), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 98); + + A::insert((3, ()), 10); + assert_eq!(A::contains_key((3, ())), true); + assert_eq!(A::get((3, ())), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 10); + + A::swap::<_, _, Key>((3, ()), (2, ())); + assert_eq!(A::contains_key((3, ())), false); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((3, ())), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 98); + assert_eq!(A::get((2, ())), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2, ())), 10); + + A::remove((2, ())); + assert_eq!(A::contains_key((2, ())), false); + assert_eq!(A::get((2, ())), None); + + AValueQueryWithAnOnEmpty::mutate((2, ()), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2, ()), |v| *v = *v * 2); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(98 * 4)); + + A::remove((2, ())); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + *v = *v * 2; Ok(()) + }); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + *v = *v * 2; Ok(()) + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(98 * 4)); + + A::remove((2, ())); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + *v = *v * 2; Err(()) + }); + assert_eq!(A::contains_key((2, ())), false); + + A::remove((2, ())); + AValueQueryWithAnOnEmpty::mutate_exists((2, ()), |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2, ()), |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(100)); + + A::remove((2, ())); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(100)); + assert_eq!(A::try_get((2, ())), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(100)); + + + A::insert((2, ()), 10); + assert_eq!(A::take((2, ())), Some(10)); + assert_eq!(A::contains_key((2, ())), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2, ())), 98); + assert_eq!(A::contains_key((2, ())), false); + assert_eq!(A::try_get((2, ())), Err(())); + + B::insert((2, ()), 10); + assert_eq!(A::migrate_keys::, _>((2, ())), Some(10)); + assert_eq!(A::contains_key((2, ())), true); + assert_eq!(A::get((2, ())), Some(10)); + + A::insert((3, ()), 10); + A::insert((4, ()), 10); + A::remove_all(); + assert_eq!(A::contains_key((3, ())), false); + assert_eq!(A::contains_key((4, ())), false); + + A::insert((3, ()), 10); + A::insert((4, ()), 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert((3, ()), 10); + C::insert((4, ()), 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![((4, ()), 20), ((3, ()), 20)]); + + A::insert((3, ()), 10); + A::insert((4, ()), 10); + assert_eq!(A::iter().collect::>(), vec![((4, ()), 10), ((3, ()), 10)]); + assert_eq!(A::drain().collect::>(), vec![((4, ()), 10), ((3, ()), 10)]); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert((3, ()), 10); + C::insert((4, ()), 10); + A::translate::(|(k1, ()), v| Some((k1 as u16 * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![((4, ()), 40), ((3, ()), 30)]); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!(A::NAME, "foo"); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len((3, ())), None); + WithLen::append((0, ()), 10); + assert_eq!(WithLen::decode_len((0, ())), Some(1)); + }); + } + + #[test] + fn test_2_keys() { + type A = StorageNMap>, u32, OptionQuery>; + type AValueQueryWithAnOnEmpty = StorageNMap< + Prefix, Key>, u32, ValueQuery, ADefault + >; + type B = StorageNMap>, u32, ValueQuery>; + type C = StorageNMap>, u8, ValueQuery>; + type WithLen = StorageNMap>, Vec>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + k.extend(&30u8.twox_64_concat()); + assert_eq!(A::hashed_key_for((3, (30, ()))).to_vec(), k); + + assert_eq!(A::contains_key((3, (30, ()))), false); + assert_eq!(A::get((3, (30, ()))), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 98); + + A::insert((3, (30, ())), 10); + assert_eq!(A::contains_key((3, (30, ()))), true); + assert_eq!(A::get((3, (30, ()))), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 10); + + A::swap::<_, _, Key>>((3, (30, ())), (2, (20, ()))); + assert_eq!(A::contains_key((3, (30, ()))), false); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((3, (30, ()))), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 98); + assert_eq!(A::get((2, (20, ()))), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2, (20, ()))), 10); + + A::remove((2, (20, ()))); + assert_eq!(A::contains_key((2, (20, ()))), false); + assert_eq!(A::get((2, (20, ()))), None); + + AValueQueryWithAnOnEmpty::mutate((2, (20, ())), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2, (20, ())), |v| *v = *v * 2); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(98 * 4)); + + A::remove((2, (20, ()))); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, ())), |v| { + *v = *v * 2; Err(()) + }); + assert_eq!(A::contains_key((2, (20, ()))), false); + + A::remove((2, (20, ()))); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, ())), |v| { + *v = *v * 2; Err(()) + }); + assert_eq!(A::contains_key((2, (20, ()))), false); + + A::remove((2, (20, ()))); + AValueQueryWithAnOnEmpty::mutate_exists((2, (20, ())), |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2, (20, ())), |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(100)); + + A::remove((2, (20, ()))); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(100)); + assert_eq!(A::try_get((2, (20, ()))), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(100)); + + + A::insert((2, (20, ())), 10); + assert_eq!(A::take((2, (20, ()))), Some(10)); + assert_eq!(A::contains_key((2, (20, ()))), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2, (20, ()))), 98); + assert_eq!(A::contains_key((2, (20, ()))), false); + assert_eq!(A::try_get((2, (20, ()))), Err(())); + + B::insert((2, (20, ())), 10); + assert_eq!(A::migrate_keys::>, _>((2, (20, ()))), Some(10)); + assert_eq!(A::contains_key((2, (20, ()))), true); + assert_eq!(A::get((2, (20, ()))), Some(10)); + + A::insert((3, (30, ())), 10); + A::insert((4, (40, ())), 10); + A::remove_all(); + assert_eq!(A::contains_key((3, (30, ()))), false); + assert_eq!(A::contains_key((4, (40, ()))), false); + + A::insert((3, (30, ())), 10); + A::insert((4, (40, ())), 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert((3, (30, ())), 10); + C::insert((4, (40, ())), 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 20), ((3, (30, ())), 20)]); + + A::insert((3, (30, ())), 10); + A::insert((4, (40, ())), 10); + assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 10), ((3, (30, ())), 10)]); + assert_eq!(A::drain().collect::>(), vec![((4, (40, ())), 10), ((3, (30, ())), 10)]); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert((3, (30, ())), 10); + C::insert((4, (40, ())), 10); + A::translate::(|(k1, (k2, ())), v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 1600), ((3, (30, ())), 900)]); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!(A::NAME, "foo"); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len((3, (30, ()))), None); + WithLen::append((0, (100, ())), 10); + assert_eq!(WithLen::decode_len((0, (100, ()))), Some(1)); + + A::insert((3, (30, ())), 11); + A::insert((3, (31, ())), 12); + A::insert((4, (40, ())), 13); + A::insert((4, (41, ())), 14); + assert_eq!(A::iter_prefix_values::, _>((3, ())).collect::>(), vec![12, 11]); + assert_eq!(A::iter_prefix_values::, _>((4, ())).collect::>(), vec![13, 14]); + }); + } + + #[test] + fn test_3_keys() { + type A = StorageNMap>>, u32, OptionQuery>; + type AValueQueryWithAnOnEmpty = StorageNMap< + Prefix, Key>>, u32, ValueQuery, ADefault + >; + type B = StorageNMap>>, u32, ValueQuery>; + type C = StorageNMap>>, u8, ValueQuery>; + type WithLen = StorageNMap>>, Vec>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&1u16.blake2_128_concat()); + k.extend(&10u16.blake2_128_concat()); + k.extend(&100u16.twox_64_concat()); + assert_eq!(A::hashed_key_for((1, (10, (100, ())))).to_vec(), k); + + assert_eq!(A::contains_key((1, (10, (100, ())))), false); + assert_eq!(A::get((1, (10, (100, ())))), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 98); + + A::insert((1, (10, (100, ()))), 30); + assert_eq!(A::contains_key((1, (10, (100, ())))), true); + assert_eq!(A::get((1, (10, (100, ())))), Some(30)); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 30); + + A::swap::<_, _, Key>>>( + (1, (10, (100, ()))), + (2, (20, (200, ()))), + ); + assert_eq!(A::contains_key((1, (10, (100, ())))), false); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((1, (10, (100, ())))), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 98); + assert_eq!(A::get((2, (20, (200, ())))), Some(30)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2, (20, (200, ())))), 30); + + A::remove((2, (20, (200, ())))); + assert_eq!(A::contains_key((2, (20, (200, ())))), false); + assert_eq!(A::get((2, (20, (200, ())))), None); + + AValueQueryWithAnOnEmpty::mutate((2, (20, (200, ()))), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2, (20, (200, ()))), |v| *v = *v * 2); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(98 * 4)); + + A::remove((2, (20, (200, ())))); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, (200, ()))), |v| { + *v = *v * 2; Err(()) + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), false); + + A::remove((2, (20, (200, ())))); + AValueQueryWithAnOnEmpty::mutate_exists((2, (20, (200, ()))), |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2, (20, (200, ()))), |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(100)); + + A::remove((2, (20, (200, ())))); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(100)); + assert_eq!(A::try_get((2, (20, (200, ())))), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(100)); + + + A::insert((2, (20, (200, ()))), 10); + assert_eq!(A::take((2, (20, (200, ())))), Some(10)); + assert_eq!(A::contains_key((2, (20, (200, ())))), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2, (20, (200, ())))), 98); + assert_eq!(A::contains_key((2, (20, (200, ())))), false); + assert_eq!(A::try_get((2, (20, (200, ())))), Err(())); + + B::insert((2, (20, (200, ()))), 10); + assert_eq!(A::migrate_keys::< + KeyHasher>>, + _, + >((2, (20, (200, ())))), Some(10)); + assert_eq!(A::contains_key((2, (20, (200, ())))), true); + assert_eq!(A::get((2, (20, (200, ())))), Some(10)); + + A::insert((3, (30, (300, ()))), 10); + A::insert((4, (40, (400, ()))), 10); + A::remove_all(); + assert_eq!(A::contains_key((3, (30, (300, ())))), false); + assert_eq!(A::contains_key((4, (40, (400, ())))), false); + + A::insert((3, (30, (300, ()))), 10); + A::insert((4, (40, (400, ()))), 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert((3, (30, (300, ()))), 10); + C::insert((4, (40, (400, ()))), 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 20), ((3, (30, (300, ()))), 20)]); + + A::insert((3, (30, (300, ()))), 10); + A::insert((4, (40, (400, ()))), 10); + assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 10), ((3, (30, (300, ()))), 10)]); + assert_eq!(A::drain().collect::>(), vec![((4, (40, (400, ()))), 10), ((3, (30, (300, ()))), 10)]); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert((3, (30, (300, ()))), 10); + C::insert((4, (40, (400, ()))), 10); + A::translate::(|(k1, (k2, (k3, ()))), v| Some((k1 * k2 as u16 * v as u16 / k3 as u16).into())); + assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 4), ((3, (30, (300, ()))), 3)]); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!(A::NAME, "foo"); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len((3, (30, (300, ())))), None); + WithLen::append((0, (100, (1000, ()))), 10); + assert_eq!(WithLen::decode_len((0, (100, (1000, ())))), Some(1)); + + A::insert((3, (30, (300, ()))), 11); + A::insert((3, (30, (301, ()))), 12); + A::insert((4, (40, (400, ()))), 13); + A::insert((4, (40, (401, ()))), 14); + assert_eq!(A::iter_prefix_values::>, _>((3, (30, ()))).collect::>(), vec![11, 12]); + assert_eq!(A::iter_prefix_values::>, _>((4, (40, ()))).collect::>(), vec![14, 13]); + }); + } +} From a52724afdbf2eb9fafb75616475b2a760fd82f81 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sat, 17 Apr 2021 19:52:51 -0700 Subject: [PATCH 02/34] Change copyright date to 2021 --- frame/support/src/storage/generator/nmap.rs | 2 +- frame/support/src/storage/types/key.rs | 2 +- frame/support/src/storage/types/nmap.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 43ddc6cfc3055..8d4a3c78a1f94 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index f029b6042c759..878b5ad872ea6 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index afa23f4de4c47..4c37e7ff0edc3 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// Copyright (C) 2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); From 42513d2493f8b46ca4364da5d25898c2f3df4ad5 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 21 Apr 2021 10:33:35 -0700 Subject: [PATCH 03/34] Rewrite keys to use impl_for_tuples instead of recursion --- frame/support/src/storage/generator/nmap.rs | 138 ++--- frame/support/src/storage/mod.rs | 69 +-- frame/support/src/storage/types/key.rs | 141 ++--- frame/support/src/storage/types/mod.rs | 2 +- frame/support/src/storage/types/nmap.rs | 622 +++++++++----------- 5 files changed, 380 insertions(+), 592 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 8d4a3c78a1f94..9a41448c00799 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -18,11 +18,11 @@ #[cfg(not(feature = "std"))] use sp_std::prelude::*; use sp_std::borrow::Borrow; -use codec::{FullCodec, Decode, Encode, EncodeLike}; +use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ self, unhashed, - types::{KeyGenerator, KeyHasherGenerator, ReversibleKeyGenerator}, + types::{KeyGenerator, ReversibleKeyGenerator}, StorageAppend, PrefixIterator }, Never, hash::{StorageHasher, Twox128}, @@ -74,14 +74,10 @@ pub trait StorageNMap { fn from_query_to_optional_value(v: Self::Query) -> Option; /// Generate a partial key used in top storage. - fn storage_n_map_partial_key(key: (KArg, KG::NextKey)) -> Vec - where - KG: KeyGenerator, - KArg: EncodeLike, - { + fn storage_n_map_partial_key(key: KG::Key) -> Vec { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); - let key_hashed = KG::final_key(&key); + let key_hashed = KG::final_key(key); let mut final_key = Vec::with_capacity( module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() @@ -95,7 +91,7 @@ pub trait StorageNMap { } /// Generate the full key used in top storage. - fn storage_n_map_final_key>(key: &(KArg, K::NextKey)) -> Vec { + fn storage_n_map_final_key(key: K::Key) -> Vec { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); let key_hashed = K::final_key(key); @@ -120,38 +116,33 @@ where { type Query = G::Query; - fn hashed_key_for>(key: (KArg, K::NextKey)) -> Vec { - Self::storage_n_map_final_key(&key) + fn hashed_key_for(key: K::Key) -> Vec { + Self::storage_n_map_final_key(key) } - fn contains_key>(key: (KArg, K::NextKey)) -> bool { - unhashed::exists(&Self::storage_n_map_final_key(&key)) + fn contains_key(key: K::Key) -> bool { + unhashed::exists(&Self::storage_n_map_final_key(key)) } - fn get>(key: (KArg, K::NextKey)) -> Self::Query { - G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key(&key))) + fn get(key: K::Key) -> Self::Query { + G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key(key))) } - fn try_get>(key: (KArg, K::NextKey)) -> Result { - unhashed::get(&Self::storage_n_map_final_key(&key)).ok_or(()) + fn try_get(key: K::Key) -> Result { + unhashed::get(&Self::storage_n_map_final_key(key)).ok_or(()) } - fn take>(key: (KArg, K::NextKey)) -> Self::Query { - let final_key = Self::storage_n_map_final_key(&key); + fn take(key: K::Key) -> Self::Query { + let final_key = Self::storage_n_map_final_key(key); let value = unhashed::take(&final_key); G::from_optional_value_to_query(value) } - fn swap(key1: (KArg1, K::NextKey), key2: (KArg2, KOther::NextKey)) - where - KOther: KeyGenerator, - KArg1: EncodeLike, - KArg2: EncodeLike, - { - let final_x_key = Self::storage_n_map_final_key(&key1); + fn swap(key1: K::Key, key2: KOther::Key) { + let final_x_key = Self::storage_n_map_final_key(key1); // Not really a partial key, but only this function allows us to specify a foreign key generator - let final_y_key = Self::storage_n_map_partial_key::(key2); + let final_y_key = Self::storage_n_map_partial_key::(key2); let v1 = unhashed::get_raw(&final_x_key); if let Some(val) = unhashed::get_raw(&final_y_key) { @@ -166,32 +157,20 @@ where } } - fn insert(key: (KArg, K::NextKey), val: VArg) - where - KArg: EncodeLike, - VArg: EncodeLike, - { - unhashed::put(&Self::storage_n_map_final_key(&key), &val.borrow()); + fn insert>(key: K::Key, val: VArg) { + unhashed::put(&Self::storage_n_map_final_key(key), &val.borrow()); } - fn remove>(key: (KArg, K::NextKey)) { - unhashed::kill(&Self::storage_n_map_final_key(&key)); + fn remove(key: K::Key) { + unhashed::kill(&Self::storage_n_map_final_key(key)); } - fn remove_prefix(partial_key: (KArg, KG::NextKey)) - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike, - { - unhashed::kill_prefix(&Self::storage_n_map_partial_key::(partial_key)); + fn remove_prefix(partial_key: KG::Key) { + unhashed::kill_prefix(&Self::storage_n_map_partial_key::(partial_key)); } - fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike, - { - let prefix = Self::storage_n_map_partial_key::(partial_key); + fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator { + let prefix = Self::storage_n_map_partial_key::(partial_key); PrefixIterator { prefix: prefix.clone(), previous_key: prefix, @@ -200,18 +179,12 @@ where } } - fn mutate, R, F: FnOnce(&mut Self::Query) -> R>( - key: (KArg, K::NextKey), - f: F, - ) -> R { + fn mutate R>(key: K::Key, f: F) -> R { Self::try_mutate(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate, R, E, F: FnOnce(&mut Self::Query) -> Result>( - key: (KArg, K::NextKey), - f: F, - ) -> Result { - let final_key = Self::storage_n_map_final_key(&key); + fn try_mutate Result>(key: K::Key, f: F) -> Result { + let final_key = Self::storage_n_map_final_key(key); let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref())); let ret = f(&mut val); @@ -224,18 +197,12 @@ where ret } - fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( - key: (KArg, K::NextKey), - f: F, - ) -> R { + fn mutate_exists) -> R>(key: K::Key, f: F) -> R { Self::try_mutate_exists(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( - key: (KArg, K::NextKey), - f: F, - ) -> Result { - let final_key = Self::storage_n_map_final_key(&key); + fn try_mutate_exists) -> Result>(key: K::Key, f: F) -> Result { + let final_key = Self::storage_n_map_final_key(key); let mut val = unhashed::get(final_key.as_ref()); let ret = f(&mut val); @@ -248,48 +215,19 @@ where ret } - fn append(key: (KArg, K::NextKey), item: EncodeLikeItem) + fn append(key: K::Key, item: EncodeLikeItem) where - KArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend { - let final_key = Self::storage_n_map_final_key(&key); + let final_key = Self::storage_n_map_final_key(key); sp_io::storage::append(&final_key, item.encode()); } - - fn migrate_keys(key: (KArg, K::NextKey)) -> Option - where - OldHasher: KeyHasherGenerator, - KArg: EncodeLike - { - let old_key = { - let module_prefix_hashed = Twox128::hash(Self::module_prefix()); - let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); - let key_hashed = K::final_hash::(&key); - - let mut final_key = Vec::with_capacity( - module_prefix_hashed.len() - + storage_prefix_hashed.len() - + key_hashed.len() - ); - - final_key.extend_from_slice(&module_prefix_hashed[..]); - final_key.extend_from_slice(&storage_prefix_hashed[..]); - final_key.extend_from_slice(key_hashed.as_ref()); - - final_key - }; - unhashed::take(old_key.as_ref()).map(|value| { - unhashed::put(Self::storage_n_map_final_key(&key).as_ref(), &value); - value - }) - } } impl> storage::IterableStorageNMap for G { - type Iterator = PrefixIterator<((K::CurrentKey, K::NextKey), V)>; + type Iterator = PrefixIterator<(K::Key, V)>; fn iter() -> Self::Iterator { let prefix = G::prefix_hash(); @@ -298,7 +236,7 @@ impl> storage::Ite previous_key: prefix, drain: false, closure: |raw_key_without_prefix, mut raw_value| { - let final_key = K::decode_final_key(raw_key_without_prefix)?; + let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?; Ok((final_key, V::decode(&mut raw_value)?)) } } @@ -310,7 +248,7 @@ impl> storage::Ite iterator } - fn translate Option>(mut f: F) { + fn translate Option>(mut f: F) { let prefix = G::prefix_hash(); let mut previous_key = prefix.clone(); while let Some(next) = sp_io::storage::next_key(&previous_key) @@ -326,7 +264,7 @@ impl> storage::Ite }; let final_key = match K::decode_final_key(&previous_key[prefix.len()..]) { - Ok(final_key) => final_key, + Ok((final_key, _)) => final_key, Err(_) => { log::error!("Invalid translate: fail to decode key"); continue diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 07f3aae9f8ae7..5b9c988fa8179 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -22,7 +22,7 @@ use sp_std::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, - storage::types::{KeyGenerator, KeyHasherGenerator, ReversibleKeyGenerator}, + storage::types::{KeyGenerator, ReversibleKeyGenerator}, traits::Get, }; use sp_runtime::generic::{Digest, DigestItem}; @@ -364,7 +364,7 @@ pub trait IterableStorageDoubleMap< /// A strongly-typed map with arbitrary number of keys in storage whose keys and values can be iterated over. pub trait IterableStorageNMap: StorageNMap { /// The type that iterates over all `(key1, (key2, (key3, ... (keyN, ()))), value)` tuples - type Iterator: Iterator; + type Iterator: Iterator; /// Enumerate all elements in the map in no particular order. If you add or remove values to /// the map while doing this, you'll get undefined results. @@ -378,7 +378,7 @@ pub trait IterableStorageNMap: StorageN /// By returning `None` from `f` for an element, you'll remove it from the map. /// /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - fn translate Option>(f: F); + fn translate Option>(f: F); } /// An implementation of a map with a two keys. @@ -540,72 +540,50 @@ pub trait StorageNMap { type Query; /// Get the storage key used to fetch a value corresponding to a specific key. - fn hashed_key_for>(key: (KArg, K::NextKey)) -> Vec; + fn hashed_key_for(key: K::Key) -> Vec; /// Does the value (explicitly) exist in storage? - fn contains_key>(key: (KArg, K::NextKey)) -> bool; + fn contains_key(key: K::Key) -> bool; /// Load the value associated with the given key from the map. - fn get>(key: (KArg, K::NextKey)) -> Self::Query; + fn get(key: K::Key) -> Self::Query; /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - fn try_get>(key: (KArg, K::NextKey)) -> Result; + fn try_get(key: K::Key) -> Result; /// Swap the values of two keys. - fn swap(key1: (KArg1, K::NextKey), key2: (KArg2, KOther::NextKey)) - where - KOther: KeyGenerator, - KArg1: EncodeLike, - KArg2: EncodeLike; + fn swap(key1: K::Key, key2: KOther::Key); /// Store a value to be associated with the given key from the map. - fn insert, VArg: EncodeLike>(key: (KArg, K::NextKey), val: VArg); + fn insert>(key: K::Key, val: VArg); /// Remove the value under a key. - fn remove>(key: (KArg, K::NextKey)); + fn remove(key: K::Key); /// Remove all values under the partial prefix key. - fn remove_prefix(partial_key: (KArg, KG::NextKey)) - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike; + fn remove_prefix(partial_key: KG::Key); /// Iterate over values that share the partial prefix key. - fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike; + fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator; /// Mutate the value under a key. - fn mutate, R, F: FnOnce(&mut Self::Query) -> R>( - key: (KArg, K::NextKey), - f: F, - ) -> R; + fn mutate R>(key: K::Key, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. - fn try_mutate, R, E, F: FnOnce(&mut Self::Query) -> Result>( - key: (KArg, K::NextKey), - f: F, - ) -> Result; + fn try_mutate Result>(key: K::Key, f: F) -> Result; /// Mutate the value under a key. /// /// Deletes the item if mutated to a `None`. - fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( - key: (KArg, K::NextKey), - f: F, - ) -> R; + fn mutate_exists) -> R>(key: K::Key, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( - key: (KArg, K::NextKey), - f: F, - ) -> Result; + fn try_mutate_exists) -> Result>(key: K::Key, f: F) -> Result; /// Take the value under a key. - fn take>(key: (KArg, K::NextKey)) -> Self::Query; + fn take(key: K::Key) -> Self::Query; /// Append the given items to the value in the storage. /// @@ -616,9 +594,8 @@ pub trait StorageNMap { /// If the storage item is not encoded properly, the storage will be overwritten /// and set to `[item]`. Any default value set for the storage item will be ignored /// on overwrite. - fn append(key: (KArg, K::NextKey), item: EncodeLikeItem) + fn append(key: K::Key, item: EncodeLikeItem) where - KArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend; @@ -635,20 +612,12 @@ pub trait StorageNMap { /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - fn decode_len>(key: (KArg, K::NextKey)) -> Option + fn decode_len(key: K::Key) -> Option where V: StorageDecodeLength, { V::decode_len(&Self::hashed_key_for(key)) } - - /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - fn migrate_keys(key: (KArg, K::NextKey)) -> Option - where - OldHasher: KeyHasherGenerator, - KArg: EncodeLike; } /// Iterate over a prefix and decode raw_key and raw_value into `T`. diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 878b5ad872ea6..4bbcb5ba38ba2 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -17,7 +17,7 @@ //! Storage key type. -use crate::hash::{ReversibleStorageHasher, StorageHasher, Identity}; +use crate::hash::{ReversibleStorageHasher, StorageHasher}; use codec::{EncodeLike, FullCodec}; use sp_std::prelude::*; @@ -30,129 +30,68 @@ use sp_std::prelude::*; /// ++ ... /// ++ HasherN(encode(keyN)) /// ``` -pub struct Key( - core::marker::PhantomData<(Hasher, KeyType, NextKeyGenerator)>, +pub struct Key( + core::marker::PhantomData<(Hasher, KeyType)>, ); -/// A type to chain arbitrary number of hashers. Primarily used for -/// migrating old hashers to new hashers in StorageNMap. -pub struct KeyHasher( - core::marker::PhantomData<(Hasher, NextHasherGenerator)>, -); - -pub trait KeyHasherGenerator { - /// The current hasher generated by this type - type CurrentHasher: StorageHasher; - /// The next chained key hasher - type NextHasher: KeyHasherGenerator; -} - -impl KeyHasherGenerator for KeyHasher<(), ()> { - type CurrentHasher = Identity; - type NextHasher = KeyHasher<(), ()>; -} - -impl KeyHasherGenerator for KeyHasher { - type CurrentHasher = H; - type NextHasher = KeyHasher<(), ()>; -} - -impl KeyHasherGenerator for KeyHasher { - type CurrentHasher = H; - type NextHasher = KeyHasher; -} - /// A trait that contains the current key as an associated type and generates the next key. pub trait KeyGenerator { - type CurrentKey: EncodeLike; - type NextKey; - - fn final_key>(k: &(KArg, Self::NextKey)) -> Vec; - fn final_hash(k: &(KArg, Self::NextKey)) -> Vec - where - KArg: EncodeLike, - KHG: KeyHasherGenerator; -} + type Key: EncodeLike; -impl KeyGenerator for Key { - type CurrentKey = K; - type NextKey = (); + fn final_key(key: Self::Key) -> Vec; +} - fn final_key>((k, _): &(KArg, Self::NextKey)) -> Vec { - k.using_encoded(H::hash).as_ref().to_vec() - } +impl KeyGenerator for Key { + type Key = K; - fn final_hash((k, _): &(KArg, Self::NextKey)) -> Vec - where - KArg: EncodeLike, - KHG: KeyHasherGenerator, - { - k.using_encoded(KHG::CurrentHasher::hash).as_ref().to_vec() + fn final_key(key: Self::Key) -> Vec { + key.using_encoded(H::hash).as_ref().to_vec() } } -impl KeyGenerator for Key -where - H: StorageHasher, - K: FullCodec, - KG: KeyGenerator, -{ - type CurrentKey = K; - type NextKey = (KG::CurrentKey, KG::NextKey); - - fn final_key>((kh, kt): &(KArg, Self::NextKey)) -> Vec { - let kh_hashed = kh.using_encoded(H::hash); - let kt_hashed = KG::final_key(kt); - - let mut final_key = Vec::with_capacity(kh_hashed.as_ref().len() + kt_hashed.len()); - final_key.extend_from_slice(kh_hashed.as_ref()); - final_key.extend_from_slice(kt_hashed.as_ref()); - final_key - } +#[impl_trait_for_tuples::impl_for_tuples(2, 18)] +impl KeyGenerator for Tuple { + for_tuples!( type Key = ( #(Tuple::Key),* ); ); - fn final_hash((kh, kt): &(KArg, Self::NextKey)) -> Vec - where - KArg: EncodeLike, - KHG: KeyHasherGenerator, - { - let kh_hashed = kh.using_encoded(KHG::CurrentHasher::hash); - let kt_hashed = KG::final_hash::(kt); - - let mut final_key = Vec::with_capacity(kh_hashed.as_ref().len() + kt_hashed.len()); - final_key.extend_from_slice(kh_hashed.as_ref()); - final_key.extend_from_slice(kt_hashed.as_ref()); + fn final_key(key: Self::Key) -> Vec { + let mut final_key = Vec::new(); + for_tuples!( + #( final_key.extend_from_slice(&Tuple::final_key(key.Tuple)); )* + ); final_key } } /// A trait that indicates the hashers for the keys generated are all reversible. pub trait ReversibleKeyGenerator: KeyGenerator { - type CurrentHasher: ReversibleStorageHasher; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error>; + type Hasher; + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; } -impl ReversibleKeyGenerator for Key { - type CurrentHasher = H; +impl ReversibleKeyGenerator for Key { + type Hasher = H; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error> { - let mut current_key_material = Self::CurrentHasher::reverse(key_material); + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = Self::Hasher::reverse(key_material); let key = K::decode(&mut current_key_material)?; - Ok((key, ())) + Ok((key, current_key_material)) } } -impl ReversibleKeyGenerator for Key -where - H: ReversibleStorageHasher, - K: FullCodec, - RKG: ReversibleKeyGenerator, -{ - type CurrentHasher = H; - - fn decode_final_key(key_material: &[u8]) -> Result<(Self::CurrentKey, Self::NextKey), codec::Error> { - let mut current_key_material = Self::CurrentHasher::reverse(key_material); - let key = K::decode(&mut current_key_material)?; - let next_key = RKG::decode_final_key(current_key_material)?; - Ok((key, next_key)) +#[impl_trait_for_tuples::impl_for_tuples(2, 18)] +impl ReversibleKeyGenerator for Tuple { + for_tuples!( type Hasher = ( #(Tuple::Hasher),* ); ); + + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = key_material; + Ok((( + for_tuples!{ + #({ + let (key, material) = Tuple::decode_final_key(current_key_material)?; + current_key_material = material; + key + }),* + } + ), current_key_material)) } } diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index cd03339f75cb0..012b9a9698036 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -27,7 +27,7 @@ mod map; mod nmap; mod double_map; -pub use key::{Key, KeyGenerator, KeyHasher, KeyHasherGenerator, ReversibleKeyGenerator}; +pub use key::{Key, KeyGenerator, ReversibleKeyGenerator}; pub use value::{StorageValue, StorageValueMetadata}; pub use map::{StorageMap, StorageMapMetadata}; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 4c37e7ff0edc3..d5539b787b3b1 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -22,7 +22,7 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, - KeyGenerator, KeyHasherGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, + KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, }, traits::{GetDefault, StorageInstance}, }; @@ -103,103 +103,81 @@ where OnEmpty: crate::traits::Get + 'static, { /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for>(key: (KArg, Key::NextKey)) -> Vec { + pub fn hashed_key_for(key: Key::Key) -> Vec { >::hashed_key_for(key) } /// Does the value (explicitly) exist in storage? - pub fn contains_key>(key: (KArg, Key::NextKey)) -> bool { + pub fn contains_key(key: Key::Key) -> bool { >::contains_key(key) } /// Load the value associated with the given key from the map. - pub fn get>(key: (KArg, Key::NextKey)) -> QueryKind::Query { + pub fn get(key: Key::Key) -> QueryKind::Query { >::get(key) } /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get>(key: (KArg, Key::NextKey)) -> Result { + pub fn try_get(key: Key::Key) -> Result { >::try_get(key) } /// Take a value from storage, removing it afterwards. - pub fn take>(key: (KArg, Key::NextKey)) -> QueryKind::Query { + pub fn take(key: Key::Key) -> QueryKind::Query { >::take(key) } /// Swap the values of two key-pairs. - pub fn swap(key1: (KArg1, Key::NextKey), key2: (KArg2, KOther::NextKey)) - where - KOther: KeyGenerator, - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::swap::<_, _, KOther>(key1, key2) + pub fn swap(key1: Key::Key, key2: KOther::Key) { + >::swap::(key1, key2) } /// Store a value to be associated with the given keys from the map. - pub fn insert(key: (KArg, Key::NextKey), val: VArg) - where - KArg: EncodeLike, - VArg: EncodeLike, - { + pub fn insert>(key: Key::Key, val: VArg) { >::insert(key, val) } /// Remove the value under the given keys. - pub fn remove>(key: (KArg, Key::NextKey)) { + pub fn remove(key: Key::Key) { >::remove(key) } /// Remove all values under the first key. - pub fn remove_prefix(partial_key: (KArg, KG::NextKey)) - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike, - { - >::remove_prefix::(partial_key) + pub fn remove_prefix(partial_key: KG::Key) { + >::remove_prefix::(partial_key) } /// Iterate over values that share the first key. - pub fn iter_prefix_values(partial_key: (KArg, KG::NextKey)) -> PrefixIterator - where - KG: KeyGenerator, - KArg: ?Sized + EncodeLike, - { - >::iter_prefix_values::(partial_key) + pub fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator { + >::iter_prefix_values::(partial_key) } /// Mutate the value under the given keys. - pub fn mutate(key: (KArg, Key::NextKey), f: F) -> R + pub fn mutate(key: Key::Key, f: F) -> R where - KArg: EncodeLike, F: FnOnce(&mut QueryKind::Query) -> R, { >::mutate(key, f) } /// Mutate the value under the given keys when the closure returns `Ok`. - pub fn try_mutate(key: (KArg, Key::NextKey), f: F) -> Result + pub fn try_mutate(key: Key::Key, f: F) -> Result where - KArg: EncodeLike, F: FnOnce(&mut QueryKind::Query) -> Result, { >::try_mutate(key, f) } /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. - pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( - key: (KArg, Key::NextKey), - f: F, - ) -> R { + pub fn mutate_exists) -> R>(key: Key::Key, f: F) -> R { >::mutate_exists(key, f) } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( - key: (KArg, Key::NextKey), + pub fn try_mutate_exists) -> Result>( + key: Key::Key, f: F, ) -> Result { >::try_mutate_exists(key, f) @@ -214,9 +192,8 @@ where /// If the storage item is not encoded properly, the storage will be overwritten /// and set to `[item]`. Any default value set for the storage item will be ignored /// on overwrite. - pub fn append(key: (KArg, Key::NextKey), item: EncodeLikeItem) + pub fn append(key: Key::Key, item: EncodeLikeItem) where - KArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend @@ -236,27 +213,13 @@ where /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - pub fn decode_len>(key: (KArg, Key::NextKey)) -> Option + pub fn decode_len(key: Key::Key) -> Option where Value: StorageDecodeLength, { >::decode_len(key) } - /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and - /// `OldHasher2` to the current hashers. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_keys(key: (KArg, Key::NextKey)) -> Option - where - OldHasher: KeyHasherGenerator, - KArg: EncodeLike - { - < - Self as crate::storage::StorageNMap - >::migrate_keys::(key) - } - /// Remove all value of the storage. pub fn remove_all() { >::remove_all() @@ -298,14 +261,14 @@ where /// Enumerate all elements in the map in no particular order. /// /// If you add or remove values to the map while doing this, you'll get undefined results. - pub fn iter() -> crate::storage::PrefixIterator<((Key::CurrentKey, Key::NextKey), Value)> { + pub fn iter() -> crate::storage::PrefixIterator<(Key::Key, Value)> { >::iter() } /// Remove all elements from the map and iterate through them in no particular order. /// /// If you add elements to the map while doing this, you'll get undefined results. - pub fn drain() -> crate::storage::PrefixIterator<((Key::CurrentKey, Key::NextKey), Value)> { + pub fn drain() -> crate::storage::PrefixIterator<(Key::Key, Value)> { >::drain() } @@ -314,7 +277,7 @@ where /// By returning `None` from `f` for an element, you'll remove it from the map. /// /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - pub fn translate Option>(f: F) { + pub fn translate Option>(f: F) { >::translate(f) } } @@ -348,7 +311,7 @@ mod test { use super::*; use sp_io::{TestExternalities, hashing::twox_128}; use crate::hash::*; - use crate::storage::types::{Key, KeyHasher, ValueQuery}; + use crate::storage::types::{Key, ValueQuery}; use frame_metadata::StorageEntryModifier; struct Prefix; @@ -370,7 +333,6 @@ mod test { type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, Key, u32, ValueQuery, ADefault >; - type B = StorageNMap, u32, ValueQuery>; type C = StorageNMap, u8, ValueQuery>; type WithLen = StorageNMap, Vec>; @@ -379,123 +341,118 @@ mod test { k.extend(&twox_128(b"test")); k.extend(&twox_128(b"foo")); k.extend(&3u16.blake2_128_concat()); - assert_eq!(A::hashed_key_for((3, ())).to_vec(), k); - - assert_eq!(A::contains_key((3, ())), false); - assert_eq!(A::get((3, ())), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 98); - - A::insert((3, ()), 10); - assert_eq!(A::contains_key((3, ())), true); - assert_eq!(A::get((3, ())), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 10); - - A::swap::<_, _, Key>((3, ()), (2, ())); - assert_eq!(A::contains_key((3, ())), false); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((3, ())), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, ())), 98); - assert_eq!(A::get((2, ())), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get((2, ())), 10); - - A::remove((2, ())); - assert_eq!(A::contains_key((2, ())), false); - assert_eq!(A::get((2, ())), None); - - AValueQueryWithAnOnEmpty::mutate((2, ()), |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate((2, ()), |v| *v = *v * 2); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(98 * 4)); - - A::remove((2, ())); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + assert_eq!(A::hashed_key_for(3).to_vec(), k); + + assert_eq!(A::contains_key(3), false); + assert_eq!(A::get(3), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 98); + + A::insert(3, 10); + assert_eq!(A::contains_key(3), true); + assert_eq!(A::get(3), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); + + A::swap::>(3, 2); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(3), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 98); + assert_eq!(A::get(2), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); + + A::remove(2); + assert_eq!(A::contains_key(2), false); + assert_eq!(A::get(2), None); + + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(98 * 4)); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { *v = *v * 2; Ok(()) }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { *v = *v * 2; Ok(()) }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(98 * 4)); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(98 * 4)); - A::remove((2, ())); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, ()), |v| { + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { *v = *v * 2; Err(()) }); - assert_eq!(A::contains_key((2, ())), false); + assert_eq!(A::contains_key(2), false); - A::remove((2, ())); - AValueQueryWithAnOnEmpty::mutate_exists((2, ()), |v| { + A::remove(2); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { assert!(v.is_none()); *v = Some(10); }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists((2, ()), |v| { + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { *v = Some(v.unwrap() * 10); }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(100)); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); - A::remove((2, ())); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { assert!(v.is_none()); *v = Some(10); Ok(()) }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { *v = Some(v.unwrap() * 10); Ok(()) }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(100)); - assert_eq!(A::try_get((2, ())), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, ()), |v| { + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + assert_eq!(A::try_get(2), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { *v = Some(v.unwrap() * 10); Err(()) }); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(100)); - + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); - A::insert((2, ()), 10); - assert_eq!(A::take((2, ())), Some(10)); - assert_eq!(A::contains_key((2, ())), false); - assert_eq!(AValueQueryWithAnOnEmpty::take((2, ())), 98); - assert_eq!(A::contains_key((2, ())), false); - assert_eq!(A::try_get((2, ())), Err(())); - B::insert((2, ()), 10); - assert_eq!(A::migrate_keys::, _>((2, ())), Some(10)); - assert_eq!(A::contains_key((2, ())), true); - assert_eq!(A::get((2, ())), Some(10)); + A::insert(2, 10); + assert_eq!(A::take(2), Some(10)); + assert_eq!(A::contains_key(2), false); + assert_eq!(AValueQueryWithAnOnEmpty::take(2), 98); + assert_eq!(A::contains_key(2), false); + assert_eq!(A::try_get(2), Err(())); - A::insert((3, ()), 10); - A::insert((4, ()), 10); + A::insert(3, 10); + A::insert(4, 10); A::remove_all(); - assert_eq!(A::contains_key((3, ())), false); - assert_eq!(A::contains_key((4, ())), false); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(4), false); - A::insert((3, ()), 10); - A::insert((4, ()), 10); + A::insert(3, 10); + A::insert(4, 10); assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - C::insert((3, ()), 10); - C::insert((4, ()), 10); + C::insert(3, 10); + C::insert(4, 10); A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![((4, ()), 20), ((3, ()), 20)]); + assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); - A::insert((3, ()), 10); - A::insert((4, ()), 10); - assert_eq!(A::iter().collect::>(), vec![((4, ()), 10), ((3, ()), 10)]); - assert_eq!(A::drain().collect::>(), vec![((4, ()), 10), ((3, ()), 10)]); + A::insert(3, 10); + A::insert(4, 10); + assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); + assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); assert_eq!(A::iter().collect::>(), vec![]); - C::insert((3, ()), 10); - C::insert((4, ()), 10); - A::translate::(|(k1, ()), v| Some((k1 as u16 * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![((4, ()), 40), ((3, ()), 30)]); + C::insert(3, 10); + C::insert(4, 10); + A::translate::(|k1, v| Some((k1 as u16 * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); @@ -504,21 +461,20 @@ mod test { assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); - assert_eq!(WithLen::decode_len((3, ())), None); - WithLen::append((0, ()), 10); - assert_eq!(WithLen::decode_len((0, ())), Some(1)); + assert_eq!(WithLen::decode_len(3), None); + WithLen::append(0, 10); + assert_eq!(WithLen::decode_len(0), Some(1)); }); } #[test] fn test_2_keys() { - type A = StorageNMap>, u32, OptionQuery>; + type A = StorageNMap, Key), u32, OptionQuery>; type AValueQueryWithAnOnEmpty = StorageNMap< - Prefix, Key>, u32, ValueQuery, ADefault + Prefix, (Key, Key), u32, ValueQuery, ADefault >; - type B = StorageNMap>, u32, ValueQuery>; - type C = StorageNMap>, u8, ValueQuery>; - type WithLen = StorageNMap>, Vec>; + type C = StorageNMap, Key), u8, ValueQuery>; + type WithLen = StorageNMap, Key), Vec>; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -526,119 +482,114 @@ mod test { k.extend(&twox_128(b"foo")); k.extend(&3u16.blake2_128_concat()); k.extend(&30u8.twox_64_concat()); - assert_eq!(A::hashed_key_for((3, (30, ()))).to_vec(), k); - - assert_eq!(A::contains_key((3, (30, ()))), false); - assert_eq!(A::get((3, (30, ()))), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 98); - - A::insert((3, (30, ())), 10); - assert_eq!(A::contains_key((3, (30, ()))), true); - assert_eq!(A::get((3, (30, ()))), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 10); - - A::swap::<_, _, Key>>((3, (30, ())), (2, (20, ()))); - assert_eq!(A::contains_key((3, (30, ()))), false); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((3, (30, ()))), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((3, (30, ()))), 98); - assert_eq!(A::get((2, (20, ()))), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get((2, (20, ()))), 10); - - A::remove((2, (20, ()))); - assert_eq!(A::contains_key((2, (20, ()))), false); - assert_eq!(A::get((2, (20, ()))), None); - - AValueQueryWithAnOnEmpty::mutate((2, (20, ())), |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate((2, (20, ())), |v| *v = *v * 2); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(98 * 4)); - - A::remove((2, (20, ()))); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, ())), |v| { + assert_eq!(A::hashed_key_for((3, 30)).to_vec(), k); + + assert_eq!(A::contains_key((3, 30)), false); + assert_eq!(A::get((3, 30)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, 30)), 98); + + A::insert((3, 30), 10); + assert_eq!(A::contains_key((3, 30)), true); + assert_eq!(A::get((3, 30)), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, 30)), 10); + + A::swap::<(Key, Key)>((3, 30), (2, 20)); + assert_eq!(A::contains_key((3, 30)), false); + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((3, 30)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3, 30)), 98); + assert_eq!(A::get((2, 20)), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2, 20)), 10); + + A::remove((2, 20)); + assert_eq!(A::contains_key((2, 20)), false); + assert_eq!(A::get((2, 20)), None); + + AValueQueryWithAnOnEmpty::mutate((2, 20), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2, 20), |v| *v = *v * 2); + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(98 * 4)); + + A::remove((2, 20)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20), |v| { *v = *v * 2; Err(()) }); - assert_eq!(A::contains_key((2, (20, ()))), false); + assert_eq!(A::contains_key((2, 20)), false); - A::remove((2, (20, ()))); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, ())), |v| { + A::remove((2, 20)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20), |v| { *v = *v * 2; Err(()) }); - assert_eq!(A::contains_key((2, (20, ()))), false); + assert_eq!(A::contains_key((2, 20)), false); - A::remove((2, (20, ()))); - AValueQueryWithAnOnEmpty::mutate_exists((2, (20, ())), |v| { + A::remove((2, 20)); + AValueQueryWithAnOnEmpty::mutate_exists((2, 20), |v| { assert!(v.is_none()); *v = Some(10); }); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists((2, (20, ())), |v| { + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2, 20), |v| { *v = Some(v.unwrap() * 10); }); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(100)); + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(100)); - A::remove((2, (20, ()))); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + A::remove((2, 20)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20), |v| { assert!(v.is_none()); *v = Some(10); Ok(()) }); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20), |v| { *v = Some(v.unwrap() * 10); Ok(()) }); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(100)); - assert_eq!(A::try_get((2, (20, ()))), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, ())), |v| { + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(100)); + assert_eq!(A::try_get((2, 20)), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20), |v| { *v = Some(v.unwrap() * 10); Err(()) }); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(100)); + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(100)); - A::insert((2, (20, ())), 10); - assert_eq!(A::take((2, (20, ()))), Some(10)); - assert_eq!(A::contains_key((2, (20, ()))), false); - assert_eq!(AValueQueryWithAnOnEmpty::take((2, (20, ()))), 98); - assert_eq!(A::contains_key((2, (20, ()))), false); - assert_eq!(A::try_get((2, (20, ()))), Err(())); + A::insert((2, 20), 10); + assert_eq!(A::take((2, 20)), Some(10)); + assert_eq!(A::contains_key((2, 20)), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2, 20)), 98); + assert_eq!(A::contains_key((2, 20)), false); + assert_eq!(A::try_get((2, 20)), Err(())); - B::insert((2, (20, ())), 10); - assert_eq!(A::migrate_keys::>, _>((2, (20, ()))), Some(10)); - assert_eq!(A::contains_key((2, (20, ()))), true); - assert_eq!(A::get((2, (20, ()))), Some(10)); - - A::insert((3, (30, ())), 10); - A::insert((4, (40, ())), 10); + A::insert((3, 30), 10); + A::insert((4, 40), 10); A::remove_all(); - assert_eq!(A::contains_key((3, (30, ()))), false); - assert_eq!(A::contains_key((4, (40, ()))), false); + assert_eq!(A::contains_key((3, 30)), false); + assert_eq!(A::contains_key((4, 40)), false); - A::insert((3, (30, ())), 10); - A::insert((4, (40, ())), 10); + A::insert((3, 30), 10); + A::insert((4, 40), 10); assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - C::insert((3, (30, ())), 10); - C::insert((4, (40, ())), 10); + C::insert((3, 30), 10); + C::insert((4, 40), 10); A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 20), ((3, (30, ())), 20)]); + assert_eq!(A::iter().collect::>(), vec![((4, 40), 20), ((3, 30), 20)]); - A::insert((3, (30, ())), 10); - A::insert((4, (40, ())), 10); - assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 10), ((3, (30, ())), 10)]); - assert_eq!(A::drain().collect::>(), vec![((4, (40, ())), 10), ((3, (30, ())), 10)]); + A::insert((3, 30), 10); + A::insert((4, 40), 10); + assert_eq!(A::iter().collect::>(), vec![((4, 40), 10), ((3, 30), 10)]); + assert_eq!(A::drain().collect::>(), vec![((4, 40), 10), ((3, 30), 10)]); assert_eq!(A::iter().collect::>(), vec![]); - C::insert((3, (30, ())), 10); - C::insert((4, (40, ())), 10); - A::translate::(|(k1, (k2, ())), v| Some((k1 * k2 as u16 * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![((4, (40, ())), 1600), ((3, (30, ())), 900)]); + C::insert((3, 30), 10); + C::insert((4, 40), 10); + A::translate::(|(k1, k2), v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![((4, 40), 1600), ((3, 30), 900)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); @@ -647,28 +598,27 @@ mod test { assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); - assert_eq!(WithLen::decode_len((3, (30, ()))), None); - WithLen::append((0, (100, ())), 10); - assert_eq!(WithLen::decode_len((0, (100, ()))), Some(1)); - - A::insert((3, (30, ())), 11); - A::insert((3, (31, ())), 12); - A::insert((4, (40, ())), 13); - A::insert((4, (41, ())), 14); - assert_eq!(A::iter_prefix_values::, _>((3, ())).collect::>(), vec![12, 11]); - assert_eq!(A::iter_prefix_values::, _>((4, ())).collect::>(), vec![13, 14]); + assert_eq!(WithLen::decode_len((3, 30)), None); + WithLen::append((0, 100), 10); + assert_eq!(WithLen::decode_len((0, 100)), Some(1)); + + A::insert((3, 30), 11); + A::insert((3, 31), 12); + A::insert((4, 40), 13); + A::insert((4, 41), 14); + assert_eq!(A::iter_prefix_values::>(3).collect::>(), vec![12, 11]); + assert_eq!(A::iter_prefix_values::>(4).collect::>(), vec![13, 14]); }); } #[test] fn test_3_keys() { - type A = StorageNMap>>, u32, OptionQuery>; + type A = StorageNMap, Key, Key), u32, OptionQuery>; type AValueQueryWithAnOnEmpty = StorageNMap< - Prefix, Key>>, u32, ValueQuery, ADefault + Prefix, (Key, Key, Key), u32, ValueQuery, ADefault >; - type B = StorageNMap>>, u32, ValueQuery>; - type C = StorageNMap>>, u8, ValueQuery>; - type WithLen = StorageNMap>>, Vec>; + type C = StorageNMap, Key, Key), u8, ValueQuery>; + type WithLen = StorageNMap, Key, Key), Vec>; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -677,119 +627,111 @@ mod test { k.extend(&1u16.blake2_128_concat()); k.extend(&10u16.blake2_128_concat()); k.extend(&100u16.twox_64_concat()); - assert_eq!(A::hashed_key_for((1, (10, (100, ())))).to_vec(), k); + assert_eq!(A::hashed_key_for((1, 10, 100)).to_vec(), k); - assert_eq!(A::contains_key((1, (10, (100, ())))), false); - assert_eq!(A::get((1, (10, (100, ())))), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 98); + assert_eq!(A::contains_key((1, 10, 100)), false); + assert_eq!(A::get((1, 10, 100)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 98); - A::insert((1, (10, (100, ()))), 30); - assert_eq!(A::contains_key((1, (10, (100, ())))), true); - assert_eq!(A::get((1, (10, (100, ())))), Some(30)); - assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 30); + A::insert((1, 10, 100), 30); + assert_eq!(A::contains_key((1, 10, 100)), true); + assert_eq!(A::get((1, 10, 100)), Some(30)); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 30); - A::swap::<_, _, Key>>>( - (1, (10, (100, ()))), - (2, (20, (200, ()))), + A::swap::<(Key, Key, Key)>( + (1, 10, 100), + (2, 20, 200), ); - assert_eq!(A::contains_key((1, (10, (100, ())))), false); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((1, (10, (100, ())))), None); - assert_eq!(AValueQueryWithAnOnEmpty::get((1, (10, (100, ())))), 98); - assert_eq!(A::get((2, (20, (200, ())))), Some(30)); - assert_eq!(AValueQueryWithAnOnEmpty::get((2, (20, (200, ())))), 30); - - A::remove((2, (20, (200, ())))); - assert_eq!(A::contains_key((2, (20, (200, ())))), false); - assert_eq!(A::get((2, (20, (200, ())))), None); - - AValueQueryWithAnOnEmpty::mutate((2, (20, (200, ()))), |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate((2, (20, (200, ()))), |v| *v = *v * 2); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(98 * 4)); - - A::remove((2, (20, (200, ())))); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, (20, (200, ()))), |v| { + assert_eq!(A::contains_key((1, 10, 100)), false); + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((1, 10, 100)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 98); + assert_eq!(A::get((2, 20, 200)), Some(30)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2, 20, 200)), 30); + + A::remove((2, 20, 200)); + assert_eq!(A::contains_key((2, 20, 200)), false); + assert_eq!(A::get((2, 20, 200)), None); + + AValueQueryWithAnOnEmpty::mutate((2, 20, 200), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2, 20, 200), |v| *v = *v * 2); + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(98 * 4)); + + A::remove((2, 20, 200)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20, 200), |v| { *v = *v * 2; Err(()) }); - assert_eq!(A::contains_key((2, (20, (200, ())))), false); + assert_eq!(A::contains_key((2, 20, 200)), false); - A::remove((2, (20, (200, ())))); - AValueQueryWithAnOnEmpty::mutate_exists((2, (20, (200, ()))), |v| { + A::remove((2, 20, 200)); + AValueQueryWithAnOnEmpty::mutate_exists((2, 20, 200), |v| { assert!(v.is_none()); *v = Some(10); }); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists((2, (20, (200, ()))), |v| { + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2, 20, 200), |v| { *v = Some(v.unwrap() * 10); }); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(100)); + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(100)); - A::remove((2, (20, (200, ())))); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + A::remove((2, 20, 200)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { assert!(v.is_none()); *v = Some(10); Ok(()) }); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { *v = Some(v.unwrap() * 10); Ok(()) }); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(100)); - assert_eq!(A::try_get((2, (20, (200, ())))), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, (20, (200, ()))), |v| { + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(100)); + assert_eq!(A::try_get((2, 20, 200)), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { *v = Some(v.unwrap() * 10); Err(()) }); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(100)); - - - A::insert((2, (20, (200, ()))), 10); - assert_eq!(A::take((2, (20, (200, ())))), Some(10)); - assert_eq!(A::contains_key((2, (20, (200, ())))), false); - assert_eq!(AValueQueryWithAnOnEmpty::take((2, (20, (200, ())))), 98); - assert_eq!(A::contains_key((2, (20, (200, ())))), false); - assert_eq!(A::try_get((2, (20, (200, ())))), Err(())); - - B::insert((2, (20, (200, ()))), 10); - assert_eq!(A::migrate_keys::< - KeyHasher>>, - _, - >((2, (20, (200, ())))), Some(10)); - assert_eq!(A::contains_key((2, (20, (200, ())))), true); - assert_eq!(A::get((2, (20, (200, ())))), Some(10)); - - A::insert((3, (30, (300, ()))), 10); - A::insert((4, (40, (400, ()))), 10); + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(100)); + + + A::insert((2, 20, 200), 10); + assert_eq!(A::take((2, 20, 200)), Some(10)); + assert_eq!(A::contains_key((2, 20, 200)), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2, 20, 200)), 98); + assert_eq!(A::contains_key((2, 20, 200)), false); + assert_eq!(A::try_get((2, 20, 200)), Err(())); + + A::insert((3, 30, 300), 10); + A::insert((4, 40, 400), 10); A::remove_all(); - assert_eq!(A::contains_key((3, (30, (300, ())))), false); - assert_eq!(A::contains_key((4, (40, (400, ())))), false); + assert_eq!(A::contains_key((3, 30, 300)), false); + assert_eq!(A::contains_key((4, 40, 400)), false); - A::insert((3, (30, (300, ()))), 10); - A::insert((4, (40, (400, ()))), 10); + A::insert((3, 30, 300), 10); + A::insert((4, 40, 400), 10); assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - C::insert((3, (30, (300, ()))), 10); - C::insert((4, (40, (400, ()))), 10); + C::insert((3, 30, 300), 10); + C::insert((4, 40, 400), 10); A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 20), ((3, (30, (300, ()))), 20)]); + assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 20), ((3, 30, 300), 20)]); - A::insert((3, (30, (300, ()))), 10); - A::insert((4, (40, (400, ()))), 10); - assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 10), ((3, (30, (300, ()))), 10)]); - assert_eq!(A::drain().collect::>(), vec![((4, (40, (400, ()))), 10), ((3, (30, (300, ()))), 10)]); + A::insert((3, 30, 300), 10); + A::insert((4, 40, 400), 10); + assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 10), ((3, 30, 300), 10)]); + assert_eq!(A::drain().collect::>(), vec![((4, 40, 400), 10), ((3, 30, 300), 10)]); assert_eq!(A::iter().collect::>(), vec![]); - C::insert((3, (30, (300, ()))), 10); - C::insert((4, (40, (400, ()))), 10); - A::translate::(|(k1, (k2, (k3, ()))), v| Some((k1 * k2 as u16 * v as u16 / k3 as u16).into())); - assert_eq!(A::iter().collect::>(), vec![((4, (40, (400, ()))), 4), ((3, (30, (300, ()))), 3)]); + C::insert((3, 30, 300), 10); + C::insert((4, 40, 400), 10); + A::translate::(|(k1, k2, k3), v| Some((k1 * k2 as u16 * v as u16 / k3 as u16).into())); + assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 4), ((3, 30, 300), 3)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); @@ -798,16 +740,16 @@ mod test { assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); - assert_eq!(WithLen::decode_len((3, (30, (300, ())))), None); - WithLen::append((0, (100, (1000, ()))), 10); - assert_eq!(WithLen::decode_len((0, (100, (1000, ())))), Some(1)); - - A::insert((3, (30, (300, ()))), 11); - A::insert((3, (30, (301, ()))), 12); - A::insert((4, (40, (400, ()))), 13); - A::insert((4, (40, (401, ()))), 14); - assert_eq!(A::iter_prefix_values::>, _>((3, (30, ()))).collect::>(), vec![11, 12]); - assert_eq!(A::iter_prefix_values::>, _>((4, (40, ()))).collect::>(), vec![14, 13]); + assert_eq!(WithLen::decode_len((3, 30, 300)), None); + WithLen::append((0, 100, 1000), 10); + assert_eq!(WithLen::decode_len((0, 100, 1000)), Some(1)); + + A::insert((3, 30, 300), 11); + A::insert((3, 30, 301), 12); + A::insert((4, 40, 400), 13); + A::insert((4, 40, 401), 14); + assert_eq!(A::iter_prefix_values::<(Key, Key)>((3, 30)).collect::>(), vec![11, 12]); + assert_eq!(A::iter_prefix_values::<(Key, Key)>((4, 40)).collect::>(), vec![14, 13]); }); } } From a89bf4138800cf6706bb936330f539f00e245d4a Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 21 Apr 2021 21:59:02 -0700 Subject: [PATCH 04/34] Implement prefix iteration on StorageNMap --- frame/support/src/storage/generator/nmap.rs | 74 ++++-- frame/support/src/storage/mod.rs | 18 +- frame/support/src/storage/types/key.rs | 256 +++++++++++++++++++- frame/support/src/storage/types/mod.rs | 2 +- frame/support/src/storage/types/nmap.rs | 46 +++- 5 files changed, 360 insertions(+), 36 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 9a41448c00799..edc83f490554b 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -22,7 +22,7 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ self, unhashed, - types::{KeyGenerator, ReversibleKeyGenerator}, + types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, StorageAppend, PrefixIterator }, Never, hash::{StorageHasher, Twox128}, @@ -74,10 +74,13 @@ pub trait StorageNMap { fn from_query_to_optional_value(v: Self::Query) -> Option; /// Generate a partial key used in top storage. - fn storage_n_map_partial_key(key: KG::Key) -> Vec { + fn storage_n_map_partial_key(key: KP) -> Vec + where + K: HasKeyPrefix, + { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); - let key_hashed = KG::final_key(key); + let key_hashed = >::partial_key(key); let mut final_key = Vec::with_capacity( module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() @@ -91,10 +94,10 @@ pub trait StorageNMap { } /// Generate the full key used in top storage. - fn storage_n_map_final_key(key: K::Key) -> Vec { + fn storage_n_map_final_key(key: KG::Key) -> Vec { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); - let key_hashed = K::final_key(key); + let key_hashed = KG::final_key(key); let mut final_key = Vec::with_capacity( module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() @@ -117,32 +120,31 @@ where type Query = G::Query; fn hashed_key_for(key: K::Key) -> Vec { - Self::storage_n_map_final_key(key) + Self::storage_n_map_final_key::(key) } fn contains_key(key: K::Key) -> bool { - unhashed::exists(&Self::storage_n_map_final_key(key)) + unhashed::exists(&Self::storage_n_map_final_key::(key)) } fn get(key: K::Key) -> Self::Query { - G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key(key))) + G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::(key))) } fn try_get(key: K::Key) -> Result { - unhashed::get(&Self::storage_n_map_final_key(key)).ok_or(()) + unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) } fn take(key: K::Key) -> Self::Query { - let final_key = Self::storage_n_map_final_key(key); + let final_key = Self::storage_n_map_final_key::(key); let value = unhashed::take(&final_key); G::from_optional_value_to_query(value) } fn swap(key1: K::Key, key2: KOther::Key) { - let final_x_key = Self::storage_n_map_final_key(key1); - // Not really a partial key, but only this function allows us to specify a foreign key generator - let final_y_key = Self::storage_n_map_partial_key::(key2); + let final_x_key = Self::storage_n_map_final_key::(key1); + let final_y_key = Self::storage_n_map_final_key::(key2); let v1 = unhashed::get_raw(&final_x_key); if let Some(val) = unhashed::get_raw(&final_y_key) { @@ -158,19 +160,22 @@ where } fn insert>(key: K::Key, val: VArg) { - unhashed::put(&Self::storage_n_map_final_key(key), &val.borrow()); + unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); } fn remove(key: K::Key) { - unhashed::kill(&Self::storage_n_map_final_key(key)); + unhashed::kill(&Self::storage_n_map_final_key::(key)); } - fn remove_prefix(partial_key: KG::Key) { - unhashed::kill_prefix(&Self::storage_n_map_partial_key::(partial_key)); + fn remove_prefix(partial_key: KP) where K: HasKeyPrefix { + unhashed::kill_prefix(&Self::storage_n_map_partial_key(partial_key)); } - fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator { - let prefix = Self::storage_n_map_partial_key::(partial_key); + fn iter_prefix_values(partial_key: KP) -> PrefixIterator + where + K: HasKeyPrefix, + { + let prefix = Self::storage_n_map_partial_key(partial_key); PrefixIterator { prefix: prefix.clone(), previous_key: prefix, @@ -184,7 +189,7 @@ where } fn try_mutate Result>(key: K::Key, f: F) -> Result { - let final_key = Self::storage_n_map_final_key(key); + let final_key = Self::storage_n_map_final_key::(key); let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref())); let ret = f(&mut val); @@ -202,7 +207,7 @@ where } fn try_mutate_exists) -> Result>(key: K::Key, f: F) -> Result { - let final_key = Self::storage_n_map_final_key(key); + let final_key = Self::storage_n_map_final_key::(key); let mut val = unhashed::get(final_key.as_ref()); let ret = f(&mut val); @@ -221,7 +226,7 @@ where EncodeLikeItem: EncodeLike, V: StorageAppend { - let final_key = Self::storage_n_map_final_key(key); + let final_key = Self::storage_n_map_final_key::(key); sp_io::storage::append(&final_key, item.encode()); } } @@ -229,6 +234,31 @@ where impl> storage::IterableStorageNMap for G { type Iterator = PrefixIterator<(K::Key, V)>; + fn iter_prefix(kp: KP) -> PrefixIterator<(>::Suffix, V)> + where + K: HasReversibleKeyPrefix, + { + let prefix = G::storage_n_map_partial_key(kp); + PrefixIterator { + prefix: prefix.clone(), + previous_key: prefix, + drain: false, + closure: |raw_key_without_prefix, mut raw_value| { + let partial_key = K::decode_partial_key(raw_key_without_prefix)?; + Ok((partial_key, V::decode(&mut raw_value)?)) + }, + } + } + + fn drain_prefix(kp: KP) -> PrefixIterator<(>::Suffix, V)> + where + K: HasReversibleKeyPrefix, + { + let mut iter = Self::iter_prefix(kp); + iter.drain = true; + iter + } + fn iter() -> Self::Iterator { let prefix = G::prefix_hash(); Self::Iterator { diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 5b9c988fa8179..7a8fc3b2a9d97 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -22,7 +22,7 @@ use sp_std::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, - storage::types::{KeyGenerator, ReversibleKeyGenerator}, + storage::types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, traits::Get, }; use sp_runtime::generic::{Digest, DigestItem}; @@ -366,6 +366,18 @@ pub trait IterableStorageNMap: StorageN /// The type that iterates over all `(key1, (key2, (key3, ... (keyN, ()))), value)` tuples type Iterator: Iterator; + /// Enumerate all elements in the map with prefix key `kp` in no particular order. If you add or + /// remove values whose prefix is `kp` to the map while doing this, you'll get undefined + /// results. + fn iter_prefix(kp: KP) -> PrefixIterator<(>::Suffix, V)> + where K: HasReversibleKeyPrefix; + + /// Remove all elements from the map with prefix key `kp` and iterate through them in no + /// particular order. If you add elements with prefix key `kp` to the map while doing this, + /// you'll get undefined results. + fn drain_prefix(kp: KP) -> PrefixIterator<(>::Suffix, V)> + where K: HasReversibleKeyPrefix; + /// Enumerate all elements in the map in no particular order. If you add or remove values to /// the map while doing this, you'll get undefined results. fn iter() -> Self::Iterator; @@ -563,10 +575,10 @@ pub trait StorageNMap { fn remove(key: K::Key); /// Remove all values under the partial prefix key. - fn remove_prefix(partial_key: KG::Key); + fn remove_prefix(partial_key: KP) where K: HasKeyPrefix; /// Iterate over values that share the partial prefix key. - fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator; + fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix; /// Mutate the value under a key. fn mutate R>(key: K::Key, f: F) -> R; diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 4bbcb5ba38ba2..3a74576a6cd98 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -19,6 +19,7 @@ use crate::hash::{ReversibleStorageHasher, StorageHasher}; use codec::{EncodeLike, FullCodec}; +use paste::paste; use sp_std::prelude::*; /// A type used exclusively by storage maps as their key type. @@ -34,7 +35,7 @@ pub struct Key( core::marker::PhantomData<(Hasher, KeyType)>, ); -/// A trait that contains the current key as an associated type and generates the next key. +/// A trait that contains the current key as an associated type. pub trait KeyGenerator { type Key: EncodeLike; @@ -95,3 +96,256 @@ impl ReversibleKeyGenerator for Tuple { ), current_key_material)) } } + +/// Trait indicating whether a KeyGenerator has the prefix P. +pub trait HasKeyPrefix

: KeyGenerator { + type Suffix; + + fn partial_key(prefix: P) -> Vec; +} + +/// Trait indicating whether a ReversibleKeyGenerator has the prefix P. +pub trait HasReversibleKeyPrefix

: ReversibleKeyGenerator + HasKeyPrefix

{ + fn decode_partial_key(key_material: &[u8]) -> Result; +} + +macro_rules! impl_key_prefix_for { + (($($keygen:ident),+), ($($prefix:ident),+), ($($suffix:ident),+)) => { + paste! { + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: StorageHasher),+> + HasKeyPrefix<($($prefix),+)> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + type Suffix = ($($suffix),+); + + fn partial_key(prefix: ($($prefix),+)) -> Vec { + <($(Key<[<$prefix $prefix>], $prefix>),+)>::final_key(prefix) + } + } + + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: ReversibleStorageHasher),+> + HasReversibleKeyPrefix<($($prefix),+)> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + fn decode_partial_key(key_material: &[u8]) -> Result { + <($(Key<[<$suffix $suffix>], $suffix>),+)>::decode_final_key(key_material).map(|k| k.0) + } + } + } + }; + (($($keygen:ident),+), $prefix:ident, ($($suffix:ident),+)) => { + paste! { + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: StorageHasher),+> + HasKeyPrefix<$prefix> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + type Suffix = ($($suffix),+); + + fn partial_key(prefix: $prefix) -> Vec { + ], $prefix>>::final_key(prefix) + } + } + + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: ReversibleStorageHasher),+> + HasReversibleKeyPrefix<$prefix> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + fn decode_partial_key(key_material: &[u8]) -> Result { + <($(Key<[<$suffix $suffix>], $suffix>),+)>::decode_final_key(key_material).map(|k| k.0) + } + } + } + }; + (($($keygen:ident),+), ($($prefix:ident),+), $suffix:ident) => { + paste! { + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: StorageHasher),+> + HasKeyPrefix<($($prefix),+)> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + type Suffix = $suffix; + + fn partial_key(prefix: ($($prefix),+)) -> Vec { + <($(Key<[<$prefix $prefix>], $prefix>),+)>::final_key(prefix) + } + } + + impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: ReversibleStorageHasher),+> + HasReversibleKeyPrefix<($($prefix),+)> for + ($(Key<[<$keygen $keygen>], $keygen>),+) + { + fn decode_partial_key(key_material: &[u8]) -> Result { + ], $suffix>>::decode_final_key(key_material).map(|k| k.0) + } + } + } + }; +} + +impl HasKeyPrefix for (Key, Key) { + type Suffix = B; + + fn partial_key(prefix: A) -> Vec { + >::final_key(prefix) + } +} + +impl + HasReversibleKeyPrefix for (Key, Key) +{ + fn decode_partial_key(key_material: &[u8]) -> Result { + >::decode_final_key(key_material).map(|k| k.0) + } +} + +impl_key_prefix_for!((A, B, C), (A, B), C); +impl_key_prefix_for!((A, B, C), A, (B, C)); +impl_key_prefix_for!((A, B, C, D), (A, B, C), D); +impl_key_prefix_for!((A, B, C, D), (A, B), (C, D)); +impl_key_prefix_for!((A, B, C, D), A, (B, C, D)); +impl_key_prefix_for!((A, B, C, D, E), (A, B, C, D), E); +impl_key_prefix_for!((A, B, C, D, E), (A, B, C), (D, E)); +impl_key_prefix_for!((A, B, C, D, E), (A, B), (C, D, E)); +impl_key_prefix_for!((A, B, C, D, E), A, (B, C, D, E)); +impl_key_prefix_for!((A, B, C, D, E, F), (A, B, C, D, E), F); +impl_key_prefix_for!((A, B, C, D, E, F), (A, B, C, D), (E, F)); +impl_key_prefix_for!((A, B, C, D, E, F), (A, B, C), (D, E, F)); +impl_key_prefix_for!((A, B, C, D, E, F), (A, B), (C, D, E, F)); +impl_key_prefix_for!((A, B, C, D, E, F), A, (B, C, D, E, F)); +impl_key_prefix_for!((A, B, C, D, E, F, G), (A, B, C, D, E, F), G); +impl_key_prefix_for!((A, B, C, D, E, F, G), (A, B, C, D, E), (F, G)); +impl_key_prefix_for!((A, B, C, D, E, F, G), (A, B, C, D), (E, F, G)); +impl_key_prefix_for!((A, B, C, D, E, F, G), (A, B, C), (D, E, F, G)); +impl_key_prefix_for!((A, B, C, D, E, F, G), (A, B), (C, D, E, F, G)); +impl_key_prefix_for!((A, B, C, D, E, F, G), A, (B, C, D, E, F, G)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B, C, D, E, F, G), H); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B, C, D, E, F), (G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B, C, D, E), (F, G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B, C, D), (E, F, G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B, C), (D, E, F, G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), (A, B), (C, D, E, F, G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H), A, (B, C, D, E, F, G, H)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D, E, F, G, H), I); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D, E, F, G), (H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D, E, F), (G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D, E), (F, G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D), (E, F, G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C), (D, E, F, G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B), (C, D, E, F, G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), A, (B, C, D, E, F, G, H, I)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G, H, I), J); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G, H), (I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G), (H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F), (G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E), (F, G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D), (E, F, G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C), (D, E, F, G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B), (C, D, E, F, G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), A, (B, C, D, E, F, G, H, I, J)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H, I, J), K); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H, I), (J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H), (I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G), (H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F), (G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E), (F, G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D), (E, F, G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C), (D, E, F, G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B), (C, D, E, F, G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), A, (B, C, D, E, F, G, H, I, J, K)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I, J, K), L); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I, J), (K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I), (J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H), (I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G), (H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F), (G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E), (F, G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D), (E, F, G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C), (D, E, F, G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B), (C, D, E, F, G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), A, (B, C, D, E, F, G, H, I, J, K, L)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J, K, L), M); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J, K), (L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J), (K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I), (J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H), (I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G), (H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F), (G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E), (F, G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D), (E, F, G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C), (D, E, F, G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B), (C, D, E, F, G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), A, (B, C, D, E, F, G, H, I, J, K, L, M)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K, L, M), N); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), A, (B, C, D, E, F, G, H, I, J, K, L, M, N)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), O); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), P); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), Q); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), R); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 012b9a9698036..b49855b45c682 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -27,7 +27,7 @@ mod map; mod nmap; mod double_map; -pub use key::{Key, KeyGenerator, ReversibleKeyGenerator}; +pub use key::{HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator}; pub use value::{StorageValue, StorageValueMetadata}; pub use map::{StorageMap, StorageMapMetadata}; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index d5539b787b3b1..7434874628ee5 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -21,7 +21,7 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + types::{HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter, OptionQuery, QueryKindTrait}, KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, }, traits::{GetDefault, StorageInstance}, @@ -145,13 +145,16 @@ where } /// Remove all values under the first key. - pub fn remove_prefix(partial_key: KG::Key) { - >::remove_prefix::(partial_key) + pub fn remove_prefix(partial_key: KP) where Key: HasKeyPrefix { + >::remove_prefix(partial_key) } /// Iterate over values that share the first key. - pub fn iter_prefix_values(partial_key: KG::Key) -> PrefixIterator { - >::iter_prefix_values::(partial_key) + pub fn iter_prefix_values(partial_key: KP) -> PrefixIterator + where + Key: HasKeyPrefix, + { + >::iter_prefix_values(partial_key) } /// Mutate the value under the given keys. @@ -258,6 +261,29 @@ where QueryKind: QueryKindTrait, OnEmpty: crate::traits::Get + 'static { + /// Enumerate all elements in the map with prefix key `kp` in no particular order. + /// + /// If you add or remove values whose prefix key is `kp` to the map while doing this, you'll get + /// undefined results. + pub fn iter_prefix(kp: KP) -> crate::storage::PrefixIterator<(>::Suffix, Value)> + where + Key: HasReversibleKeyPrefix, + { + >::iter_prefix(kp) + } + + /// Remove all elements from the map with prefix key `kp` and iterate through them in no + /// particular order. + /// + /// If you add elements with prefix key `k1` to the map while doing this, you'll get undefined + /// results. + pub fn drain_prefix(kp: KP) -> crate::storage::PrefixIterator<(>::Suffix, Value)> + where + Key: HasReversibleKeyPrefix, + { + >::drain_prefix(kp) + } + /// Enumerate all elements in the map in no particular order. /// /// If you add or remove values to the map while doing this, you'll get undefined results. @@ -606,8 +632,8 @@ mod test { A::insert((3, 31), 12); A::insert((4, 40), 13); A::insert((4, 41), 14); - assert_eq!(A::iter_prefix_values::>(3).collect::>(), vec![12, 11]); - assert_eq!(A::iter_prefix_values::>(4).collect::>(), vec![13, 14]); + assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); + assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); }); } @@ -748,8 +774,10 @@ mod test { A::insert((3, 30, 301), 12); A::insert((4, 40, 400), 13); A::insert((4, 40, 401), 14); - assert_eq!(A::iter_prefix_values::<(Key, Key)>((3, 30)).collect::>(), vec![11, 12]); - assert_eq!(A::iter_prefix_values::<(Key, Key)>((4, 40)).collect::>(), vec![14, 13]); + assert_eq!(A::iter_prefix_values(3).collect::>(), vec![11, 12]); + assert_eq!(A::iter_prefix_values(4).collect::>(), vec![14, 13]); + assert_eq!(A::iter_prefix_values((3, 30)).collect::>(), vec![11, 12]); + assert_eq!(A::iter_prefix_values((4, 40)).collect::>(), vec![14, 13]); }); } } From 6b17d09fdf393ee28b4597baffebb8660aecd86b Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 22 Apr 2021 15:51:33 -0700 Subject: [PATCH 05/34] Implement EncodeLike for key arguments --- frame/support/src/storage/generator/nmap.rs | 78 ++++--- frame/support/src/storage/mod.rs | 41 ++-- frame/support/src/storage/types/key.rs | 63 ++++-- frame/support/src/storage/types/mod.rs | 2 +- frame/support/src/storage/types/nmap.rs | 213 +++++++++++--------- 5 files changed, 241 insertions(+), 156 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index edc83f490554b..c7fbf381e3733 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -23,7 +23,7 @@ use crate::{ storage::{ self, unhashed, types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, - StorageAppend, PrefixIterator + PrefixIterator, StorageAppend, TupleToEncodedIter, }, Never, hash::{StorageHasher, Twox128}, }; @@ -94,7 +94,11 @@ pub trait StorageNMap { } /// Generate the full key used in top storage. - fn storage_n_map_final_key(key: KG::Key) -> Vec { + fn storage_n_map_final_key(key: KArg) -> Vec + where + KG: KeyGenerator, + KArg: EncodeLike + TupleToEncodedIter, + { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); let key_hashed = KG::final_key(key); @@ -119,32 +123,37 @@ where { type Query = G::Query; - fn hashed_key_for(key: K::Key) -> Vec { - Self::storage_n_map_final_key::(key) + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { + Self::storage_n_map_final_key::(key) } - fn contains_key(key: K::Key) -> bool { - unhashed::exists(&Self::storage_n_map_final_key::(key)) + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { + unhashed::exists(&Self::storage_n_map_final_key::(key)) } - fn get(key: K::Key) -> Self::Query { - G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::(key))) + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query { + G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::(key))) } - fn try_get(key: K::Key) -> Result { - unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) + fn try_get + TupleToEncodedIter>(key: KArg) -> Result { + unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) } - fn take(key: K::Key) -> Self::Query { - let final_key = Self::storage_n_map_final_key::(key); + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { + let final_key = Self::storage_n_map_final_key::(key); let value = unhashed::take(&final_key); G::from_optional_value_to_query(value) } - fn swap(key1: K::Key, key2: KOther::Key) { - let final_x_key = Self::storage_n_map_final_key::(key1); - let final_y_key = Self::storage_n_map_final_key::(key2); + fn swap(key1: KArg1, key2: KArg2) + where + KOther: KeyGenerator, + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter, + { + let final_x_key = Self::storage_n_map_final_key::(key1); + let final_y_key = Self::storage_n_map_final_key::(key2); let v1 = unhashed::get_raw(&final_x_key); if let Some(val) = unhashed::get_raw(&final_y_key) { @@ -159,19 +168,19 @@ where } } - fn insert>(key: K::Key, val: VArg) { - unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); + fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { + unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); } - fn remove(key: K::Key) { - unhashed::kill(&Self::storage_n_map_final_key::(key)); + fn remove + TupleToEncodedIter>(key: KArg) { + unhashed::kill(&Self::storage_n_map_final_key::(key)); } fn remove_prefix(partial_key: KP) where K: HasKeyPrefix { unhashed::kill_prefix(&Self::storage_n_map_partial_key(partial_key)); } - fn iter_prefix_values(partial_key: KP) -> PrefixIterator + fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix, { @@ -184,12 +193,18 @@ where } } - fn mutate R>(key: K::Key, f: F) -> R { + fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>( + key: KArg, + f: F, + ) -> R { Self::try_mutate(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate Result>(key: K::Key, f: F) -> Result { - let final_key = Self::storage_n_map_final_key::(key); + fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( + key: KArg, + f: F, + ) -> Result { + let final_key = Self::storage_n_map_final_key::(key); let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref())); let ret = f(&mut val); @@ -202,12 +217,18 @@ where ret } - fn mutate_exists) -> R>(key: K::Key, f: F) -> R { + fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>( + key: KArg, + f: F, + ) -> R { Self::try_mutate_exists(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate_exists) -> Result>(key: K::Key, f: F) -> Result { - let final_key = Self::storage_n_map_final_key::(key); + fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( + key: KArg, + f: F, + ) -> Result { + let final_key = Self::storage_n_map_final_key::(key); let mut val = unhashed::get(final_key.as_ref()); let ret = f(&mut val); @@ -220,13 +241,14 @@ where ret } - fn append(key: K::Key, item: EncodeLikeItem) + fn append(key: KArg, item: EncodeLikeItem) where + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend { - let final_key = Self::storage_n_map_final_key::(key); + let final_key = Self::storage_n_map_final_key::(key); sp_io::storage::append(&final_key, item.encode()); } } diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 7a8fc3b2a9d97..a8717ca0f6b5a 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -22,7 +22,7 @@ use sp_std::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, - storage::types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, + storage::types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator, TupleToEncodedIter}, traits::Get, }; use sp_runtime::generic::{Digest, DigestItem}; @@ -552,27 +552,31 @@ pub trait StorageNMap { type Query; /// Get the storage key used to fetch a value corresponding to a specific key. - fn hashed_key_for(key: K::Key) -> Vec; + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec; /// Does the value (explicitly) exist in storage? - fn contains_key(key: K::Key) -> bool; + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool; /// Load the value associated with the given key from the map. - fn get(key: K::Key) -> Self::Query; + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - fn try_get(key: K::Key) -> Result; + fn try_get + TupleToEncodedIter>(key: KArg) -> Result; /// Swap the values of two keys. - fn swap(key1: K::Key, key2: KOther::Key); + fn swap(key1: KArg1, key2: KArg2) + where + KOther: KeyGenerator, + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter; /// Store a value to be associated with the given key from the map. - fn insert>(key: K::Key, val: VArg); + fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg); /// Remove the value under a key. - fn remove(key: K::Key); + fn remove + TupleToEncodedIter>(key: KArg); /// Remove all values under the partial prefix key. fn remove_prefix(partial_key: KP) where K: HasKeyPrefix; @@ -581,21 +585,27 @@ pub trait StorageNMap { fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix; /// Mutate the value under a key. - fn mutate R>(key: K::Key, f: F) -> R; + fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>(key: KArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. - fn try_mutate Result>(key: K::Key, f: F) -> Result; + fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( + key: KArg, + f: F, + ) -> Result; /// Mutate the value under a key. /// /// Deletes the item if mutated to a `None`. - fn mutate_exists) -> R>(key: K::Key, f: F) -> R; + fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>(key: KArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - fn try_mutate_exists) -> Result>(key: K::Key, f: F) -> Result; + fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( + key: KArg, + f: F, + ) -> Result; /// Take the value under a key. - fn take(key: K::Key) -> Self::Query; + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Append the given items to the value in the storage. /// @@ -606,8 +616,9 @@ pub trait StorageNMap { /// If the storage item is not encoded properly, the storage will be overwritten /// and set to `[item]`. Any default value set for the storage item will be ignored /// on overwrite. - fn append(key: K::Key, item: EncodeLikeItem) + fn append(key: KArg, item: EncodeLikeItem) where + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend; @@ -624,7 +635,7 @@ pub trait StorageNMap { /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - fn decode_len(key: K::Key) -> Option + fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where V: StorageDecodeLength, { diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 3a74576a6cd98..fa3dbe0ffbd11 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -18,7 +18,7 @@ //! Storage key type. use crate::hash::{ReversibleStorageHasher, StorageHasher}; -use codec::{EncodeLike, FullCodec}; +use codec::{Encode, EncodeLike, FullCodec}; use paste::paste; use sp_std::prelude::*; @@ -38,29 +38,66 @@ pub struct Key( /// A trait that contains the current key as an associated type. pub trait KeyGenerator { type Key: EncodeLike; + type Arg: Encode; - fn final_key(key: Self::Key) -> Vec; + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn final_hash(encoded: &[u8]) -> Vec; } impl KeyGenerator for Key { type Key = K; + type Arg = (K,); - fn final_key(key: Self::Key) -> Vec { - key.using_encoded(H::hash).as_ref().to_vec() + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + H::hash(&key.to_encoded_iter().next().expect("should have at least one element!")).as_ref().to_vec() + } + + fn final_hash(encoded: &[u8]) -> Vec { + H::hash(encoded).as_ref().to_vec() } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] impl KeyGenerator for Tuple { for_tuples!( type Key = ( #(Tuple::Key),* ); ); + for_tuples!( type Arg = ( #(Tuple::Key),* ); ); - fn final_key(key: Self::Key) -> Vec { + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { let mut final_key = Vec::new(); + let mut iter = key.to_encoded_iter(); for_tuples!( - #( final_key.extend_from_slice(&Tuple::final_key(key.Tuple)); )* + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + final_key.extend_from_slice(&Tuple::final_hash(&next_encoded)); + )* ); final_key } + + fn final_hash(encoded: &[u8]) -> Vec { + panic!("final_hash called on KeyGenerator tuple") + } +} + +pub trait TupleToEncodedIter { + fn to_encoded_iter(self) -> Box>>; +} + +impl TupleToEncodedIter for (A,) { + fn to_encoded_iter(self) -> Box>> { + Box::new(sp_std::iter::once(self.0.encode())) + } +} + +#[impl_trait_for_tuples::impl_for_tuples(2, 18)] +#[tuple_types_no_default_trait_bound] +impl TupleToEncodedIter for Tuple { + for_tuples!( where #(Tuple: Encode),* ); + fn to_encoded_iter(self) -> Box>> { + let mut iter: Box>> = Box::new(sp_std::iter::empty::>()); + for_tuples!( #(iter = Box::new(iter.chain((self.Tuple,).to_encoded_iter()));)* ); + iter + } } /// A trait that indicates the hashers for the keys generated are all reversible. @@ -136,18 +173,18 @@ macro_rules! impl_key_prefix_for { (($($keygen:ident),+), $prefix:ident, ($($suffix:ident),+)) => { paste! { impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: StorageHasher),+> - HasKeyPrefix<$prefix> for + HasKeyPrefix<($prefix,)> for ($(Key<[<$keygen $keygen>], $keygen>),+) { type Suffix = ($($suffix),+); - fn partial_key(prefix: $prefix) -> Vec { + fn partial_key(prefix: ($prefix,)) -> Vec { ], $prefix>>::final_key(prefix) } } impl<$($keygen: FullCodec,)+ $( [<$keygen $keygen>]: ReversibleStorageHasher),+> - HasReversibleKeyPrefix<$prefix> for + HasReversibleKeyPrefix<($prefix,)> for ($(Key<[<$keygen $keygen>], $keygen>),+) { fn decode_partial_key(key_material: &[u8]) -> Result { @@ -181,16 +218,18 @@ macro_rules! impl_key_prefix_for { }; } -impl HasKeyPrefix for (Key, Key) { +impl + HasKeyPrefix<(A,)> for (Key, Key) +{ type Suffix = B; - fn partial_key(prefix: A) -> Vec { + fn partial_key(prefix: (A,)) -> Vec { >::final_key(prefix) } } impl - HasReversibleKeyPrefix for (Key, Key) + HasReversibleKeyPrefix<(A,)> for (Key, Key) { fn decode_partial_key(key_material: &[u8]) -> Result { >::decode_final_key(key_material).map(|k| k.0) diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index b49855b45c682..07b8700616bd3 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -27,7 +27,7 @@ mod map; mod nmap; mod double_map; -pub use key::{HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator}; +pub use key::{HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator, TupleToEncodedIter}; pub use value::{StorageValue, StorageValueMetadata}; pub use map::{StorageMap, StorageMapMetadata}; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 7434874628ee5..ea8d5292ded79 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -22,7 +22,7 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ types::{HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter, OptionQuery, QueryKindTrait}, - KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, + KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, TupleToEncodedIter, }, traits::{GetDefault, StorageInstance}, }; @@ -103,44 +103,49 @@ where OnEmpty: crate::traits::Get + 'static, { /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for(key: Key::Key) -> Vec { + pub fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { >::hashed_key_for(key) } /// Does the value (explicitly) exist in storage? - pub fn contains_key(key: Key::Key) -> bool { + pub fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { >::contains_key(key) } /// Load the value associated with the given key from the map. - pub fn get(key: Key::Key) -> QueryKind::Query { + pub fn get + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::get(key) } /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get(key: Key::Key) -> Result { + pub fn try_get + TupleToEncodedIter>(key: KArg) -> Result { >::try_get(key) } /// Take a value from storage, removing it afterwards. - pub fn take(key: Key::Key) -> QueryKind::Query { + pub fn take + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::take(key) } /// Swap the values of two key-pairs. - pub fn swap(key1: Key::Key, key2: KOther::Key) { - >::swap::(key1, key2) + pub fn swap(key1: KArg1, key2: KArg2) + where + KOther: KeyGenerator, + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter, + { + >::swap::(key1, key2) } /// Store a value to be associated with the given keys from the map. - pub fn insert>(key: Key::Key, val: VArg) { + pub fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { >::insert(key, val) } /// Remove the value under the given keys. - pub fn remove(key: Key::Key) { + pub fn remove + TupleToEncodedIter>(key: KArg) { >::remove(key) } @@ -158,31 +163,38 @@ where } /// Mutate the value under the given keys. - pub fn mutate(key: Key::Key, f: F) -> R + pub fn mutate(key: KArg, f: F) -> R where + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> R, { >::mutate(key, f) } /// Mutate the value under the given keys when the closure returns `Ok`. - pub fn try_mutate(key: Key::Key, f: F) -> Result + pub fn try_mutate(key: KArg, f: F) -> Result where + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> Result, { >::try_mutate(key, f) } /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. - pub fn mutate_exists) -> R>(key: Key::Key, f: F) -> R { + pub fn mutate_exists(key: KArg, f: F) -> R + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> R, + { >::mutate_exists(key, f) } /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists) -> Result>( - key: Key::Key, - f: F, - ) -> Result { + pub fn try_mutate_exists(key: KArg, f: F) -> Result + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> Result, + { >::try_mutate_exists(key, f) } @@ -195,8 +207,9 @@ where /// If the storage item is not encoded properly, the storage will be overwritten /// and set to `[item]`. Any default value set for the storage item will be ignored /// on overwrite. - pub fn append(key: Key::Key, item: EncodeLikeItem) + pub fn append(key: KArg, item: EncodeLikeItem) where + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend @@ -216,7 +229,7 @@ where /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - pub fn decode_len(key: Key::Key) -> Option + pub fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where Value: StorageDecodeLength, { @@ -367,116 +380,116 @@ mod test { k.extend(&twox_128(b"test")); k.extend(&twox_128(b"foo")); k.extend(&3u16.blake2_128_concat()); - assert_eq!(A::hashed_key_for(3).to_vec(), k); - - assert_eq!(A::contains_key(3), false); - assert_eq!(A::get(3), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 98); - - A::insert(3, 10); - assert_eq!(A::contains_key(3), true); - assert_eq!(A::get(3), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); - - A::swap::>(3, 2); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(3), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 98); - assert_eq!(A::get(2), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); - - A::remove(2); - assert_eq!(A::contains_key(2), false); - assert_eq!(A::get(2), None); - - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(98 * 4)); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + assert_eq!(A::hashed_key_for((3,)).to_vec(), k); + + assert_eq!(A::contains_key((3,)), false); + assert_eq!(A::get((3,)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3,)), 98); + + A::insert((3,), 10); + assert_eq!(A::contains_key((3,)), true); + assert_eq!(A::get((3,)), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((3,)), 10); + + A::swap::, _, _>((3,), (2,)); + assert_eq!(A::contains_key((3,)), false); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((3,)), None); + assert_eq!(AValueQueryWithAnOnEmpty::get((3,)), 98); + assert_eq!(A::get((2,)), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get((2,)), 10); + + A::remove((2,)); + assert_eq!(A::contains_key((2,)), false); + assert_eq!(A::get((2,)), None); + + AValueQueryWithAnOnEmpty::mutate((2,), |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate((2,), |v| *v = *v * 2); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(98 * 4)); + + A::remove((2,)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { *v = *v * 2; Ok(()) }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { *v = *v * 2; Ok(()) }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(98 * 4)); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(98 * 4)); - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + A::remove((2,)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { *v = *v * 2; Err(()) }); - assert_eq!(A::contains_key(2), false); + assert_eq!(A::contains_key((2,)), false); - A::remove(2); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + A::remove((2,)); + AValueQueryWithAnOnEmpty::mutate_exists((2,), |v| { assert!(v.is_none()); *v = Some(10); }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists((2,), |v| { *v = Some(v.unwrap() * 10); }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(100)); - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + A::remove((2,)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2,), |v| { assert!(v.is_none()); *v = Some(10); Ok(()) }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2,), |v| { *v = Some(v.unwrap() * 10); Ok(()) }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - assert_eq!(A::try_get(2), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(100)); + assert_eq!(A::try_get((2,)), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2,), |v| { *v = Some(v.unwrap() * 10); Err(()) }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(100)); - A::insert(2, 10); - assert_eq!(A::take(2), Some(10)); - assert_eq!(A::contains_key(2), false); - assert_eq!(AValueQueryWithAnOnEmpty::take(2), 98); - assert_eq!(A::contains_key(2), false); - assert_eq!(A::try_get(2), Err(())); + A::insert((2,), 10); + assert_eq!(A::take((2,)), Some(10)); + assert_eq!(A::contains_key((2,)), false); + assert_eq!(AValueQueryWithAnOnEmpty::take((2,)), 98); + assert_eq!(A::contains_key((2,)), false); + assert_eq!(A::try_get((2,)), Err(())); - A::insert(3, 10); - A::insert(4, 10); + A::insert((3,), 10); + A::insert((4,), 10); A::remove_all(); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(4), false); + assert_eq!(A::contains_key((3,)), false); + assert_eq!(A::contains_key((4,)), false); - A::insert(3, 10); - A::insert(4, 10); + A::insert((3,), 10); + A::insert((4,), 10); assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - C::insert(3, 10); - C::insert(4, 10); + C::insert((3,), 10); + C::insert((4,), 10); A::translate_values::(|v| Some((v * 2).into())); assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); - A::insert(3, 10); - A::insert(4, 10); + A::insert((3,), 10); + A::insert((4,), 10); assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); assert_eq!(A::iter().collect::>(), vec![]); - C::insert(3, 10); - C::insert(4, 10); + C::insert((3,), 10); + C::insert((4,), 10); A::translate::(|k1, v| Some((k1 as u16 * v as u16).into())); assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); @@ -487,9 +500,9 @@ mod test { assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); - assert_eq!(WithLen::decode_len(3), None); - WithLen::append(0, 10); - assert_eq!(WithLen::decode_len(0), Some(1)); + assert_eq!(WithLen::decode_len((3,)), None); + WithLen::append((0,), 10); + assert_eq!(WithLen::decode_len((0,)), Some(1)); }); } @@ -519,7 +532,7 @@ mod test { assert_eq!(A::get((3, 30)), Some(10)); assert_eq!(AValueQueryWithAnOnEmpty::get((3, 30)), 10); - A::swap::<(Key, Key)>((3, 30), (2, 20)); + A::swap::<(Key, Key), _, _>((3, 30), (2, 20)); assert_eq!(A::contains_key((3, 30)), false); assert_eq!(A::contains_key((2, 20)), true); assert_eq!(A::get((3, 30)), None); @@ -632,8 +645,8 @@ mod test { A::insert((3, 31), 12); A::insert((4, 40), 13); A::insert((4, 41), 14); - assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); - assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); + assert_eq!(A::iter_prefix_values((3,)).collect::>(), vec![12, 11]); + assert_eq!(A::iter_prefix_values((4,)).collect::>(), vec![13, 14]); }); } @@ -664,7 +677,7 @@ mod test { assert_eq!(A::get((1, 10, 100)), Some(30)); assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 30); - A::swap::<(Key, Key, Key)>( + A::swap::<(Key, Key, Key), _, _>( (1, 10, 100), (2, 20, 200), ); @@ -774,8 +787,8 @@ mod test { A::insert((3, 30, 301), 12); A::insert((4, 40, 400), 13); A::insert((4, 40, 401), 14); - assert_eq!(A::iter_prefix_values(3).collect::>(), vec![11, 12]); - assert_eq!(A::iter_prefix_values(4).collect::>(), vec![14, 13]); + assert_eq!(A::iter_prefix_values((3,)).collect::>(), vec![11, 12]); + assert_eq!(A::iter_prefix_values((4,)).collect::>(), vec![14, 13]); assert_eq!(A::iter_prefix_values((3, 30)).collect::>(), vec![11, 12]); assert_eq!(A::iter_prefix_values((4, 40)).collect::>(), vec![14, 13]); }); From 09b34aba788f18c624bd1f2d8ce75b43284639da Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 22 Apr 2021 22:53:49 -0700 Subject: [PATCH 06/34] Rename KeyGenerator::Arg to KeyGenerator::KArg --- frame/support/src/storage/generator/nmap.rs | 30 ++++++++++----------- frame/support/src/storage/mod.rs | 30 ++++++++++----------- frame/support/src/storage/types/key.rs | 12 ++++----- frame/support/src/storage/types/nmap.rs | 30 ++++++++++----------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index c7fbf381e3733..6922beb61655e 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -97,7 +97,7 @@ pub trait StorageNMap { fn storage_n_map_final_key(key: KArg) -> Vec where KG: KeyGenerator, - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); @@ -123,23 +123,23 @@ where { type Query = G::Query; - fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { Self::storage_n_map_final_key::(key) } - fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { unhashed::exists(&Self::storage_n_map_final_key::(key)) } - fn get + TupleToEncodedIter>(key: KArg) -> Self::Query { + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query { G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::(key))) } - fn try_get + TupleToEncodedIter>(key: KArg) -> Result { + fn try_get + TupleToEncodedIter>(key: KArg) -> Result { unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) } - fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { let final_key = Self::storage_n_map_final_key::(key); let value = unhashed::take(&final_key); @@ -149,8 +149,8 @@ where fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter, + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter, { let final_x_key = Self::storage_n_map_final_key::(key1); let final_y_key = Self::storage_n_map_final_key::(key2); @@ -168,11 +168,11 @@ where } } - fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { + fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); } - fn remove + TupleToEncodedIter>(key: KArg) { + fn remove + TupleToEncodedIter>(key: KArg) { unhashed::kill(&Self::storage_n_map_final_key::(key)); } @@ -193,14 +193,14 @@ where } } - fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>( + fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>( key: KArg, f: F, ) -> R { Self::try_mutate(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( + fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( key: KArg, f: F, ) -> Result { @@ -217,14 +217,14 @@ where ret } - fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>( + fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>( key: KArg, f: F, ) -> R { Self::try_mutate_exists(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") } - fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( + fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( key: KArg, f: F, ) -> Result { @@ -243,7 +243,7 @@ where fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index a8717ca0f6b5a..8ab17a4cd4ec7 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -552,31 +552,31 @@ pub trait StorageNMap { type Query; /// Get the storage key used to fetch a value corresponding to a specific key. - fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec; + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec; /// Does the value (explicitly) exist in storage? - fn contains_key + TupleToEncodedIter>(key: KArg) -> bool; + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool; /// Load the value associated with the given key from the map. - fn get + TupleToEncodedIter>(key: KArg) -> Self::Query; + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - fn try_get + TupleToEncodedIter>(key: KArg) -> Result; + fn try_get + TupleToEncodedIter>(key: KArg) -> Result; /// Swap the values of two keys. fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter; + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter; /// Store a value to be associated with the given key from the map. - fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg); + fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg); /// Remove the value under a key. - fn remove + TupleToEncodedIter>(key: KArg); + fn remove + TupleToEncodedIter>(key: KArg); /// Remove all values under the partial prefix key. fn remove_prefix(partial_key: KP) where K: HasKeyPrefix; @@ -585,10 +585,10 @@ pub trait StorageNMap { fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix; /// Mutate the value under a key. - fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>(key: KArg, f: F) -> R; + fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>(key: KArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. - fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( + fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( key: KArg, f: F, ) -> Result; @@ -596,16 +596,16 @@ pub trait StorageNMap { /// Mutate the value under a key. /// /// Deletes the item if mutated to a `None`. - fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>(key: KArg, f: F) -> R; + fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>(key: KArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( + fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( key: KArg, f: F, ) -> Result; /// Take the value under a key. - fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Append the given items to the value in the storage. /// @@ -618,7 +618,7 @@ pub trait StorageNMap { /// on overwrite. fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend; @@ -635,7 +635,7 @@ pub trait StorageNMap { /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - fn decode_len + TupleToEncodedIter>(key: KArg) -> Option + fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where V: StorageDecodeLength, { diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index fa3dbe0ffbd11..012d5c75888a7 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -38,17 +38,17 @@ pub struct Key( /// A trait that contains the current key as an associated type. pub trait KeyGenerator { type Key: EncodeLike; - type Arg: Encode; + type KArg: Encode; - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; fn final_hash(encoded: &[u8]) -> Vec; } impl KeyGenerator for Key { type Key = K; - type Arg = (K,); + type KArg = (K,); - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { H::hash(&key.to_encoded_iter().next().expect("should have at least one element!")).as_ref().to_vec() } @@ -60,9 +60,9 @@ impl KeyGenerator for Key { #[impl_trait_for_tuples::impl_for_tuples(2, 18)] impl KeyGenerator for Tuple { for_tuples!( type Key = ( #(Tuple::Key),* ); ); - for_tuples!( type Arg = ( #(Tuple::Key),* ); ); + for_tuples!( type KArg = ( #(Tuple::Key),* ); ); - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { let mut final_key = Vec::new(); let mut iter = key.to_encoded_iter(); for_tuples!( diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index ea8d5292ded79..7141899fb5b1c 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -103,29 +103,29 @@ where OnEmpty: crate::traits::Get + 'static, { /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { + pub fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { >::hashed_key_for(key) } /// Does the value (explicitly) exist in storage? - pub fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { + pub fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { >::contains_key(key) } /// Load the value associated with the given key from the map. - pub fn get + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { + pub fn get + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::get(key) } /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get + TupleToEncodedIter>(key: KArg) -> Result { + pub fn try_get + TupleToEncodedIter>(key: KArg) -> Result { >::try_get(key) } /// Take a value from storage, removing it afterwards. - pub fn take + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { + pub fn take + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::take(key) } @@ -133,19 +133,19 @@ where pub fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter, + KArg1: EncodeLike + TupleToEncodedIter, + KArg2: EncodeLike + TupleToEncodedIter, { >::swap::(key1, key2) } /// Store a value to be associated with the given keys from the map. - pub fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { + pub fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { >::insert(key, val) } /// Remove the value under the given keys. - pub fn remove + TupleToEncodedIter>(key: KArg) { + pub fn remove + TupleToEncodedIter>(key: KArg) { >::remove(key) } @@ -165,7 +165,7 @@ where /// Mutate the value under the given keys. pub fn mutate(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> R, { >::mutate(key, f) @@ -174,7 +174,7 @@ where /// Mutate the value under the given keys when the closure returns `Ok`. pub fn try_mutate(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> Result, { >::try_mutate(key, f) @@ -183,7 +183,7 @@ where /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. pub fn mutate_exists(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut Option) -> R, { >::mutate_exists(key, f) @@ -192,7 +192,7 @@ where /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. pub fn try_mutate_exists(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, F: FnOnce(&mut Option) -> Result, { >::try_mutate_exists(key, f) @@ -209,7 +209,7 @@ where /// on overwrite. pub fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend @@ -229,7 +229,7 @@ where /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - pub fn decode_len + TupleToEncodedIter>(key: KArg) -> Option + pub fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where Value: StorageDecodeLength, { From 976e33770dd3ffe2f67a1380ebdacf60ad10fbaa Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 04:02:50 -0700 Subject: [PATCH 07/34] Support StorageNMap in decl_storage and #[pallet::storage] macros --- frame/metadata/src/lib.rs | 5 + .../procedural/src/pallet/expand/storage.rs | 58 +++++++ .../procedural/src/pallet/parse/storage.rs | 95 +++++++++++- .../src/storage/genesis_config/builder_def.rs | 18 +++ .../genesis_config/genesis_config_def.rs | 4 + .../support/procedural/src/storage/getters.rs | 18 +++ .../procedural/src/storage/metadata.rs | 21 +++ frame/support/procedural/src/storage/mod.rs | 51 ++++++ frame/support/procedural/src/storage/parse.rs | 44 +++++- .../src/storage/print_pallet_upgrade.rs | 9 ++ .../procedural/src/storage/storage_struct.rs | 37 +++++ frame/support/src/lib.rs | 4 +- frame/support/src/storage/generator/nmap.rs | 145 ++++++++++++++++++ frame/support/src/storage/types/mod.rs | 1 + 14 files changed, 503 insertions(+), 7 deletions(-) diff --git a/frame/metadata/src/lib.rs b/frame/metadata/src/lib.rs index a63da82ca00db..a502af079862c 100644 --- a/frame/metadata/src/lib.rs +++ b/frame/metadata/src/lib.rs @@ -300,6 +300,11 @@ pub enum StorageEntryType { value: DecodeDifferentStr, key2_hasher: StorageHasher, }, + NMap { + keys: DecodeDifferentArray<&'static str, StringBuf>, + hashers: DecodeDifferentArray, + value: DecodeDifferentStr, + }, } /// A storage entry modifier. diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 86fb84b339b24..386bc59e6a0d2 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -18,6 +18,7 @@ use crate::pallet::Def; use crate::pallet::parse::storage::{Metadata, QueryKind}; use frame_support_procedural_tools::clean_type_string; +use syn::spanned::Spanned; /// Generate the prefix_ident related the the storage. /// prefix_ident is used for the prefix struct to be given to storage as first generic param. @@ -90,6 +91,9 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { Metadata::DoubleMap { .. } => quote::quote_spanned!(storage.attr_span => #frame_support::storage::types::StorageDoubleMapMetadata ), + Metadata::NMap { .. } => quote::quote_spanned!(storage.attr_span => + #frame_support::storage::types::StorageNMapMetadata + ), }; let ty = match &storage.metadata { @@ -126,6 +130,31 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { value: #frame_support::metadata::DecodeDifferent::Encode(#value), } ) + }, + Metadata::NMap { keys, hashers, value, .. } => { + let keys = keys + .iter() + .map(|key| clean_type_string("e::quote!(#key).to_string())) + .collect::>(); + let hashers = hashers + .iter() + .map(|hasher| syn::Ident::new( + &clean_type_string("e::quote!(#hasher).to_string()), + hasher.span(), + )) + .collect::>(); + let value = clean_type_string("e::quote!(#value).to_string()); + quote::quote_spanned!(storage.attr_span => + #frame_support::metadata::StorageEntryType::NMap { + keys: #frame_support::metadata::DecodeDifferent::Encode(&[ + #( #keys, )* + ]), + hashers: #frame_support::metadata::DecodeDifferent::Encode(&[ + #( #frame_support::metadata::StorageHasher::#hashers, )* + ]), + value: #frame_support::metadata::DecodeDifferent::Encode(#value), + } + ) } }; @@ -227,6 +256,35 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { } ) }, + Metadata::NMap { keys, 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::ValueQuery => quote::quote!(#value), + }; + let key_arg = if keys.len() == 1 { + quote::quote!((key,)) + } else { + quote::quote!(key) + }; + quote::quote_spanned!(storage.attr_span => + #(#cfg_attrs)* + impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause { + #( #docs )* + pub fn #getter(key: KArg) -> #query + where + KArg: #frame_support::codec::EncodeLike<<#keygen as KeyGenerator>::KArg> + + #frame_support::storage::types::TupleToEncodedIter, + { + < + #full_ident as + #frame_support::storage::StorageNMap<#keygen, #value> + >::get(#key_arg) + } + } + ) + } } } else { Default::default() diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 41ef337b76615..e84656cd1658f 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -50,7 +50,7 @@ impl syn::parse::Parse for PalletStorageAttr { } /// The value and key types used by storages. Needed to expand metadata. -pub enum Metadata{ +pub enum Metadata { Value { value: syn::GenericArgument }, Map { value: syn::GenericArgument, key: syn::GenericArgument }, DoubleMap { @@ -58,6 +58,12 @@ pub enum Metadata{ key1: syn::GenericArgument, key2: syn::GenericArgument }, + NMap { + keys: Vec, + hashers: Vec, + keygen: syn::GenericArgument, + value: syn::GenericArgument, + }, } pub enum QueryKind { @@ -115,6 +121,78 @@ fn retrieve_arg( } } +/// Parse the 2nd type argument to `StorageNMap` and return its keys and hashers. +fn collect_keys_and_hashers(keygen: &syn::GenericArgument) -> syn::Result<(Vec, Vec)> { + if let syn::GenericArgument::Type(syn::Type::Tuple(tup)) = keygen { + tup + .elems + .iter() + .try_fold((vec![], vec![]), |mut acc, ty| { + let (key, hasher) = extract_key_and_hasher(ty)?; + + acc.0.push(key); + acc.1.push(hasher); + Ok(acc) + }) + } else if let syn::GenericArgument::Type(ty) = keygen { + let (key, hasher) = extract_key_and_hasher(ty)?; + + Ok((vec![key], vec![hasher])) + } else { + let msg = format!("Invalid pallet::storage, expected tuple of Key structs or Key struct"); + Err(syn::Error::new(keygen.span(), msg)) + } +} + +/// In `Key`, extract H and K and return (K, H). +fn extract_key_and_hasher(ty: &syn::Type) -> syn::Result<(syn::Type, syn::Type)> { + let typ = if let syn::Type::Path(typ) = ty { + typ + } else { + let msg = format!("Invalid pallet::storage, expected type path"); + return Err(syn::Error::new(ty.span(), msg)); + }; + + let key_struct = typ.path.segments.last().ok_or_else(|| { + let msg = format!("Invalid pallet::storage, expected type path with at least one segment"); + syn::Error::new(typ.path.span(), msg) + })?; + if key_struct.ident != "Key" { + let msg = format!("Invalid pallet::storage, expected Key struct"); + return Err(syn::Error::new(key_struct.ident.span(), msg)); + } + + let ty_params = if let syn::PathArguments::AngleBracketed(args) = &key_struct.arguments { + args + } else { + let msg = format!("Invalid pallet::storage, expected angle bracketed arguments"); + return Err(syn::Error::new(key_struct.arguments.span(), msg)); + }; + + if ty_params.args.len() != 2 { + let msg = format!("Invalid pallet::storage, unexpected number of generic arguments \ + for Key struct, expected 2 args, found {}", ty_params.args.len()); + return Err(syn::Error::new(ty_params.span(), msg)); + } + + let hasher = match &ty_params.args[0] { + syn::GenericArgument::Type(hasher_ty) => hasher_ty.clone(), + _ => { + let msg = format!("Invalid pallet::storage, expected type"); + return Err(syn::Error::new(ty_params.args[0].span(), msg)); + } + }; + let key = match &ty_params.args[1] { + syn::GenericArgument::Type(key_ty) => key_ty.clone(), + _ => { + let msg = format!("Invalid pallet::storage, expected type"); + return Err(syn::Error::new(ty_params.args[1].span(), msg)); + } + }; + + Ok((key, hasher)) +} + impl StorageDef { pub fn try_from( attr_span: proc_macro2::Span, @@ -177,11 +255,22 @@ impl StorageDef { value: retrieve_arg(&typ.path.segments[0], 5)?, } } + "StorageNMap" => { + query_kind = retrieve_arg(&typ.path.segments[0], 3); + let keygen = retrieve_arg(&typ.path.segments[0], 1)?; + let (keys, hashers) = collect_keys_and_hashers(&keygen)?; + Metadata::NMap { + keys, + hashers, + keygen, + value: retrieve_arg(&typ.path.segments[0], 2)?, + } + } found => { let msg = format!( "Invalid pallet::storage, expected ident: `StorageValue` or \ - `StorageMap` or `StorageDoubleMap` in order to expand metadata, found \ - `{}`", + `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order \ + to expand metadata, found `{}`", found, ); return Err(syn::Error::new(item.ty.span(), msg)); diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index 0cbfa04787f78..8fb15bf04d343 100644 --- a/frame/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/builder_def.rs @@ -120,6 +120,24 @@ impl BuilderDef { }); }} }, + StorageLineTypeDef::NMap(map) => { + let keygen = map.to_keygen_struct(); + let key_tuple = map.to_key_tuple(); + let key_arg = if map.keys.len() == 1 { + quote!((k,)) + } else { + quote!(k) + }; + quote!{{ + #data + let data: &#scrate::sp_std::vec::Vec<(#key_tuple, #value_type)> = data; + data.iter().for_each(|(k, v)| { + <#storage_struct as #scrate::#storage_trait>::insert::< + &#keygen, &#value_type + >(#key_arg, v); + }); + }} + }, }); } } diff --git a/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs b/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs index 300e47bc850ee..c54349136cf05 100644 --- a/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/genesis_config_def.rs @@ -104,6 +104,10 @@ impl GenesisConfigDef { parse_quote!( Vec<(#key1, #key2, #value_type)> ) }, + StorageLineTypeDef::NMap(map) => { + let key_tuple = map.to_key_tuple(); + parse_quote!( Vec<(#key_tuple, #value_type)> ) + } }; let default = line.default_value.as_ref() diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 65a3519033aa2..0c51ab4c71ed7 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -65,6 +65,24 @@ pub fn impl_getters(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStrea } } }, + StorageLineTypeDef::NMap(map) => { + let keygen = map.to_keygen_struct(); + let value = &map.value; + let key_arg = if map.keys.len() == 1 { + quote!((key,)) + } else { + quote!(key) + }; + quote!{ + pub fn #get_fn(key: KArg) -> #value + where + KArg: #scrate::codec::EncodeLike<<#keygen as KeyGenerator>::KArg> + + #scrate::storage::types::TupleToEncodedIter, + { + <#storage_struct as #scrate::#storage_trait>::get(#key_arg) + } + } + } }; getters.extend(getter); } diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index c321386ae1dc4..ac38892bedb18 100644 --- a/frame/support/procedural/src/storage/metadata.rs +++ b/frame/support/procedural/src/storage/metadata.rs @@ -63,6 +63,27 @@ fn storage_line_metadata_type(scrate: &TokenStream, line: &StorageLineDefExt) -> } } }, + StorageLineTypeDef::NMap(map) => { + let keys = map.keys + .iter() + .map(|key| clean_type_string("e!(#key).to_string())) + .collect::>(); + let hashers = map.hashers + .iter() + .map(|hasher| hasher.to_storage_hasher_struct()) + .collect::>(); + quote!{ + #scrate::metadata::StorageEntryType::NMap { + keys: #scrate::metadata::DecodeDifferent::Encode(&[ + #( #keys, )* + ]), + hashers: #scrate::metadata::DecodeDifferent::Encode(&[ + #( #scrate::metadata::StorageHasher::#hashers, )* + ]), + value: #scrate::metadata::DecodeDifferent::Encode(#value_type), + } + } + } } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 2f9625d2c941e..d780366a156a8 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -244,12 +244,17 @@ impl StorageLineDefExt { || ext::type_contains_ident(&map.key2, &def.module_runtime_generic) || ext::type_contains_ident(&map.value, &def.module_runtime_generic) } + StorageLineTypeDef::NMap(map) => { + map.keys.iter().any(|key| ext::type_contains_ident(key, &def.module_runtime_generic)) + || ext::type_contains_ident(&map.value, &def.module_runtime_generic) + } }; let query_type = match &storage_def.storage_type { StorageLineTypeDef::Simple(value) => value.clone(), StorageLineTypeDef::Map(map) => map.value.clone(), StorageLineTypeDef::DoubleMap(map) => map.value.clone(), + StorageLineTypeDef::NMap(map) => map.value.clone(), }; let is_option = ext::extract_type_option(&query_type).is_some(); let value_type = ext::extract_type_option(&query_type).unwrap_or_else(|| query_type.clone()); @@ -295,6 +300,10 @@ impl StorageLineDefExt { let key2 = &map.key2; quote!( StorageDoubleMap<#key1, #key2, #value_type> ) }, + StorageLineTypeDef::NMap(map) => { + let keygen = map.to_keygen_struct(); + quote!( StorageNMap<#keygen, #value_type> ) + } }; let storage_trait = quote!( storage::#storage_trait_truncated ); @@ -332,6 +341,7 @@ impl StorageLineDefExt { pub enum StorageLineTypeDef { Map(MapDef), DoubleMap(Box), + NMap(NMapDef), Simple(syn::Type), } @@ -351,6 +361,36 @@ pub struct DoubleMapDef { pub value: syn::Type, } +pub struct NMapDef { + pub hashers: Vec, + pub keys: Vec, + pub value: syn::Type, +} + +impl NMapDef { + fn to_keygen_struct(&self) -> proc_macro2::TokenStream { + let key_hasher = self.keys.iter().zip(&self.hashers).map(|(key, hasher)| { + let hasher = hasher.to_storage_hasher_struct(); + quote!( Key<#hasher, #key> ) + }) + .collect::>(); + quote!(( #(#key_hasher,)* )) + } + + fn to_key_tuple(&self) -> proc_macro2::TokenStream { + if self.keys.len() == 1 { + let key = &self.keys[0]; + return quote!(#key); + } + + let tuple = self.keys.iter().map(|key| { + quote!(#key) + }) + .collect::>(); + quote!(( #(#tuple,)* )) + } +} + pub struct ExtraGenesisLineDef { attrs: Vec, name: syn::Ident, @@ -420,9 +460,20 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr StorageValue as _, StorageMap as _, StorageDoubleMap as _, + StorageNMap as _, StoragePrefixedMap as _, IterableStorageMap as _, + IterableStorageNMap as _, IterableStorageDoubleMap as _, + + storage::types::Key, + Blake2_256, + Blake2_128, + Blake2_128Concat, + Twox256, + Twox128, + Twox64Concat, + Identity, }; #scrate_decl diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 2ff7f1fbf38c9..1c3c9c0ebf6d7 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -18,7 +18,7 @@ //! Parsing of decl_storage input. use frame_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; -use syn::{Ident, Token, spanned::Spanned}; +use syn::{Ident, Token, punctuated::Punctuated, spanned::Spanned}; mod keyword { syn::custom_keyword!(hiddencrate); @@ -29,6 +29,7 @@ mod keyword { syn::custom_keyword!(get); syn::custom_keyword!(map); syn::custom_keyword!(double_map); + syn::custom_keyword!(nmap); syn::custom_keyword!(opaque_blake2_256); syn::custom_keyword!(opaque_blake2_128); syn::custom_keyword!(blake2_128_concat); @@ -199,6 +200,7 @@ impl_parse_for_opt!(DeclStorageBuild => keyword::build); enum DeclStorageType { Map(DeclStorageMap), DoubleMap(Box), + NMap(DeclStorageNMap), Simple(syn::Type), } @@ -208,6 +210,8 @@ impl syn::parse::Parse for DeclStorageType { Ok(Self::Map(input.parse()?)) } else if input.peek(keyword::double_map) { Ok(Self::DoubleMap(input.parse()?)) + } else if input.peek(keyword::nmap) { + Ok(Self::NMap(input.parse()?)) } else { Ok(Self::Simple(input.parse()?)) } @@ -235,7 +239,32 @@ struct DeclStorageDoubleMap { pub value: syn::Type, } +#[derive(Parse, ToTokens, Debug)] +struct DeclStorageKey { + pub hasher: Opt, + pub key: syn::Type, +} + #[derive(ToTokens, Debug)] +struct DeclStorageNMap { + pub map_keyword: keyword::nmap, + pub storage_keys: Punctuated, + pub ass_keyword: Token![=>], + pub value: syn::Type, +} + +impl syn::parse::Parse for DeclStorageNMap { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(DeclStorageNMap { + map_keyword: input.parse()?, + storage_keys: >::parse_separated_nonempty(input)?, + ass_keyword: input.parse()?, + value: input.parse()?, + }) + } +} + +#[derive(Clone, ToTokens, Debug)] enum Hasher { Blake2_256(keyword::opaque_blake2_256), Blake2_128(keyword::opaque_blake2_128), @@ -291,7 +320,7 @@ impl syn::parse::Parse for Opt { } } -#[derive(Parse, ToTokens, Debug)] +#[derive(Clone, Parse, ToTokens, Debug)] struct SetHasher { pub hasher_keyword: keyword::hasher, pub inner: ext::Parens, @@ -495,6 +524,17 @@ fn parse_storage_line_defs( value: map.value, }) ), + DeclStorageType::NMap(map) => super::StorageLineTypeDef::NMap( + super::NMapDef { + hashers: map + .storage_keys + .iter() + .map(|pair| Ok(pair.hasher.inner.clone().ok_or_else(no_hasher_error)?.into())) + .collect::, syn::Error>>()?, + keys: map.storage_keys.iter().map(|pair| pair.key.clone()).collect(), + value: map.value, + } + ), DeclStorageType::Simple(expr) => super::StorageLineTypeDef::Simple(expr), }; diff --git a/frame/support/procedural/src/storage/print_pallet_upgrade.rs b/frame/support/procedural/src/storage/print_pallet_upgrade.rs index 447d13898e8df..ddfdca1b31339 100644 --- a/frame/support/procedural/src/storage/print_pallet_upgrade.rs +++ b/frame/support/procedural/src/storage/print_pallet_upgrade.rs @@ -239,6 +239,15 @@ pub fn maybe_print_pallet_upgrade(def: &super::DeclStorageDefExt) { comma_default_value_getter_name = comma_default_value_getter_name, ) }, + StorageLineTypeDef::NMap(map) => { + format!("StorageNMap<_, {keygen}, {value_type}{comma_query_kind}\ + {comma_default_value_getter_name}>", + keygen = map.to_keygen_struct(), + value_type = to_cleaned_string(&value_type), + comma_query_kind = comma_query_kind, + comma_default_value_getter_name = comma_default_value_getter_name, + ) + } StorageLineTypeDef::Simple(_) => { format!("StorageValue<_, {value_type}{comma_query_kind}\ {comma_default_value_getter_name}>", diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index 9c049789f9bd9..dfcc4eb2d5490 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -199,6 +199,43 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre #from_optional_value_to_query } + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { + #from_query_to_optional_value + } + } + ) + }, + StorageLineTypeDef::NMap(_) => { + quote!( + impl<#impl_trait> #scrate::storage::StoragePrefixedMap<#value_type> + for #storage_struct #optional_storage_where_clause + { + fn module_prefix() -> &'static [u8] { + <#instance_or_inherent as #scrate::traits::Instance>::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_bstr + } + } + + impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct + #optional_storage_where_clause + { + type Query = #query_type; + + fn module_prefix() -> &'static [u8] { + <#instance_or_inherent as #scrate::traits::Instance>::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_bstr + } + + fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { + #from_optional_value_to_query + } + fn from_query_to_optional_value(v: Self::Query) -> Option<#value_type> { #from_query_to_optional_value } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 6740e0db5a0ef..1f6caede82f37 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -74,8 +74,8 @@ pub use self::hash::{ StorageHasher, ReversibleStorageHasher }; pub use self::storage::{ - StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap, IterableStorageMap, - IterableStorageDoubleMap, migration, + StorageValue, StorageMap, StorageDoubleMap, StorageNMap, StoragePrefixedMap, IterableStorageMap, + IterableStorageDoubleMap, IterableStorageNMap, migration, bounded_vec::{self, BoundedVec}, }; pub use self::dispatch::{Parameter, Callable}; diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 6922beb61655e..676a5a97477a3 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -330,3 +330,148 @@ impl> storage::Ite } } } + +/// Test iterators for StorageNMap +#[cfg(test)] +mod test_iterators { + use codec::{Encode, Decode}; + use crate::{ + hash::StorageHasher, + storage::{generator::StorageNMap, IterableStorageNMap, unhashed}, + }; + + pub trait Config: 'static { + type Origin; + type BlockNumber; + type PalletInfo: crate::traits::PalletInfo; + type DbWeight: crate::traits::Get; + } + + crate::decl_module! { + pub struct Module for enum Call where origin: T::Origin, system=self {} + } + + #[derive(PartialEq, Eq, Clone, Encode, Decode)] + struct NoDef(u32); + + crate::decl_storage! { + trait Store for Module as Test { + NMap: nmap hasher(blake2_128_concat) u16, hasher(twox_64_concat) u32 => u64; + } + } + + fn key_before_prefix(mut prefix: Vec) -> Vec { + let last = prefix.iter_mut().last().unwrap(); + assert!(*last != 0, "mock function not implemented for this prefix"); + *last -= 1; + prefix + } + + fn key_after_prefix(mut prefix: Vec) -> Vec { + let last = prefix.iter_mut().last().unwrap(); + assert!(*last != 255, "mock function not implemented for this prefix"); + *last += 1; + prefix + } + + #[test] + fn n_map_reversible_reversible_iteration() { + sp_io::TestExternalities::default().execute_with(|| { + // All map iterator + let prefix = NMap::prefix_hash(); + + unhashed::put(&key_before_prefix(prefix.clone()), &1u64); + unhashed::put(&key_after_prefix(prefix.clone()), &1u64); + + for i in 0..4 { + NMap::insert((i as u16, i as u32), i as u64); + } + + assert_eq!( + NMap::iter().collect::>(), + vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)], + ); + + assert_eq!( + NMap::iter_values().collect::>(), + vec![3, 0, 2, 1], + ); + + assert_eq!( + NMap::drain().collect::>(), + vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)], + ); + + assert_eq!(NMap::iter().collect::>(), vec![]); + assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64)); + assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); + + // Prefix iterator + let k1 = 3 << 8; + let prefix = NMap::storage_n_map_partial_key((k1,)); + + unhashed::put(&key_before_prefix(prefix.clone()), &1u64); + unhashed::put(&key_after_prefix(prefix.clone()), &1u64); + + for i in 0..4 { + NMap::insert((k1, i as u32), i as u64); + } + + assert_eq!( + NMap::iter_prefix((k1,)).collect::>(), + vec![(1, 1), (2, 2), (0, 0), (3, 3)], + ); + + assert_eq!( + NMap::iter_prefix_values((k1,)).collect::>(), + vec![1, 2, 0, 3], + ); + + assert_eq!( + NMap::drain_prefix((k1,)).collect::>(), + vec![(1, 1), (2, 2), (0, 0), (3, 3)], + ); + + assert_eq!(NMap::iter_prefix((k1,)).collect::>(), vec![]); + assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64)); + assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); + + // Translate + let prefix = NMap::prefix_hash(); + + unhashed::put(&key_before_prefix(prefix.clone()), &1u64); + unhashed::put(&key_after_prefix(prefix.clone()), &1u64); + for i in 0..4 { + NMap::insert((i as u16, i as u32), i as u64); + } + + // Wrong key1 + unhashed::put( + &[prefix.clone(), vec![1, 2, 3]].concat(), + &3u64.encode() + ); + + // Wrong key2 + unhashed::put( + &[prefix.clone(), crate::Blake2_128Concat::hash(&1u16.encode())].concat(), + &3u64.encode() + ); + + // Wrong value + unhashed::put( + &[ + prefix.clone(), + crate::Blake2_128Concat::hash(&1u16.encode()), + crate::Twox64Concat::hash(&2u32.encode()), + ].concat(), + &vec![1], + ); + + NMap::translate(|(_k1, _k2), v: u64| Some(v*2)); + assert_eq!( + NMap::iter().collect::>(), + vec![((3, 3), 6), ((0, 0), 0), ((2, 2), 4), ((1, 1), 2)], + ); + }) + } +} diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 07b8700616bd3..11e49be6c636f 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -30,6 +30,7 @@ mod double_map; pub use key::{HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator, TupleToEncodedIter}; pub use value::{StorageValue, StorageValueMetadata}; pub use map::{StorageMap, StorageMapMetadata}; +pub use nmap::{StorageNMap, StorageNMapMetadata}; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; /// Trait implementing how the storage optional value is converted into the queried type. From 09be192e68a55ba7582d3d6edbf482dd0738e8d0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 04:57:20 -0700 Subject: [PATCH 08/34] Use StorageNMap in assets pallet --- frame/assets/src/lib.rs | 42 +++++++++++++++----------------- frame/assets/src/types.rs | 9 ------- frame/support/src/lib.rs | 2 +- frame/support/src/storage/mod.rs | 1 + 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index e8dfd50f4086a..0c14e917b4307 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -158,6 +158,7 @@ pub use pallet::*; pub mod pallet { use frame_support::{ dispatch::DispatchResult, + storage, pallet_prelude::*, }; use frame_system::pallet_prelude::*; @@ -237,12 +238,13 @@ pub mod pallet { #[pallet::storage] /// Approved balance transfers. First balance is the amount approved for transfer. Second /// is the amount of `T::Currency` reserved for storing this. - pub(super) type Approvals, I: 'static = ()> = StorageDoubleMap< + pub(super) type Approvals, I: 'static = ()> = StorageNMap< _, - Blake2_128Concat, - T::AssetId, - Blake2_128Concat, - ApprovalKey, + ( + storage::Key, + storage::Key, + storage::Key, + ), Approval>, OptionQuery, >; @@ -504,7 +506,7 @@ pub mod pallet { details.deposit.saturating_add(metadata.deposit), ); - Approvals::::remove_prefix(&id); + Approvals::::remove_prefix((id,)); Self::deposit_event(Event::Destroyed(id)); // NOTE: could use postinfo to reflect the actual number of accounts/sufficient/approvals @@ -1120,19 +1122,18 @@ pub mod pallet { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - let key = ApprovalKey { owner, delegate }; - Approvals::::try_mutate(id, &key, |maybe_approved| -> DispatchResult { + Approvals::::try_mutate((id, &owner, &delegate), |maybe_approved| -> DispatchResult { let mut approved = maybe_approved.take().unwrap_or_default(); let deposit_required = T::ApprovalDeposit::get(); if approved.deposit < deposit_required { - T::Currency::reserve(&key.owner, deposit_required - approved.deposit)?; + T::Currency::reserve(&owner, deposit_required - approved.deposit)?; approved.deposit = deposit_required; } approved.amount = approved.amount.saturating_add(amount); *maybe_approved = Some(approved); Ok(()) })?; - Self::deposit_event(Event::ApprovedTransfer(id, key.owner, key.delegate, amount)); + Self::deposit_event(Event::ApprovedTransfer(id, owner, delegate, amount)); Ok(()) } @@ -1158,11 +1159,10 @@ pub mod pallet { ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - let key = ApprovalKey { owner, delegate }; - let approval = Approvals::::take(id, &key).ok_or(Error::::Unknown)?; - T::Currency::unreserve(&key.owner, approval.deposit); + let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; + T::Currency::unreserve(&owner, approval.deposit); - Self::deposit_event(Event::ApprovalCancelled(id, key.owner, key.delegate)); + Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); Ok(()) } @@ -1198,11 +1198,10 @@ pub mod pallet { let owner = T::Lookup::lookup(owner)?; let delegate = T::Lookup::lookup(delegate)?; - let key = ApprovalKey { owner, delegate }; - let approval = Approvals::::take(id, &key).ok_or(Error::::Unknown)?; - T::Currency::unreserve(&key.owner, approval.deposit); + let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; + T::Currency::unreserve(&owner, approval.deposit); - Self::deposit_event(Event::ApprovalCancelled(id, key.owner, key.delegate)); + Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); Ok(()) } @@ -1236,8 +1235,7 @@ pub mod pallet { let owner = T::Lookup::lookup(owner)?; let destination = T::Lookup::lookup(destination)?; - let key = ApprovalKey { owner, delegate }; - Approvals::::try_mutate_exists(id, &key, |maybe_approved| -> DispatchResult { + Approvals::::try_mutate_exists((id, &owner, delegate), |maybe_approved| -> DispatchResult { let mut approved = maybe_approved.take().ok_or(Error::::Unapproved)?; let remaining = approved .amount @@ -1249,10 +1247,10 @@ pub mod pallet { best_effort: false, burn_dust: false }; - Self::do_transfer(id, &key.owner, &destination, amount, None, f)?; + Self::do_transfer(id, &owner, &destination, amount, None, f)?; if remaining.is_zero() { - T::Currency::unreserve(&key.owner, approved.deposit); + T::Currency::unreserve(&owner, approved.deposit); } else { approved.amount = remaining; *maybe_approved = Some(approved); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index f3f17c00a218f..0cfcb64e137f2 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -65,15 +65,6 @@ impl AssetDetails { - /// The owner of the funds that are being approved. - pub(super) owner: AccountId, - /// The party to whom transfer of the funds is being delegated. - pub(super) delegate: AccountId, -} - /// Data concerning an approval. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] pub struct Approval { diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 1f6caede82f37..f4665cec5e298 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1237,7 +1237,7 @@ pub mod pallet_prelude { traits::{Get, Hooks, IsType, GetPalletVersion, EnsureOrigin}, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, weights::{DispatchClass, Pays, Weight}, - storage::types::{StorageValue, StorageMap, StorageDoubleMap, ValueQuery, OptionQuery}, + storage::types::{StorageValue, StorageMap, StorageDoubleMap, StorageNMap, ValueQuery, OptionQuery}, }; pub use codec::{Encode, Decode}; pub use sp_inherents::{InherentData, InherentIdentifier, ProvideInherent}; diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 8ab17a4cd4ec7..70fa5c9441f42 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -27,6 +27,7 @@ use crate::{ }; use sp_runtime::generic::{Digest, DigestItem}; pub use sp_runtime::TransactionOutcome; +pub use types::Key; pub mod unhashed; pub mod hashed; From 54b38e74667328659c8a09ace1f67850c0f7a4c1 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 06:22:07 -0700 Subject: [PATCH 09/34] Support migrate_keys in StorageNMap --- frame/support/src/storage/generator/nmap.rs | 24 +++++++++++ frame/support/src/storage/mod.rs | 5 +++ frame/support/src/storage/types/key.rs | 37 +++++++++++++--- frame/support/src/storage/types/nmap.rs | 48 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 7 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 676a5a97477a3..4bd2e069e611f 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -251,6 +251,30 @@ where let final_key = Self::storage_n_map_final_key::(key); sp_io::storage::append(&final_key, item.encode()); } + + fn migrate_keys + TupleToEncodedIter>(key: KArg, hash_fns: K::HArg) -> Option { + let old_key = { + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = K::migrate_key(&key, hash_fns); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + + storage_prefix_hashed.len() + + key_hashed.len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key + }; + unhashed::take(old_key.as_ref()).map(|value| { + unhashed::put(Self::storage_n_map_final_key::(key).as_ref(), &value); + value + }) + } } impl> storage::IterableStorageNMap for G { diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 70fa5c9441f42..a6a46e8127043 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -642,6 +642,11 @@ pub trait StorageNMap { { V::decode_len(&Self::hashed_key_for(key)) } + + /// Migrate an item with the given `key` from defunct `hash_fns` to the current hashers. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + fn migrate_keys + TupleToEncodedIter>(key: KArg, hash_fns: K::HArg) -> Option; } /// Iterate over a prefix and decode raw_key and raw_value into `T`. diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 012d5c75888a7..28df03dd7e2b7 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -39,19 +39,28 @@ pub struct Key( pub trait KeyGenerator { type Key: EncodeLike; type KArg: Encode; + type HashFn: FnOnce(&[u8]) -> Vec; + type HArg; fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec; fn final_hash(encoded: &[u8]) -> Vec; } impl KeyGenerator for Key { type Key = K; type KArg = (K,); + type HashFn = Box Vec>; + type HArg = (Self::HashFn,); fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { H::hash(&key.to_encoded_iter().next().expect("should have at least one element!")).as_ref().to_vec() } + fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec { + (hash_fns.0)(&key.to_encoded_iter().next().expect("should have at least one element!")) + } + fn final_hash(encoded: &[u8]) -> Vec { H::hash(encoded).as_ref().to_vec() } @@ -61,6 +70,8 @@ impl KeyGenerator for Key { impl KeyGenerator for Tuple { for_tuples!( type Key = ( #(Tuple::Key),* ); ); for_tuples!( type KArg = ( #(Tuple::Key),* ); ); + for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); + type HashFn = Box Vec>; fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { let mut final_key = Vec::new(); @@ -74,18 +85,30 @@ impl KeyGenerator for Tuple { final_key } + fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec { + let mut migrated_key = Vec::new(); + let mut iter = key.to_encoded_iter(); + for_tuples!( + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded)); + )* + ); + migrated_key + } + fn final_hash(encoded: &[u8]) -> Vec { panic!("final_hash called on KeyGenerator tuple") } } pub trait TupleToEncodedIter { - fn to_encoded_iter(self) -> Box>>; + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; } impl TupleToEncodedIter for (A,) { - fn to_encoded_iter(self) -> Box>> { - Box::new(sp_std::iter::once(self.0.encode())) + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + vec![self.0.encode()].into_iter() } } @@ -93,10 +116,10 @@ impl TupleToEncodedIter for (A,) { #[tuple_types_no_default_trait_bound] impl TupleToEncodedIter for Tuple { for_tuples!( where #(Tuple: Encode),* ); - fn to_encoded_iter(self) -> Box>> { - let mut iter: Box>> = Box::new(sp_std::iter::empty::>()); - for_tuples!( #(iter = Box::new(iter.chain((self.Tuple,).to_encoded_iter()));)* ); - iter + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + [ for_tuples!( #(self.Tuple.encode()),* ) ] + .to_vec() + .into_iter() } } diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 7141899fb5b1c..73c41fc6ae2bd 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -236,6 +236,18 @@ where >::decode_len(key) } + /// Migrate an item with the given `key` from defunct `hash_fns` to the current hashers. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_keys + TupleToEncodedIter>( + key: KArg, + hash_fns: Key::HArg, + ) -> Option { + < + Self as crate::storage::StorageNMap + >::migrate_keys::<_>(key, hash_fns) + } + /// Remove all value of the storage. pub fn remove_all() { >::remove_all() @@ -372,6 +384,7 @@ mod test { type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, Key, u32, ValueQuery, ADefault >; + type B = StorageNMap, u32, ValueQuery>; type C = StorageNMap, u8, ValueQuery>; type WithLen = StorageNMap, Vec>; @@ -467,6 +480,16 @@ mod test { assert_eq!(A::contains_key((2,)), false); assert_eq!(A::try_get((2,)), Err(())); + B::insert((2,), 10); + assert_eq!(A::migrate_keys( + (2,), + ( + Box::new(|key| Blake2_256::hash(key).to_vec()), + ), + ), Some(10)); + assert_eq!(A::contains_key((2,)), true); + assert_eq!(A::get((2,)), Some(10)); + A::insert((3,), 10); A::insert((4,), 10); A::remove_all(); @@ -512,6 +535,7 @@ mod test { type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, (Key, Key), u32, ValueQuery, ADefault >; + type B = StorageNMap, Key), u32, ValueQuery>; type C = StorageNMap, Key), u8, ValueQuery>; type WithLen = StorageNMap, Key), Vec>; @@ -604,6 +628,17 @@ mod test { assert_eq!(A::contains_key((2, 20)), false); assert_eq!(A::try_get((2, 20)), Err(())); + B::insert((2, 20), 10); + assert_eq!(A::migrate_keys( + (2, 20), + ( + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Twox128::hash(key).to_vec()), + ), + ), Some(10)); + assert_eq!(A::contains_key((2, 20)), true); + assert_eq!(A::get((2, 20)), Some(10)); + A::insert((3, 30), 10); A::insert((4, 40), 10); A::remove_all(); @@ -656,6 +691,7 @@ mod test { type AValueQueryWithAnOnEmpty = StorageNMap< Prefix, (Key, Key, Key), u32, ValueQuery, ADefault >; + type B = StorageNMap, Key, Key), u32, ValueQuery>; type C = StorageNMap, Key, Key), u8, ValueQuery>; type WithLen = StorageNMap, Key, Key), Vec>; @@ -746,6 +782,18 @@ mod test { assert_eq!(A::contains_key((2, 20, 200)), false); assert_eq!(A::try_get((2, 20, 200)), Err(())); + B::insert((2, 20, 200), 10); + assert_eq!(A::migrate_keys( + (2, 20, 200), + ( + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Twox128::hash(key).to_vec()), + ), + ), Some(10)); + assert_eq!(A::contains_key((2, 20, 200)), true); + assert_eq!(A::get((2, 20, 200)), Some(10)); + A::insert((3, 30, 300), 10); A::insert((4, 40, 400), 10); A::remove_all(); From a3b48a770b087cb647779ccc77b7c9d202da2944 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 15:44:30 -0700 Subject: [PATCH 10/34] Reduce line characters on select files --- .../procedural/src/pallet/parse/storage.rs | 4 +- frame/support/src/lib.rs | 4 +- frame/support/src/storage/generator/nmap.rs | 151 +- frame/support/src/storage/mod.rs | 26 +- frame/support/src/storage/types/double_map.rs | 1216 +++++++++-------- frame/support/src/storage/types/key.rs | 929 ++++++++++--- frame/support/src/storage/types/map.rs | 892 ++++++------ frame/support/src/storage/types/mod.rs | 17 +- frame/support/src/storage/types/nmap.rs | 356 +++-- frame/support/src/storage/types/value.rs | 525 +++---- 10 files changed, 2454 insertions(+), 1666 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index e84656cd1658f..36a92fd4670b8 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -122,7 +122,9 @@ fn retrieve_arg( } /// Parse the 2nd type argument to `StorageNMap` and return its keys and hashers. -fn collect_keys_and_hashers(keygen: &syn::GenericArgument) -> syn::Result<(Vec, Vec)> { +fn collect_keys_and_hashers( + keygen: &syn::GenericArgument, +) -> syn::Result<(Vec, Vec)> { if let syn::GenericArgument::Type(syn::Type::Tuple(tup)) = keygen { tup .elems diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index f4665cec5e298..8020f47039910 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -74,8 +74,8 @@ pub use self::hash::{ StorageHasher, ReversibleStorageHasher }; pub use self::storage::{ - StorageValue, StorageMap, StorageDoubleMap, StorageNMap, StoragePrefixedMap, IterableStorageMap, - IterableStorageDoubleMap, IterableStorageNMap, migration, + StorageValue, StorageMap, StorageDoubleMap, StorageNMap, StoragePrefixedMap, + IterableStorageMap, IterableStorageDoubleMap, IterableStorageNMap, migration, bounded_vec::{self, BoundedVec}, }; pub use self::dispatch::{Parameter, Callable}; diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 4bd2e069e611f..03d4849656aea 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -15,18 +15,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#[cfg(not(feature = "std"))] -use sp_std::prelude::*; -use sp_std::borrow::Borrow; -use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ + hash::{StorageHasher, Twox128}, storage::{ - self, unhashed, + self, types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, - PrefixIterator, StorageAppend, TupleToEncodedIter, + unhashed, PrefixIterator, StorageAppend, TupleToEncodedIter, }, - Never, hash::{StorageHasher, Twox128}, + Never, }; +use codec::{Decode, Encode, EncodeLike, FullCodec}; +use sp_std::borrow::Borrow; +#[cfg(not(feature = "std"))] +use sp_std::prelude::*; /// Generator for `StorageNMap` used by `decl_storage`. /// @@ -57,9 +58,8 @@ pub trait StorageNMap { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); - let mut result = Vec::with_capacity( - module_prefix_hashed.len() + storage_prefix_hashed.len() - ); + let mut result = + Vec::with_capacity(module_prefix_hashed.len() + storage_prefix_hashed.len()); result.extend_from_slice(&module_prefix_hashed[..]); result.extend_from_slice(&storage_prefix_hashed[..]); @@ -72,7 +72,7 @@ pub trait StorageNMap { /// Convert a query to an optional value into storage. fn from_query_to_optional_value(v: Self::Query) -> Option; - + /// Generate a partial key used in top storage. fn storage_n_map_partial_key(key: KP) -> Vec where @@ -83,7 +83,7 @@ pub trait StorageNMap { let key_hashed = >::partial_key(key); let mut final_key = Vec::with_capacity( - module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(), ); final_key.extend_from_slice(&module_prefix_hashed[..]); @@ -104,7 +104,7 @@ pub trait StorageNMap { let key_hashed = KG::final_key(key); let mut final_key = Vec::with_capacity( - module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len() + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(), ); final_key.extend_from_slice(&module_prefix_hashed[..]); @@ -168,7 +168,10 @@ where } } - fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { + fn insert + TupleToEncodedIter, VArg: EncodeLike>( + key: KArg, + val: VArg, + ) { unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); } @@ -176,7 +179,10 @@ where unhashed::kill(&Self::storage_n_map_final_key::(key)); } - fn remove_prefix(partial_key: KP) where K: HasKeyPrefix { + fn remove_prefix(partial_key: KP) + where + K: HasKeyPrefix, + { unhashed::kill_prefix(&Self::storage_n_map_partial_key(partial_key)); } @@ -193,17 +199,20 @@ where } } - fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>( - key: KArg, - f: F, - ) -> R { - Self::try_mutate(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") + fn mutate(key: KArg, f: F) -> R + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Self::Query) -> R, + { + Self::try_mutate(key, |v| Ok::(f(v))) + .expect("`Never` can not be constructed; qed") } - fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( - key: KArg, - f: F, - ) -> Result { + fn try_mutate(key: KArg, f: F) -> Result + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Self::Query) -> Result + { let final_key = Self::storage_n_map_final_key::(key); let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref())); @@ -217,17 +226,20 @@ where ret } - fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>( - key: KArg, - f: F, - ) -> R { - Self::try_mutate_exists(key, |v| Ok::(f(v))).expect("`Never` can not be constructed; qed") + fn mutate_exists(key: KArg, f: F) -> R + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> R, + { + Self::try_mutate_exists(key, |v| Ok::(f(v))) + .expect("`Never` can not be constructed; qed") } - fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( - key: KArg, - f: F, - ) -> Result { + fn try_mutate_exists(key: KArg, f: F) -> Result + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> Result, + { let final_key = Self::storage_n_map_final_key::(key); let mut val = unhashed::get(final_key.as_ref()); @@ -246,22 +258,23 @@ where KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, - V: StorageAppend + V: StorageAppend, { let final_key = Self::storage_n_map_final_key::(key); sp_io::storage::append(&final_key, item.encode()); } - - fn migrate_keys + TupleToEncodedIter>(key: KArg, hash_fns: K::HArg) -> Option { + + fn migrate_keys + TupleToEncodedIter>( + key: KArg, + hash_fns: K::HArg, + ) -> Option { let old_key = { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); let key_hashed = K::migrate_key(&key, hash_fns); let mut final_key = Vec::with_capacity( - module_prefix_hashed.len() - + storage_prefix_hashed.len() - + key_hashed.len() + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(), ); final_key.extend_from_slice(&module_prefix_hashed[..]); @@ -277,7 +290,9 @@ where } } -impl> storage::IterableStorageNMap for G { +impl> + storage::IterableStorageNMap for G +{ type Iterator = PrefixIterator<(K::Key, V)>; fn iter_prefix(kp: KP) -> PrefixIterator<(>::Suffix, V)> @@ -314,7 +329,7 @@ impl> storage::Ite closure: |raw_key_without_prefix, mut raw_value| { let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?; Ok((final_key, V::decode(&mut raw_value)?)) - } + }, } } @@ -327,23 +342,23 @@ impl> storage::Ite fn translate Option>(mut f: F) { let prefix = G::prefix_hash(); let mut previous_key = prefix.clone(); - while let Some(next) = sp_io::storage::next_key(&previous_key) - .filter(|n| n.starts_with(&prefix)) + while let Some(next) = + sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) { previous_key = next; let value = match unhashed::get::(&previous_key) { Some(value) => value, None => { log::error!("Invalid translate: fail to decode old value"); - continue - }, + continue; + } }; - + let final_key = match K::decode_final_key(&previous_key[prefix.len()..]) { Ok((final_key, _)) => final_key, Err(_) => { log::error!("Invalid translate: fail to decode key"); - continue + continue; } }; @@ -358,11 +373,11 @@ impl> storage::Ite /// Test iterators for StorageNMap #[cfg(test)] mod test_iterators { - use codec::{Encode, Decode}; use crate::{ hash::StorageHasher, - storage::{generator::StorageNMap, IterableStorageNMap, unhashed}, + storage::{generator::StorageNMap, unhashed, IterableStorageNMap}, }; + use codec::{Decode, Encode}; pub trait Config: 'static { type Origin; @@ -393,7 +408,10 @@ mod test_iterators { fn key_after_prefix(mut prefix: Vec) -> Vec { let last = prefix.iter_mut().last().unwrap(); - assert!(*last != 255, "mock function not implemented for this prefix"); + assert!( + *last != 255, + "mock function not implemented for this prefix" + ); *last += 1; prefix } @@ -416,10 +434,7 @@ mod test_iterators { vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)], ); - assert_eq!( - NMap::iter_values().collect::>(), - vec![3, 0, 2, 1], - ); + assert_eq!(NMap::iter_values().collect::>(), vec![3, 0, 2, 1],); assert_eq!( NMap::drain().collect::>(), @@ -427,7 +442,10 @@ mod test_iterators { ); assert_eq!(NMap::iter().collect::>(), vec![]); - assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64)); + assert_eq!( + unhashed::get(&key_before_prefix(prefix.clone())), + Some(1u64) + ); assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); // Prefix iterator @@ -457,7 +475,10 @@ mod test_iterators { ); assert_eq!(NMap::iter_prefix((k1,)).collect::>(), vec![]); - assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64)); + assert_eq!( + unhashed::get(&key_before_prefix(prefix.clone())), + Some(1u64) + ); assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64)); // Translate @@ -470,15 +491,16 @@ mod test_iterators { } // Wrong key1 - unhashed::put( - &[prefix.clone(), vec![1, 2, 3]].concat(), - &3u64.encode() - ); + unhashed::put(&[prefix.clone(), vec![1, 2, 3]].concat(), &3u64.encode()); // Wrong key2 unhashed::put( - &[prefix.clone(), crate::Blake2_128Concat::hash(&1u16.encode())].concat(), - &3u64.encode() + &[ + prefix.clone(), + crate::Blake2_128Concat::hash(&1u16.encode()), + ] + .concat(), + &3u64.encode(), ); // Wrong value @@ -487,11 +509,12 @@ mod test_iterators { prefix.clone(), crate::Blake2_128Concat::hash(&1u16.encode()), crate::Twox64Concat::hash(&2u32.encode()), - ].concat(), + ] + .concat(), &vec![1], ); - NMap::translate(|(_k1, _k2), v: u64| Some(v*2)); + NMap::translate(|(_k1, _k2), v: u64| Some(v * 2)); assert_eq!( NMap::iter().collect::>(), vec![((3, 3), 6), ((0, 0), 0), ((2, 2), 4), ((1, 1), 2)], diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index a6a46e8127043..6b64527c58f85 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -586,24 +586,30 @@ pub trait StorageNMap { fn iter_prefix_values(partial_key: KP) -> PrefixIterator where K: HasKeyPrefix; /// Mutate the value under a key. - fn mutate + TupleToEncodedIter, R, F: FnOnce(&mut Self::Query) -> R>(key: KArg, f: F) -> R; + fn mutate(key: KArg, f: F) -> R + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Self::Query) -> R; /// Mutate the item, only if an `Ok` value is returned. - fn try_mutate + TupleToEncodedIter, R, E, F: FnOnce(&mut Self::Query) -> Result>( - key: KArg, - f: F, - ) -> Result; + fn try_mutate(key: KArg, f: F) -> Result + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Self::Query) -> Result; /// Mutate the value under a key. /// /// Deletes the item if mutated to a `None`. - fn mutate_exists + TupleToEncodedIter, R, F: FnOnce(&mut Option) -> R>(key: KArg, f: F) -> R; + fn mutate_exists(key: KArg, f: F) -> R + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - fn try_mutate_exists + TupleToEncodedIter, R, E, F: FnOnce(&mut Option) -> Result>( - key: KArg, - f: F, - ) -> Result; + fn try_mutate_exists(key: KArg, f: F) -> Result + where + KArg: EncodeLike + TupleToEncodedIter, + F: FnOnce(&mut Option) -> Result; /// Take the value under a key. fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 184d96b3a54f9..fc256f2b4e3b6 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -18,15 +18,15 @@ //! Storage map type. Implements StorageDoubleMap, StorageIterableDoubleMap, //! StoragePrefixedDoubleMap traits and their methods directly. -use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ - storage::{ - StorageAppend, StorageDecodeLength, - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, - }, - traits::{GetDefault, StorageInstance, Get}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; +use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::vec::Vec; @@ -47,612 +47,688 @@ use sp_std::vec::Vec; /// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values /// in storage can be compromised. pub struct StorageDoubleMap< - Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind=OptionQuery, OnEmpty=GetDefault + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind = OptionQuery, + OnEmpty = GetDefault, >( - core::marker::PhantomData<(Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty)> + core::marker::PhantomData<( + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind, + OnEmpty, + )>, ); impl - crate::storage::generator::StorageDoubleMap for - StorageDoubleMap + crate::storage::generator::StorageDoubleMap + for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - type Hasher1 = Hasher1; - type Hasher2 = Hasher2; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + type Hasher1 = Hasher1; + type Hasher2 = Hasher2; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } impl - crate::storage::StoragePrefixedMap for - StorageDoubleMap + crate::storage::StoragePrefixedMap + for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() - } - fn storage_prefix() -> &'static [u8] { - >::storage_prefix() - } + fn module_prefix() -> &'static [u8] { + >::module_prefix() + } + fn storage_prefix() -> &'static [u8] { + >::storage_prefix() + } } impl - StorageDoubleMap< - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - BoundedVec, - QueryKind, - OnEmpty, - > where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + StorageDoubleMap< + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + BoundedVec, + QueryKind, + OnEmpty, + > +where + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the double map in the storage. - /// - /// Is only available if `Value` of the map is [`BoundedVec`]. - pub fn try_append( - key1: EncodeLikeKey1, - key2: EncodeLikeKey2, - item: EncodeLikeItem, - ) -> Result<(), ()> - where - EncodeLikeKey1: EncodeLike + Clone, - EncodeLikeKey2: EncodeLike + Clone, - EncodeLikeItem: EncodeLike, - { - < + /// Try and append the given item to the double map in the storage. + /// + /// Is only available if `Value` of the map is [`BoundedVec`]. + pub fn try_append( + key1: EncodeLikeKey1, + key2: EncodeLikeKey2, + item: EncodeLikeItem, + ) -> Result<(), ()> + where + EncodeLikeKey1: EncodeLike + Clone, + EncodeLikeKey2: EncodeLike + Clone, + EncodeLikeItem: EncodeLike, + { + < Self as crate::storage::bounded_vec::TryAppendDoubleMap >::try_append( key1, key2, item, ) - } + } } impl - StorageDoubleMap + StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::hashed_key_for(k1, k2) - } - - /// Does the value (explicitly) exist in storage? - pub fn contains_key(k1: KArg1, k2: KArg2) -> bool - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::contains_key(k1, k2) - } - - /// Load the value associated with the given key from the double map. - pub fn get(k1: KArg1, k2: KArg2) -> QueryKind::Query - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::get(k1, k2) - } - - /// Try to get the value for the given key from the double map. - /// - /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get(k1: KArg1, k2: KArg2) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike { - >::try_get(k1, k2) - } - - /// Take a value from storage, removing it afterwards. - pub fn take(k1: KArg1, k2: KArg2) -> QueryKind::Query - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::take(k1, k2) - } - - /// Swap the values of two key-pairs. - pub fn swap(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2) - where - XKArg1: EncodeLike, - XKArg2: EncodeLike, - YKArg1: EncodeLike, - YKArg2: EncodeLike, - { - >::swap(x_k1, x_k2, y_k1, y_k2) - } - - /// Store a value to be associated with the given keys from the double map. - pub fn insert(k1: KArg1, k2: KArg2, val: VArg) - where - KArg1: EncodeLike, - KArg2: EncodeLike, - VArg: EncodeLike, - { - >::insert(k1, k2, val) - } - - /// Remove the value under the given keys. - pub fn remove(k1: KArg1, k2: KArg2) - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::remove(k1, k2) - } - - /// Remove all values under the first key. - pub fn remove_prefix(k1: KArg1) where KArg1: ?Sized + EncodeLike { - >::remove_prefix(k1) - } - - /// Iterate over values that share the first key. - pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator - where KArg1: ?Sized + EncodeLike - { - >::iter_prefix_values(k1) - } - - /// Mutate the value under the given keys. - pub fn mutate(k1: KArg1, k2: KArg2, f: F) -> R - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> R, - { - >::mutate(k1, k2, f) - } - - /// Mutate the value under the given keys when the closure returns `Ok`. - pub fn try_mutate(k1: KArg1, k2: KArg2, f: F) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> Result, - { - >::try_mutate(k1, k2, f) - } - - /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. - pub fn mutate_exists(k1: KArg1, k2: KArg2, f: F) -> R - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut Option) -> R, - { - >::mutate_exists(k1, k2, f) - } - - /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut Option) -> Result, - { - >::try_mutate_exists(k1, k2, f) - } - - /// Append the given item to the value in the storage. - /// - /// `Value` is required to implement [`StorageAppend`]. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append( - k1: KArg1, - k2: KArg2, - item: EncodeLikeItem, - ) where - KArg1: EncodeLike, - KArg2: EncodeLike, - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend, - { - >::append(k1, k2, item) - } - - /// Read the length of the storage value without decoding the entire value under the - /// given `key1` and `key2`. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len(key1: KArg1, key2: KArg2) -> Option - where - KArg1: EncodeLike, - KArg2: EncodeLike, - Value: StorageDecodeLength, - { - >::decode_len(key1, key2) - } - - /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and - /// `OldHasher2` to the current hashers. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_keys< - OldHasher1: crate::StorageHasher, - OldHasher2: crate::StorageHasher, - KeyArg1: EncodeLike, - KeyArg2: EncodeLike, - >(key1: KeyArg1, key2: KeyArg2) -> Option { - < - Self as crate::storage::StorageDoubleMap - >::migrate_keys::(key1, key2) - } - - /// Remove all value of the storage. - pub fn remove_all() { - >::remove_all() - } - - /// Iter over all value of the storage. - /// - /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. - pub fn iter_values() -> crate::storage::PrefixIterator { - >::iter_values() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade. - pub fn translate_values Option>(f: F) { - >::translate_values(f) - } + /// Get the storage key used to fetch a value corresponding to a specific key. + pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::hashed_key_for(k1, k2) + } + + /// Does the value (explicitly) exist in storage? + pub fn contains_key(k1: KArg1, k2: KArg2) -> bool + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::contains_key(k1, k2) + } + + /// Load the value associated with the given key from the double map. + pub fn get(k1: KArg1, k2: KArg2) -> QueryKind::Query + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::get(k1, k2) + } + + /// Try to get the value for the given key from the double map. + /// + /// Returns `Ok` if it exists, `Err` if not. + pub fn try_get(k1: KArg1, k2: KArg2) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::try_get(k1, k2) + } + + /// Take a value from storage, removing it afterwards. + pub fn take(k1: KArg1, k2: KArg2) -> QueryKind::Query + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::take(k1, k2) + } + + /// Swap the values of two key-pairs. + pub fn swap( + x_k1: XKArg1, + x_k2: XKArg2, + y_k1: YKArg1, + y_k2: YKArg2, + ) where + XKArg1: EncodeLike, + XKArg2: EncodeLike, + YKArg1: EncodeLike, + YKArg2: EncodeLike, + { + >::swap(x_k1, x_k2, y_k1, y_k2) + } + + /// Store a value to be associated with the given keys from the double map. + pub fn insert(k1: KArg1, k2: KArg2, val: VArg) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + VArg: EncodeLike, + { + >::insert(k1, k2, val) + } + + /// Remove the value under the given keys. + pub fn remove(k1: KArg1, k2: KArg2) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::remove(k1, k2) + } + + /// Remove all values under the first key. + pub fn remove_prefix(k1: KArg1) + where + KArg1: ?Sized + EncodeLike, + { + >::remove_prefix(k1) + } + + /// Iterate over values that share the first key. + pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator + where + KArg1: ?Sized + EncodeLike, + { + >::iter_prefix_values(k1) + } + + /// Mutate the value under the given keys. + pub fn mutate(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> R, + { + >::mutate(k1, k2, f) + } + + /// Mutate the value under the given keys when the closure returns `Ok`. + pub fn try_mutate(k1: KArg1, k2: KArg2, f: F) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> Result, + { + >::try_mutate(k1, k2, f) + } + + /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. + pub fn mutate_exists(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut Option) -> R, + { + >::mutate_exists(k1, k2, f) + } + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut Option) -> Result, + { + >::try_mutate_exists(k1, k2, f) + } + + /// Append the given item to the value in the storage. + /// + /// `Value` is required to implement [`StorageAppend`]. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(k1: KArg1, k2: KArg2, item: EncodeLikeItem) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(k1, k2, item) + } + + /// Read the length of the storage value without decoding the entire value under the + /// given `key1` and `key2`. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len(key1: KArg1, key2: KArg2) -> Option + where + KArg1: EncodeLike, + KArg2: EncodeLike, + Value: StorageDecodeLength, + { + >::decode_len(key1, key2) + } + + /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and + /// `OldHasher2` to the current hashers. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_keys< + OldHasher1: crate::StorageHasher, + OldHasher2: crate::StorageHasher, + KeyArg1: EncodeLike, + KeyArg2: EncodeLike, + >( + key1: KeyArg1, + key2: KeyArg2, + ) -> Option { + >::migrate_keys::< + OldHasher1, + OldHasher2, + _, + _, + >(key1, key2) + } + + /// Remove all value of the storage. + pub fn remove_all() { + >::remove_all() + } + + /// Iter over all value of the storage. + /// + /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. + pub fn iter_values() -> crate::storage::PrefixIterator { + >::iter_values() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade. + pub fn translate_values Option>(f: F) { + >::translate_values(f) + } } impl - StorageDoubleMap + StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Hasher2: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Hasher2: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Enumerate all elements in the map with first key `k1` in no particular order. - /// - /// If you add or remove values whose first key is `k1` to the map while doing this, you'll get - /// undefined results. - pub fn iter_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { - >::iter_prefix(k1) - } - - /// Remove all elements from the map with first key `k1` and iterate through them in no - /// particular order. - /// - /// If you add elements with first key `k1` to the map while doing this, you'll get undefined - /// results. - pub fn drain_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { - >::drain_prefix(k1) - } - - /// Enumerate all elements in the map in no particular order. - /// - /// If you add or remove values to the map while doing this, you'll get undefined results. - pub fn iter() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { - >::iter() - } - - /// Remove all elements from the map and iterate through them in no particular order. - /// - /// If you add elements to the map while doing this, you'll get undefined results. - pub fn drain() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { - >::drain() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - pub fn translate Option>(f: F) { - >::translate(f) - } + /// Enumerate all elements in the map with first key `k1` in no particular order. + /// + /// If you add or remove values whose first key is `k1` to the map while doing this, you'll get + /// undefined results. + pub fn iter_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { + >::iter_prefix(k1) + } + + /// Remove all elements from the map with first key `k1` and iterate through them in no + /// particular order. + /// + /// If you add elements with first key `k1` to the map while doing this, you'll get undefined + /// results. + pub fn drain_prefix( + k1: impl EncodeLike, + ) -> crate::storage::PrefixIterator<(Key2, Value)> { + >::drain_prefix(k1) + } + + /// Enumerate all elements in the map in no particular order. + /// + /// If you add or remove values to the map while doing this, you'll get undefined results. + pub fn iter() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { + >::iter() + } + + /// Remove all elements from the map and iterate through them in no particular order. + /// + /// If you add elements to the map while doing this, you'll get undefined results. + pub fn drain() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { + >::drain() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + pub fn translate Option>(f: F) { + >::translate(f) + } } /// Part of storage metadata for a storage double map. /// /// NOTE: Generic hashers is supported. pub trait StorageDoubleMapMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; - const HASHER1: frame_metadata::StorageHasher; - const HASHER2: frame_metadata::StorageHasher; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; + const HASHER1: frame_metadata::StorageHasher; + const HASHER2: frame_metadata::StorageHasher; } impl StorageDoubleMapMetadata - for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + for StorageDoubleMap +where + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; - const HASHER2: frame_metadata::StorageHasher = Hasher2::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = - DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; + const HASHER2: frame_metadata::StorageHasher = Hasher2::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use sp_io::{TestExternalities, hashing::twox_128}; - use crate::hash::*; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { "test" } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = StorageDoubleMap< - Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u32, OptionQuery - >; - type AValueQueryWithAnOnEmpty = StorageDoubleMap< - Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u32, ValueQuery, ADefault - >; - type B = StorageDoubleMap; - type C = StorageDoubleMap; - type WithLen = StorageDoubleMap>; - - TestExternalities::default().execute_with(|| { - let mut k: Vec = vec![]; - k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"foo")); - k.extend(&3u16.blake2_128_concat()); - k.extend(&30u8.twox_64_concat()); - assert_eq!(A::hashed_key_for(3, 30).to_vec(), k); - - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::get(3, 30), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); - - A::insert(3, 30, 10); - assert_eq!(A::contains_key(3, 30), true); - assert_eq!(A::get(3, 30), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 10); - - A::swap(3, 30, 2, 20); - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(3, 30), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); - assert_eq!(A::get(2, 20), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(2, 20), 10); - - A::remove(2, 20); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(A::get(2, 20), None); - - AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(97 * 4)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; Ok(()) - }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(97 * 4)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; Err(()) - }); - assert_eq!(A::contains_key(2, 20), false); - - A::remove(2, 20); - AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { - assert!(v.is_none()); - *v = Some(10); - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - assert!(v.is_none()); - *v = Some(10); - Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - assert_eq!(A::try_get(2, 20), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - Err(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - - - A::insert(2, 20, 10); - assert_eq!(A::take(2, 20), Some(10)); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(AValueQueryWithAnOnEmpty::take(2, 20), 97); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(A::try_get(2, 20), Err(())); - - B::insert(2, 20, 10); - assert_eq!(A::migrate_keys::(2, 20), Some(10)); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - A::remove_all(); - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::contains_key(4, 40), false); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - - C::insert(3, 30, 10); - C::insert(4, 40, 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 40, 20), (3, 30, 20)]); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - assert_eq!(A::iter().collect::>(), vec![(4, 40, 10), (3, 30, 10)]); - assert_eq!(A::drain().collect::>(), vec![(4, 40, 10), (3, 30, 10)]); - assert_eq!(A::iter().collect::>(), vec![]); - - C::insert(3, 30, 10); - C::insert(4, 40, 10); - A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 40, 1600), (3, 30, 900)]); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); - assert_eq!(A::HASHER1, frame_metadata::StorageHasher::Blake2_128Concat); - assert_eq!(A::HASHER2, frame_metadata::StorageHasher::Twox64Concat); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER1, - frame_metadata::StorageHasher::Blake2_128Concat - ); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER2, - frame_metadata::StorageHasher::Twox64Concat - ); - assert_eq!(A::NAME, "foo"); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - - WithLen::remove_all(); - assert_eq!(WithLen::decode_len(3, 30), None); - WithLen::append(0, 100, 10); - assert_eq!(WithLen::decode_len(0, 100), Some(1)); - - A::insert(3, 30, 11); - A::insert(3, 31, 12); - A::insert(4, 40, 13); - A::insert(4, 41, 14); - assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); - assert_eq!(A::iter_prefix(3).collect::>(), vec![(31, 12), (30, 11)]); - assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); - assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); - - A::remove_prefix(3); - assert_eq!(A::iter_prefix(3).collect::>(), vec![]); - assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); - - assert_eq!(A::drain_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); - assert_eq!(A::iter_prefix(4).collect::>(), vec![]); - assert_eq!(A::drain_prefix(4).collect::>(), vec![]); - }) - } + use super::*; + use crate::hash::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = + StorageDoubleMap; + type AValueQueryWithAnOnEmpty = StorageDoubleMap< + Prefix, + Blake2_128Concat, + u16, + Twox64Concat, + u8, + u32, + ValueQuery, + ADefault, + >; + type B = StorageDoubleMap; + type C = StorageDoubleMap; + type WithLen = StorageDoubleMap>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + k.extend(&30u8.twox_64_concat()); + assert_eq!(A::hashed_key_for(3, 30).to_vec(), k); + + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::get(3, 30), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); + + A::insert(3, 30, 10); + assert_eq!(A::contains_key(3, 30), true); + assert_eq!(A::get(3, 30), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 10); + + A::swap(3, 30, 2, 20); + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(3, 30), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); + assert_eq!(A::get(2, 20), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(2, 20), 10); + + A::remove(2, 20); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(A::get(2, 20), None); + + AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(97 * 4)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Ok(()) + }); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(97 * 4)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Err(()) + }); + assert_eq!(A::contains_key(2, 20), false); + + A::remove(2, 20); + AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + assert_eq!(A::try_get(2, 20), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + + A::insert(2, 20, 10); + assert_eq!(A::take(2, 20), Some(10)); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(AValueQueryWithAnOnEmpty::take(2, 20), 97); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(A::try_get(2, 20), Err(())); + + B::insert(2, 20, 10); + assert_eq!( + A::migrate_keys::(2, 20), + Some(10) + ); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + A::remove_all(); + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::contains_key(4, 40), false); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert(3, 30, 10); + C::insert(4, 40, 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 20), (3, 30, 20)] + ); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 10), (3, 30, 10)] + ); + assert_eq!( + A::drain().collect::>(), + vec![(4, 40, 10), (3, 30, 10)] + ); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert(3, 30, 10); + C::insert(4, 40, 10); + A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 1600), (3, 30, 900)] + ); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::HASHER1, frame_metadata::StorageHasher::Blake2_128Concat); + assert_eq!(A::HASHER2, frame_metadata::StorageHasher::Twox64Concat); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER1, + frame_metadata::StorageHasher::Blake2_128Concat + ); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER2, + frame_metadata::StorageHasher::Twox64Concat + ); + assert_eq!(A::NAME, "foo"); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len(3, 30), None); + WithLen::append(0, 100, 10); + assert_eq!(WithLen::decode_len(0, 100), Some(1)); + + A::insert(3, 30, 11); + A::insert(3, 31, 12); + A::insert(4, 40, 13); + A::insert(4, 41, 14); + assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); + assert_eq!( + A::iter_prefix(3).collect::>(), + vec![(31, 12), (30, 11)] + ); + assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); + assert_eq!( + A::iter_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + + A::remove_prefix(3); + assert_eq!(A::iter_prefix(3).collect::>(), vec![]); + assert_eq!( + A::iter_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + + assert_eq!( + A::drain_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + assert_eq!(A::iter_prefix(4).collect::>(), vec![]); + assert_eq!(A::drain_prefix(4).collect::>(), vec![]); + }) + } } diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 28df03dd7e2b7..f1cd07d302c74 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -31,142 +31,161 @@ use sp_std::prelude::*; /// ++ ... /// ++ HasherN(encode(keyN)) /// ``` -pub struct Key( - core::marker::PhantomData<(Hasher, KeyType)>, -); +pub struct Key(core::marker::PhantomData<(Hasher, KeyType)>); /// A trait that contains the current key as an associated type. pub trait KeyGenerator { - type Key: EncodeLike; - type KArg: Encode; - type HashFn: FnOnce(&[u8]) -> Vec; - type HArg; - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; - fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec; - fn final_hash(encoded: &[u8]) -> Vec; + type Key: EncodeLike; + type KArg: Encode; + type HashFn: FnOnce(&[u8]) -> Vec; + type HArg; + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec; + fn final_hash(encoded: &[u8]) -> Vec; } impl KeyGenerator for Key { - type Key = K; - type KArg = (K,); - type HashFn = Box Vec>; - type HArg = (Self::HashFn,); - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { - H::hash(&key.to_encoded_iter().next().expect("should have at least one element!")).as_ref().to_vec() - } - - fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec { - (hash_fns.0)(&key.to_encoded_iter().next().expect("should have at least one element!")) - } - - fn final_hash(encoded: &[u8]) -> Vec { - H::hash(encoded).as_ref().to_vec() - } + type Key = K; + type KArg = (K,); + type HashFn = Box Vec>; + type HArg = (Self::HashFn,); + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + H::hash( + &key.to_encoded_iter() + .next() + .expect("should have at least one element!"), + ) + .as_ref() + .to_vec() + } + + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec { + (hash_fns.0)( + &key.to_encoded_iter() + .next() + .expect("should have at least one element!"), + ) + } + + fn final_hash(encoded: &[u8]) -> Vec { + H::hash(encoded).as_ref().to_vec() + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] impl KeyGenerator for Tuple { - for_tuples!( type Key = ( #(Tuple::Key),* ); ); - for_tuples!( type KArg = ( #(Tuple::Key),* ); ); - for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); - type HashFn = Box Vec>; - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { - let mut final_key = Vec::new(); - let mut iter = key.to_encoded_iter(); - for_tuples!( - #( - let next_encoded = iter.next().expect("KArg number should be equal to Key number"); - final_key.extend_from_slice(&Tuple::final_hash(&next_encoded)); - )* - ); - final_key - } - - fn migrate_key + TupleToEncodedIter>(key: &KArg, hash_fns: Self::HArg) -> Vec { - let mut migrated_key = Vec::new(); - let mut iter = key.to_encoded_iter(); - for_tuples!( - #( - let next_encoded = iter.next().expect("KArg number should be equal to Key number"); - migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded)); - )* - ); - migrated_key - } - - fn final_hash(encoded: &[u8]) -> Vec { - panic!("final_hash called on KeyGenerator tuple") - } + for_tuples!( type Key = ( #(Tuple::Key),* ); ); + for_tuples!( type KArg = ( #(Tuple::Key),* ); ); + for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); + type HashFn = Box Vec>; + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + let mut final_key = Vec::new(); + let mut iter = key.to_encoded_iter(); + for_tuples!( + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + final_key.extend_from_slice(&Tuple::final_hash(&next_encoded)); + )* + ); + final_key + } + + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec { + let mut migrated_key = Vec::new(); + let mut iter = key.to_encoded_iter(); + for_tuples!( + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded)); + )* + ); + migrated_key + } + + fn final_hash(encoded: &[u8]) -> Vec { + panic!("final_hash called on KeyGenerator tuple") + } } +/// Trait to indicate that a tuple can be converted into an iterator of a vector of encoded bytes. pub trait TupleToEncodedIter { - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; } impl TupleToEncodedIter for (A,) { - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { - vec![self.0.encode()].into_iter() - } + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + vec![self.0.encode()].into_iter() + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] #[tuple_types_no_default_trait_bound] impl TupleToEncodedIter for Tuple { - for_tuples!( where #(Tuple: Encode),* ); - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { - [ for_tuples!( #(self.Tuple.encode()),* ) ] - .to_vec() - .into_iter() - } + for_tuples!( where #(Tuple: Encode),* ); + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + [for_tuples!( #(self.Tuple.encode()),* )] + .to_vec() + .into_iter() + } } /// A trait that indicates the hashers for the keys generated are all reversible. pub trait ReversibleKeyGenerator: KeyGenerator { - type Hasher; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; + type Hasher; + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; } impl ReversibleKeyGenerator for Key { - type Hasher = H; + type Hasher = H; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { - let mut current_key_material = Self::Hasher::reverse(key_material); - let key = K::decode(&mut current_key_material)?; - Ok((key, current_key_material)) - } + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = Self::Hasher::reverse(key_material); + let key = K::decode(&mut current_key_material)?; + Ok((key, current_key_material)) + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] impl ReversibleKeyGenerator for Tuple { - for_tuples!( type Hasher = ( #(Tuple::Hasher),* ); ); - - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { - let mut current_key_material = key_material; - Ok((( - for_tuples!{ - #({ - let (key, material) = Tuple::decode_final_key(current_key_material)?; - current_key_material = material; - key - }),* - } - ), current_key_material)) - } + for_tuples!( type Hasher = ( #(Tuple::Hasher),* ); ); + + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = key_material; + Ok(( + (for_tuples! { + #({ + let (key, material) = Tuple::decode_final_key(current_key_material)?; + current_key_material = material; + key + }),* + }), + current_key_material, + )) + } } /// Trait indicating whether a KeyGenerator has the prefix P. pub trait HasKeyPrefix

: KeyGenerator { - type Suffix; + type Suffix; - fn partial_key(prefix: P) -> Vec; + fn partial_key(prefix: P) -> Vec; } /// Trait indicating whether a ReversibleKeyGenerator has the prefix P. pub trait HasReversibleKeyPrefix

: ReversibleKeyGenerator + HasKeyPrefix

{ - fn decode_partial_key(key_material: &[u8]) -> Result; + fn decode_partial_key(key_material: &[u8]) -> Result; } macro_rules! impl_key_prefix_for { @@ -241,22 +260,22 @@ macro_rules! impl_key_prefix_for { }; } -impl - HasKeyPrefix<(A,)> for (Key, Key) +impl HasKeyPrefix<(A,)> + for (Key, Key) { - type Suffix = B; + type Suffix = B; - fn partial_key(prefix: (A,)) -> Vec { - >::final_key(prefix) - } + fn partial_key(prefix: (A,)) -> Vec { + >::final_key(prefix) + } } impl - HasReversibleKeyPrefix<(A,)> for (Key, Key) + HasReversibleKeyPrefix<(A,)> for (Key, Key) { - fn decode_partial_key(key_material: &[u8]) -> Result { - >::decode_final_key(key_material).map(|k| k.0) - } + fn decode_partial_key(key_material: &[u8]) -> Result { + >::decode_final_key(key_material).map(|k| k.0) + } } impl_key_prefix_for!((A, B, C), (A, B), C); @@ -294,120 +313,588 @@ impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C, D), (E, F, G, H, I)) impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C), (D, E, F, G, H, I)); impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B), (C, D, E, F, G, H, I)); impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), A, (B, C, D, E, F, G, H, I)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G, H, I), J); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G, H), (I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F, G), (H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E, F), (G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D, E), (F, G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C, D), (E, F, G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B, C), (D, E, F, G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), (A, B), (C, D, E, F, G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J), A, (B, C, D, E, F, G, H, I, J)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H, I, J), K); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H, I), (J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H), (I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G), (H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F), (G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E), (F, G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D), (E, F, G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B, C), (D, E, F, G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), (A, B), (C, D, E, F, G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K), A, (B, C, D, E, F, G, H, I, J, K)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I, J, K), L); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I, J), (K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H, I), (J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G, H), (I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F, G), (H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E, F), (G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D, E), (F, G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C, D), (E, F, G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B, C), (D, E, F, G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), (A, B), (C, D, E, F, G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L), A, (B, C, D, E, F, G, H, I, J, K, L)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J, K, L), M); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J, K), (L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J), (K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I), (J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H), (I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G), (H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F), (G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E), (F, G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D), (E, F, G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C), (D, E, F, G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B), (C, D, E, F, G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M), A, (B, C, D, E, F, G, H, I, J, K, L, M)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K, L, M), N); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N), A, (B, C, D, E, F, G, H, I, J, K, L, M, N)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), O); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), P); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), Q); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), R); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), (Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M, N), (O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L, M), (N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K, L), (M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J, K), (L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I, J), (K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H, I), (J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G, H), (I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F, G), (H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E, F), (G, H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D, E), (F, G, H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C, D), (E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B, C), (D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), (A, B), (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); -impl_key_prefix_for!((A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), A, (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R)); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G, H, I), + J +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G, H), + (I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G), + (H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F), + (G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E), + (F, G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D), + (E, F, G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B, C), + (D, E, F, G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + (A, B), + (C, D, E, F, G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J), + A, + (B, C, D, E, F, G, H, I, J) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H, I, J), + K +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H, I), + (J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H), + (I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G), + (H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F), + (G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E), + (F, G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D), + (E, F, G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C), + (D, E, F, G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + (A, B), + (C, D, E, F, G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K), + A, + (B, C, D, E, F, G, H, I, J, K) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I, J, K), + L +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I, J), + (K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I), + (J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H), + (I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G), + (H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F), + (G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E), + (F, G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D), + (E, F, G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C), + (D, E, F, G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B), + (C, D, E, F, G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L), + A, + (B, C, D, E, F, G, H, I, J, K, L) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J, K, L), + M +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M), + A, + (B, C, D, E, F, G, H, I, J, K, L, M) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + N +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + O +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + P +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + Q +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + R +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) +); +impl_key_prefix_for!( + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) +); diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index 187323b4ad1ee..e01a4b14f2920 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -18,15 +18,15 @@ //! Storage map type. Implements StorageMap, StorageIterableMap, StoragePrefixedMap traits and their //! methods directly. -use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ - storage::{ - StorageAppend, StorageDecodeLength, - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, - }, - traits::{GetDefault, StorageInstance, Get}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; +use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::prelude::*; @@ -43,475 +43,487 @@ use sp_std::prelude::*; /// /// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as /// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised. -pub struct StorageMap( - core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)> +pub struct StorageMap( + core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>, ); impl - crate::storage::generator::StorageMap - for StorageMap + crate::storage::generator::StorageMap + for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - type Hasher = Hasher; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + type Hasher = Hasher; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } -impl crate::storage::StoragePrefixedMap for - StorageMap +impl crate::storage::StoragePrefixedMap + for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() - } - fn storage_prefix() -> &'static [u8] { - >::storage_prefix() - } + fn module_prefix() -> &'static [u8] { + >::module_prefix() + } + fn storage_prefix() -> &'static [u8] { + >::storage_prefix() + } } impl - StorageMap, QueryKind, OnEmpty> + StorageMap, QueryKind, OnEmpty> where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the map in the storage. - /// - /// Is only available if `Value` of the map is [`BoundedVec`]. - pub fn try_append( - key: EncodeLikeKey, - item: EncodeLikeItem, - ) -> Result<(), ()> - where - EncodeLikeKey: EncodeLike + Clone, - EncodeLikeItem: EncodeLike, - { - >::try_append( - key, item, - ) - } + /// Try and append the given item to the map in the storage. + /// + /// Is only available if `Value` of the map is [`BoundedVec`]. + pub fn try_append( + key: EncodeLikeKey, + item: EncodeLikeItem, + ) -> Result<(), ()> + where + EncodeLikeKey: EncodeLike + Clone, + EncodeLikeItem: EncodeLike, + { + >::try_append( + key, item, + ) + } } impl - StorageMap + StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for>(key: KeyArg) -> Vec { - >::hashed_key_for(key) - } - - /// Does the value (explicitly) exist in storage? - pub fn contains_key>(key: KeyArg) -> bool { - >::contains_key(key) - } - - /// Load the value associated with the given key from the map. - pub fn get>(key: KeyArg) -> QueryKind::Query { - >::get(key) - } - - /// Try to get the value for the given key from the map. - /// - /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get>(key: KeyArg) -> Result { - >::try_get(key) - } - - /// Swap the values of two keys. - pub fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2) { - >::swap(key1, key2) - } - - /// Store a value to be associated with the given key from the map. - pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { - >::insert(key, val) - } - - /// Remove the value under a key. - pub fn remove>(key: KeyArg) { - >::remove(key) - } - - /// Mutate the value under a key. - pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( - key: KeyArg, - f: F - ) -> R { - >::mutate(key, f) - } - - /// Mutate the item, only if an `Ok` value is returned. - pub fn try_mutate(key: KeyArg, f: F) -> Result - where - KeyArg: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> Result, - { - >::try_mutate(key, f) - } - - /// Mutate the value under a key. Deletes the item if mutated to a `None`. - pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( - key: KeyArg, - f: F - ) -> R { - >::mutate_exists(key, f) - } - - /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists(key: KeyArg, f: F) -> Result - where - KeyArg: EncodeLike, - F: FnOnce(&mut Option) -> Result, - { - >::try_mutate_exists(key, f) - } - - /// Take the value under a key. - pub fn take>(key: KeyArg) -> QueryKind::Query { - >::take(key) - } - - /// Append the given items to the value in the storage. - /// - /// `Value` is required to implement `codec::EncodeAppend`. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) - where - EncodeLikeKey: EncodeLike, - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend - { - >::append(key, item) - } - - /// Read the length of the storage value without decoding the entire value under the - /// given `key`. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len>(key: KeyArg) -> Option - where Value: StorageDecodeLength, - { - >::decode_len(key) - } - - /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_key>( - key: KeyArg - ) -> Option { - >::migrate_key::(key) - } - - /// Remove all value of the storage. - pub fn remove_all() { - >::remove_all() - } - - /// Iter over all value of the storage. - /// - /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. - pub fn iter_values() -> crate::storage::PrefixIterator { - >::iter_values() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade. - pub fn translate_values Option>(f: F) { - >::translate_values(f) - } + /// Get the storage key used to fetch a value corresponding to a specific key. + pub fn hashed_key_for>(key: KeyArg) -> Vec { + >::hashed_key_for(key) + } + + /// Does the value (explicitly) exist in storage? + pub fn contains_key>(key: KeyArg) -> bool { + >::contains_key(key) + } + + /// Load the value associated with the given key from the map. + pub fn get>(key: KeyArg) -> QueryKind::Query { + >::get(key) + } + + /// Try to get the value for the given key from the map. + /// + /// Returns `Ok` if it exists, `Err` if not. + pub fn try_get>(key: KeyArg) -> Result { + >::try_get(key) + } + + /// Swap the values of two keys. + pub fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2) { + >::swap(key1, key2) + } + + /// Store a value to be associated with the given key from the map. + pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { + >::insert(key, val) + } + + /// Remove the value under a key. + pub fn remove>(key: KeyArg) { + >::remove(key) + } + + /// Mutate the value under a key. + pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( + key: KeyArg, + f: F, + ) -> R { + >::mutate(key, f) + } + + /// Mutate the item, only if an `Ok` value is returned. + pub fn try_mutate(key: KeyArg, f: F) -> Result + where + KeyArg: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> Result, + { + >::try_mutate(key, f) + } + + /// Mutate the value under a key. Deletes the item if mutated to a `None`. + pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( + key: KeyArg, + f: F, + ) -> R { + >::mutate_exists(key, f) + } + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists(key: KeyArg, f: F) -> Result + where + KeyArg: EncodeLike, + F: FnOnce(&mut Option) -> Result, + { + >::try_mutate_exists(key, f) + } + + /// Take the value under a key. + pub fn take>(key: KeyArg) -> QueryKind::Query { + >::take(key) + } + + /// Append the given items to the value in the storage. + /// + /// `Value` is required to implement `codec::EncodeAppend`. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) + where + EncodeLikeKey: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(key, item) + } + + /// Read the length of the storage value without decoding the entire value under the + /// given `key`. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len>(key: KeyArg) -> Option + where + Value: StorageDecodeLength, + { + >::decode_len(key) + } + + /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_key>( + key: KeyArg, + ) -> Option { + >::migrate_key::(key) + } + + /// Remove all value of the storage. + pub fn remove_all() { + >::remove_all() + } + + /// Iter over all value of the storage. + /// + /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. + pub fn iter_values() -> crate::storage::PrefixIterator { + >::iter_values() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade. + pub fn translate_values Option>(f: F) { + >::translate_values(f) + } } impl - StorageMap + StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Enumerate all elements in the map in no particular order. - /// - /// If you alter the map while doing this, you'll get undefined results. - pub fn iter() -> crate::storage::PrefixIterator<(Key, Value)> { - >::iter() - } - - /// Remove all elements from the map and iterate through them in no particular order. - /// - /// If you add elements to the map while doing this, you'll get undefined results. - pub fn drain() -> crate::storage::PrefixIterator<(Key, Value)> { - >::drain() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - pub fn translate Option>(f: F) { - >::translate(f) - } + /// Enumerate all elements in the map in no particular order. + /// + /// If you alter the map while doing this, you'll get undefined results. + pub fn iter() -> crate::storage::PrefixIterator<(Key, Value)> { + >::iter() + } + + /// Remove all elements from the map and iterate through them in no particular order. + /// + /// If you add elements to the map while doing this, you'll get undefined results. + pub fn drain() -> crate::storage::PrefixIterator<(Key, Value)> { + >::drain() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + pub fn translate Option>(f: F) { + >::translate(f) + } } /// Part of storage metadata for a storage map. /// /// NOTE: Generic hasher is supported. pub trait StorageMapMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; - const HASHER: frame_metadata::StorageHasher; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; + const HASHER: frame_metadata::StorageHasher; } impl StorageMapMetadata - for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + for StorageMap +where + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = - DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use sp_io::{TestExternalities, hashing::twox_128}; - use crate::hash::*; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { "test" } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = StorageMap; - type AValueQueryWithAnOnEmpty = StorageMap< - Prefix, Blake2_128Concat, u16, u32, ValueQuery, ADefault - >; - type B = StorageMap; - type C = StorageMap; - type WithLen = StorageMap>; - - TestExternalities::default().execute_with(|| { - let mut k: Vec = vec![]; - k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"foo")); - k.extend(&3u16.blake2_128_concat()); - assert_eq!(A::hashed_key_for(3).to_vec(), k); - - assert_eq!(A::contains_key(3), false); - assert_eq!(A::get(3), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); - - A::insert(3, 10); - assert_eq!(A::contains_key(3), true); - assert_eq!(A::get(3), Some(10)); - assert_eq!(A::try_get(3), Ok(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); - - A::swap(3, 2); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(3), None); - assert_eq!(A::try_get(3), Err(())); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); - assert_eq!(A::get(2), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); - - A::remove(2); - assert_eq!(A::contains_key(2), false); - assert_eq!(A::get(2), None); - - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - assert_eq!(AValueQueryWithAnOnEmpty::contains_key(2), true); - assert_eq!(AValueQueryWithAnOnEmpty::get(2), 97 * 4); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; Ok(()) - }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(97 * 4)); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; Err(()) - }); - assert_eq!(A::contains_key(2), false); - - A::remove(2); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { - assert!(v.is_none()); - *v = Some(10); - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - assert!(v.is_none()); - *v = Some(10); - Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - Err(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - - - A::insert(2, 10); - assert_eq!(A::take(2), Some(10)); - assert_eq!(A::contains_key(2), false); - assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97); - assert_eq!(A::contains_key(2), false); - - B::insert(2, 10); - assert_eq!(A::migrate_key::(2), Some(10)); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - - A::insert(3, 10); - A::insert(4, 10); - A::remove_all(); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(4), false); - - A::insert(3, 10); - A::insert(4, 10); - assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - - C::insert(3, 10); - C::insert(4, 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); - - A::insert(3, 10); - A::insert(4, 10); - assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); - assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); - assert_eq!(A::iter().collect::>(), vec![]); - - C::insert(3, 10); - C::insert(4, 10); - A::translate::(|k, v| Some((k * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); - assert_eq!(A::HASHER, frame_metadata::StorageHasher::Blake2_128Concat); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER, - frame_metadata::StorageHasher::Blake2_128Concat - ); - assert_eq!(A::NAME, "foo"); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - - WithLen::remove_all(); - assert_eq!(WithLen::decode_len(3), None); - WithLen::append(0, 10); - assert_eq!(WithLen::decode_len(0), Some(1)); - }) - } + use super::*; + use crate::hash::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = StorageMap; + type AValueQueryWithAnOnEmpty = + StorageMap; + type B = StorageMap; + type C = StorageMap; + type WithLen = StorageMap>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + assert_eq!(A::hashed_key_for(3).to_vec(), k); + + assert_eq!(A::contains_key(3), false); + assert_eq!(A::get(3), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); + + A::insert(3, 10); + assert_eq!(A::contains_key(3), true); + assert_eq!(A::get(3), Some(10)); + assert_eq!(A::try_get(3), Ok(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); + + A::swap(3, 2); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(3), None); + assert_eq!(A::try_get(3), Err(())); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); + assert_eq!(A::get(2), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); + + A::remove(2); + assert_eq!(A::contains_key(2), false); + assert_eq!(A::get(2), None); + + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + assert_eq!(AValueQueryWithAnOnEmpty::contains_key(2), true); + assert_eq!(AValueQueryWithAnOnEmpty::get(2), 97 * 4); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Ok(()) + }); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(97 * 4)); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Err(()) + }); + assert_eq!(A::contains_key(2), false); + + A::remove(2); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + + A::insert(2, 10); + assert_eq!(A::take(2), Some(10)); + assert_eq!(A::contains_key(2), false); + assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97); + assert_eq!(A::contains_key(2), false); + + B::insert(2, 10); + assert_eq!(A::migrate_key::(2), Some(10)); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + + A::insert(3, 10); + A::insert(4, 10); + A::remove_all(); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(4), false); + + A::insert(3, 10); + A::insert(4, 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert(3, 10); + C::insert(4, 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); + + A::insert(3, 10); + A::insert(4, 10); + assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); + assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert(3, 10); + C::insert(4, 10); + A::translate::(|k, v| Some((k * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::HASHER, frame_metadata::StorageHasher::Blake2_128Concat); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER, + frame_metadata::StorageHasher::Blake2_128Concat + ); + assert_eq!(A::NAME, "foo"); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len(3), None); + WithLen::append(0, 10); + assert_eq!(WithLen::decode_len(0), Some(1)); + }) + } } diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 11e49be6c636f..001a6e1f23408 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -21,17 +21,20 @@ use codec::FullCodec; use frame_metadata::{DefaultByte, StorageEntryModifier}; +mod double_map; mod key; -mod value; mod map; mod nmap; -mod double_map; +mod value; -pub use key::{HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator, TupleToEncodedIter}; -pub use value::{StorageValue, StorageValueMetadata}; +pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; +pub use key::{ + HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator, + TupleToEncodedIter, +}; pub use map::{StorageMap, StorageMapMetadata}; pub use nmap::{StorageNMap, StorageNMapMetadata}; -pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; +pub use value::{StorageValue, StorageValueMetadata}; /// Trait implementing how the storage optional value is converted into the queried type. /// @@ -108,5 +111,5 @@ impl> DefaultByte OnEmpty::get().encode() } } -unsafe impl > Send for OnEmptyGetter {} -unsafe impl > Sync for OnEmptyGetter {} +unsafe impl> Send for OnEmptyGetter {} +unsafe impl> Sync for OnEmptyGetter {} diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 73c41fc6ae2bd..8e6b5792198c6 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -18,7 +18,6 @@ //! Storage map type. Implements StorageDoubleMap, StorageIterableDoubleMap, //! StoragePrefixedDoubleMap traits and their methods directly. -use codec::{Decode, Encode, EncodeLike, FullCodec}; use crate::{ storage::{ types::{HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter, OptionQuery, QueryKindTrait}, @@ -26,6 +25,7 @@ use crate::{ }, traits::{GetDefault, StorageInstance}, }; +use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::prelude::*; @@ -50,9 +50,8 @@ pub struct StorageNMap, ); -impl - crate::storage::generator::StorageNMap for - StorageNMap +impl crate::storage::generator::StorageNMap + for StorageNMap where Prefix: StorageInstance, Key: super::key::KeyGenerator, @@ -75,9 +74,8 @@ where } } -impl - crate::storage::StoragePrefixedMap for - StorageNMap +impl crate::storage::StoragePrefixedMap + for StorageNMap where Prefix: StorageInstance, Key: super::key::KeyGenerator, @@ -93,8 +91,7 @@ where } } -impl - StorageNMap +impl StorageNMap where Prefix: StorageInstance, Key: super::key::KeyGenerator, @@ -120,7 +117,9 @@ where /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get + TupleToEncodedIter>(key: KArg) -> Result { + pub fn try_get + TupleToEncodedIter>( + key: KArg, + ) -> Result { >::try_get(key) } @@ -140,7 +139,10 @@ where } /// Store a value to be associated with the given keys from the map. - pub fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg) { + pub fn insert + TupleToEncodedIter, VArg: EncodeLike>( + key: KArg, + val: VArg, + ) { >::insert(key, val) } @@ -150,7 +152,10 @@ where } /// Remove all values under the first key. - pub fn remove_prefix(partial_key: KP) where Key: HasKeyPrefix { + pub fn remove_prefix(partial_key: KP) + where + Key: HasKeyPrefix, + { >::remove_prefix(partial_key) } @@ -212,7 +217,7 @@ where KArg: EncodeLike + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, - Value: StorageAppend + Value: StorageAppend, { >::append(key, item) } @@ -243,9 +248,7 @@ where key: KArg, hash_fns: Key::HArg, ) -> Option { - < - Self as crate::storage::StorageNMap - >::migrate_keys::<_>(key, hash_fns) + >::migrate_keys::<_>(key, hash_fns) } /// Remove all value of the storage. @@ -284,13 +287,15 @@ where Key: super::key::ReversibleKeyGenerator, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static + OnEmpty: crate::traits::Get + 'static, { /// Enumerate all elements in the map with prefix key `kp` in no particular order. /// /// If you add or remove values whose prefix key is `kp` to the map while doing this, you'll get /// undefined results. - pub fn iter_prefix(kp: KP) -> crate::storage::PrefixIterator<(>::Suffix, Value)> + pub fn iter_prefix( + kp: KP, + ) -> crate::storage::PrefixIterator<(>::Suffix, Value)> where Key: HasReversibleKeyPrefix, { @@ -302,7 +307,9 @@ where /// /// If you add elements with prefix key `k1` to the map while doing this, you'll get undefined /// results. - pub fn drain_prefix(kp: KP) -> crate::storage::PrefixIterator<(>::Suffix, Value)> + pub fn drain_prefix( + kp: KP, + ) -> crate::storage::PrefixIterator<(>::Suffix, Value)> where Key: HasReversibleKeyPrefix, { @@ -353,21 +360,24 @@ where { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = - DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { use super::*; - use sp_io::{TestExternalities, hashing::twox_128}; use crate::hash::*; use crate::storage::types::{Key, ValueQuery}; use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { "test" } + fn pallet_prefix() -> &'static str { + "test" + } const STORAGE_PREFIX: &'static str = "foo"; } @@ -381,9 +391,8 @@ mod test { #[test] fn test_1_key() { type A = StorageNMap, u32, OptionQuery>; - type AValueQueryWithAnOnEmpty = StorageNMap< - Prefix, Key, u32, ValueQuery, ADefault - >; + type AValueQueryWithAnOnEmpty = + StorageNMap, u32, ValueQuery, ADefault>; type B = StorageNMap, u32, ValueQuery>; type C = StorageNMap, u8, ValueQuery>; type WithLen = StorageNMap, Vec>; @@ -423,17 +432,20 @@ mod test { A::remove((2,)); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { - *v = *v * 2; Ok(()) + *v = *v * 2; + Ok(()) }); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { - *v = *v * 2; Ok(()) + *v = *v * 2; + Ok(()) }); assert_eq!(A::contains_key((2,)), true); assert_eq!(A::get((2,)), Some(98 * 4)); A::remove((2,)); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2,), |v| { - *v = *v * 2; Err(()) + *v = *v * 2; + Err(()) }); assert_eq!(A::contains_key((2,)), false); @@ -472,7 +484,6 @@ mod test { assert_eq!(A::contains_key((2,)), true); assert_eq!(A::get((2,)), Some(100)); - A::insert((2,), 10); assert_eq!(A::take((2,)), Some(10)); assert_eq!(A::contains_key((2,)), false); @@ -481,12 +492,10 @@ mod test { assert_eq!(A::try_get((2,)), Err(())); B::insert((2,), 10); - assert_eq!(A::migrate_keys( - (2,), - ( - Box::new(|key| Blake2_256::hash(key).to_vec()), - ), - ), Some(10)); + assert_eq!( + A::migrate_keys((2,), (Box::new(|key| Blake2_256::hash(key).to_vec()),),), + Some(10) + ); assert_eq!(A::contains_key((2,)), true); assert_eq!(A::get((2,)), Some(10)); @@ -502,7 +511,7 @@ mod test { C::insert((3,), 10); C::insert((4,), 10); - A::translate_values::(|v| Some((v * 2).into())); + A::translate_values::(|v| Some((v * 2).into())); assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); A::insert((3,), 10); @@ -513,13 +522,19 @@ mod test { C::insert((3,), 10); C::insert((4,), 10); - A::translate::(|k1, v| Some((k1 as u16 * v as u16).into())); + A::translate::(|k1, v| Some((k1 as u16 * v as u16).into())); assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); assert_eq!(A::NAME, "foo"); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 98u32.encode() + ); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); @@ -531,13 +546,28 @@ mod test { #[test] fn test_2_keys() { - type A = StorageNMap, Key), u32, OptionQuery>; + type A = StorageNMap< + Prefix, + (Key, Key), + u32, + OptionQuery, + >; type AValueQueryWithAnOnEmpty = StorageNMap< - Prefix, (Key, Key), u32, ValueQuery, ADefault + Prefix, + (Key, Key), + u32, + ValueQuery, + ADefault, >; type B = StorageNMap, Key), u32, ValueQuery>; - type C = StorageNMap, Key), u8, ValueQuery>; - type WithLen = StorageNMap, Key), Vec>; + type C = StorageNMap< + Prefix, + (Key, Key), + u8, + ValueQuery, + >; + type WithLen = + StorageNMap, Key), Vec>; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -575,13 +605,15 @@ mod test { A::remove((2, 20)); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20), |v| { - *v = *v * 2; Err(()) + *v = *v * 2; + Err(()) }); assert_eq!(A::contains_key((2, 20)), false); A::remove((2, 20)); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20), |v| { - *v = *v * 2; Err(()) + *v = *v * 2; + Err(()) }); assert_eq!(A::contains_key((2, 20)), false); @@ -620,7 +652,6 @@ mod test { assert_eq!(A::contains_key((2, 20)), true); assert_eq!(A::get((2, 20)), Some(100)); - A::insert((2, 20), 10); assert_eq!(A::take((2, 20)), Some(10)); assert_eq!(A::contains_key((2, 20)), false); @@ -629,13 +660,16 @@ mod test { assert_eq!(A::try_get((2, 20)), Err(())); B::insert((2, 20), 10); - assert_eq!(A::migrate_keys( - (2, 20), - ( - Box::new(|key| Blake2_256::hash(key).to_vec()), - Box::new(|key| Twox128::hash(key).to_vec()), + assert_eq!( + A::migrate_keys( + (2, 20), + ( + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Twox128::hash(key).to_vec()), + ), ), - ), Some(10)); + Some(10) + ); assert_eq!(A::contains_key((2, 20)), true); assert_eq!(A::get((2, 20)), Some(10)); @@ -651,24 +685,42 @@ mod test { C::insert((3, 30), 10); C::insert((4, 40), 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![((4, 40), 20), ((3, 30), 20)]); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40), 20), ((3, 30), 20)] + ); A::insert((3, 30), 10); A::insert((4, 40), 10); - assert_eq!(A::iter().collect::>(), vec![((4, 40), 10), ((3, 30), 10)]); - assert_eq!(A::drain().collect::>(), vec![((4, 40), 10), ((3, 30), 10)]); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40), 10), ((3, 30), 10)] + ); + assert_eq!( + A::drain().collect::>(), + vec![((4, 40), 10), ((3, 30), 10)] + ); assert_eq!(A::iter().collect::>(), vec![]); C::insert((3, 30), 10); C::insert((4, 40), 10); - A::translate::(|(k1, k2), v| Some((k1 * k2 as u16 * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![((4, 40), 1600), ((3, 30), 900)]); + A::translate::(|(k1, k2), v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40), 1600), ((3, 30), 900)] + ); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); assert_eq!(A::NAME, "foo"); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 98u32.encode() + ); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); @@ -680,20 +732,69 @@ mod test { A::insert((3, 31), 12); A::insert((4, 40), 13); A::insert((4, 41), 14); - assert_eq!(A::iter_prefix_values((3,)).collect::>(), vec![12, 11]); - assert_eq!(A::iter_prefix_values((4,)).collect::>(), vec![13, 14]); + assert_eq!( + A::iter_prefix_values((3,)).collect::>(), + vec![12, 11] + ); + assert_eq!( + A::iter_prefix_values((4,)).collect::>(), + vec![13, 14] + ); }); } #[test] fn test_3_keys() { - type A = StorageNMap, Key, Key), u32, OptionQuery>; + type A = StorageNMap< + Prefix, + ( + Key, + Key, + Key, + ), + u32, + OptionQuery, + >; type AValueQueryWithAnOnEmpty = StorageNMap< - Prefix, (Key, Key, Key), u32, ValueQuery, ADefault + Prefix, + ( + Key, + Key, + Key, + ), + u32, + ValueQuery, + ADefault, + >; + type B = StorageNMap< + Prefix, + ( + Key, + Key, + Key, + ), + u32, + ValueQuery, + >; + type C = StorageNMap< + Prefix, + ( + Key, + Key, + Key, + ), + u8, + ValueQuery, + >; + type WithLen = StorageNMap< + Prefix, + ( + Key, + Key, + Key, + ), + Vec, >; - type B = StorageNMap, Key, Key), u32, ValueQuery>; - type C = StorageNMap, Key, Key), u8, ValueQuery>; - type WithLen = StorageNMap, Key, Key), Vec>; TestExternalities::default().execute_with(|| { let mut k: Vec = vec![]; @@ -713,10 +814,15 @@ mod test { assert_eq!(A::get((1, 10, 100)), Some(30)); assert_eq!(AValueQueryWithAnOnEmpty::get((1, 10, 100)), 30); - A::swap::<(Key, Key, Key), _, _>( - (1, 10, 100), - (2, 20, 200), - ); + A::swap::< + ( + Key, + Key, + Key, + ), + _, + _, + >((1, 10, 100), (2, 20, 200)); assert_eq!(A::contains_key((1, 10, 100)), false); assert_eq!(A::contains_key((2, 20, 200)), true); assert_eq!(A::get((1, 10, 100)), None); @@ -735,7 +841,8 @@ mod test { A::remove((2, 20, 200)); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate((2, 20, 200), |v| { - *v = *v * 2; Err(()) + *v = *v * 2; + Err(()) }); assert_eq!(A::contains_key((2, 20, 200)), false); @@ -753,28 +860,30 @@ mod test { assert_eq!(A::get((2, 20, 200)), Some(100)); A::remove((2, 20, 200)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { - assert!(v.is_none()); - *v = Some(10); - Ok(()) - }); + let _: Result<(), ()> = + AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); assert_eq!(A::contains_key((2, 20, 200)), true); assert_eq!(A::get((2, 20, 200)), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { - *v = Some(v.unwrap() * 10); - Ok(()) - }); + let _: Result<(), ()> = + AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); assert_eq!(A::contains_key((2, 20, 200)), true); assert_eq!(A::get((2, 20, 200)), Some(100)); assert_eq!(A::try_get((2, 20, 200)), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { - *v = Some(v.unwrap() * 10); - Err(()) - }); + let _: Result<(), ()> = + AValueQueryWithAnOnEmpty::try_mutate_exists((2, 20, 200), |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); assert_eq!(A::contains_key((2, 20, 200)), true); assert_eq!(A::get((2, 20, 200)), Some(100)); - A::insert((2, 20, 200), 10); assert_eq!(A::take((2, 20, 200)), Some(10)); assert_eq!(A::contains_key((2, 20, 200)), false); @@ -783,14 +892,17 @@ mod test { assert_eq!(A::try_get((2, 20, 200)), Err(())); B::insert((2, 20, 200), 10); - assert_eq!(A::migrate_keys( - (2, 20, 200), - ( - Box::new(|key| Blake2_256::hash(key).to_vec()), - Box::new(|key| Blake2_256::hash(key).to_vec()), - Box::new(|key| Twox128::hash(key).to_vec()), + assert_eq!( + A::migrate_keys( + (2, 20, 200), + ( + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Blake2_256::hash(key).to_vec()), + Box::new(|key| Twox128::hash(key).to_vec()), + ), ), - ), Some(10)); + Some(10) + ); assert_eq!(A::contains_key((2, 20, 200)), true); assert_eq!(A::get((2, 20, 200)), Some(10)); @@ -806,24 +918,44 @@ mod test { C::insert((3, 30, 300), 10); C::insert((4, 40, 400), 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 20), ((3, 30, 300), 20)]); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40, 400), 20), ((3, 30, 300), 20)] + ); A::insert((3, 30, 300), 10); A::insert((4, 40, 400), 10); - assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 10), ((3, 30, 300), 10)]); - assert_eq!(A::drain().collect::>(), vec![((4, 40, 400), 10), ((3, 30, 300), 10)]); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40, 400), 10), ((3, 30, 300), 10)] + ); + assert_eq!( + A::drain().collect::>(), + vec![((4, 40, 400), 10), ((3, 30, 300), 10)] + ); assert_eq!(A::iter().collect::>(), vec![]); C::insert((3, 30, 300), 10); C::insert((4, 40, 400), 10); - A::translate::(|(k1, k2, k3), v| Some((k1 * k2 as u16 * v as u16 / k3 as u16).into())); - assert_eq!(A::iter().collect::>(), vec![((4, 40, 400), 4), ((3, 30, 300), 3)]); + A::translate::(|(k1, k2, k3), v| { + Some((k1 * k2 as u16 * v as u16 / k3 as u16).into()) + }); + assert_eq!( + A::iter().collect::>(), + vec![((4, 40, 400), 4), ((3, 30, 300), 3)] + ); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); assert_eq!(A::NAME, "foo"); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 98u32.encode()); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 98u32.encode() + ); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); @@ -835,10 +967,22 @@ mod test { A::insert((3, 30, 301), 12); A::insert((4, 40, 400), 13); A::insert((4, 40, 401), 14); - assert_eq!(A::iter_prefix_values((3,)).collect::>(), vec![11, 12]); - assert_eq!(A::iter_prefix_values((4,)).collect::>(), vec![14, 13]); - assert_eq!(A::iter_prefix_values((3, 30)).collect::>(), vec![11, 12]); - assert_eq!(A::iter_prefix_values((4, 40)).collect::>(), vec![14, 13]); + assert_eq!( + A::iter_prefix_values((3,)).collect::>(), + vec![11, 12] + ); + assert_eq!( + A::iter_prefix_values((4,)).collect::>(), + vec![14, 13] + ); + assert_eq!( + A::iter_prefix_values((3, 30)).collect::>(), + vec![11, 12] + ); + assert_eq!( + A::iter_prefix_values((4, 40)).collect::>(), + vec![14, 13] + ); }); } } diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index d536d76d76b8e..a96ad7d84d551 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -17,15 +17,15 @@ //! Storage value type. Implements StorageValue trait and its method directly. -use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ - storage::{ - StorageAppend, StorageDecodeLength, - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, - }, - traits::{GetDefault, StorageInstance, Get}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; +use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; /// A type that allow to store a value. @@ -34,268 +34,303 @@ use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; /// ```nocompile /// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) /// ``` -pub struct StorageValue( - core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)> +pub struct StorageValue( + core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, ); -impl crate::storage::generator::StorageValue for - StorageValue +impl crate::storage::generator::StorageValue + for StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } impl - StorageValue, QueryKind, OnEmpty> + StorageValue, QueryKind, OnEmpty> where - Prefix: StorageInstance, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + Prefix: StorageInstance, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the value in the storage. - /// - /// Is only available if `Value` of the storage is [`BoundedVec`]. - pub fn try_append(item: EncodeLikeItem) -> Result<(), ()> - where - EncodeLikeItem: EncodeLike, - { - >::try_append(item) - } + /// Try and append the given item to the value in the storage. + /// + /// Is only available if `Value` of the storage is [`BoundedVec`]. + pub fn try_append(item: EncodeLikeItem) -> Result<(), ()> + where + EncodeLikeItem: EncodeLike, + { + >::try_append(item) + } } impl StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key. - pub fn hashed_key() -> [u8; 32] { >::hashed_key() } - - /// Does the value (explicitly) exist in storage? - pub fn exists() -> bool { >::exists() } - - /// Load the value from the provided storage instance. - pub fn get() -> QueryKind::Query { >::get() } - - /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, - /// `Err` if not. - pub fn try_get() -> Result { - >::try_get() - } - - /// Translate a value from some previous type (`O`) to the current type. - /// - /// `f: F` is the translation function. - /// - /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along - /// with the new value if it could. - /// - /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default - /// value of the original type. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade, - /// while ensuring **no usage of this storage are made before the call to - /// `on_runtime_upgrade`**. (More precisely prior initialized modules doesn't make use of this - /// storage). - pub fn translate) -> Option>( - f: F, - ) -> Result, ()> { - >::translate(f) - } - - /// Store a value under this key into the provided storage instance. - pub fn put>(val: Arg) { - >::put(val) - } - - /// Store a value under this key into the provided storage instance. - /// - /// this uses the query type rather than the underlying value. - pub fn set(val: QueryKind::Query) { >::set(val) } - - /// Mutate the value - pub fn mutate R>(f: F) -> R { - >::mutate(f) - } - - /// Mutate the value if closure returns `Ok` - pub fn try_mutate Result>( - f: F, - ) -> Result { - >::try_mutate(f) - } - - /// Clear the storage value. - pub fn kill() { >::kill() } - - /// Take a value from storage, removing it afterwards. - pub fn take() -> QueryKind::Query { >::take() } - - /// Append the given item to the value in the storage. - /// - /// `Value` is required to implement [`StorageAppend`]. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage item will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append(item: EncodeLikeItem) - where - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend - { - >::append(item) - } - - /// Read the length of the storage value without decoding the entire value. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len() -> Option where Value: StorageDecodeLength { - >::decode_len() - } + /// Get the storage key. + pub fn hashed_key() -> [u8; 32] { + >::hashed_key() + } + + /// Does the value (explicitly) exist in storage? + pub fn exists() -> bool { + >::exists() + } + + /// Load the value from the provided storage instance. + pub fn get() -> QueryKind::Query { + >::get() + } + + /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, + /// `Err` if not. + pub fn try_get() -> Result { + >::try_get() + } + + /// Translate a value from some previous type (`O`) to the current type. + /// + /// `f: F` is the translation function. + /// + /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along + /// with the new value if it could. + /// + /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default + /// value of the original type. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade, + /// while ensuring **no usage of this storage are made before the call to + /// `on_runtime_upgrade`**. (More precisely prior initialized modules doesn't make use of this + /// storage). + pub fn translate) -> Option>( + f: F, + ) -> Result, ()> { + >::translate(f) + } + + /// Store a value under this key into the provided storage instance. + pub fn put>(val: Arg) { + >::put(val) + } + + /// Store a value under this key into the provided storage instance. + /// + /// this uses the query type rather than the underlying value. + pub fn set(val: QueryKind::Query) { + >::set(val) + } + + /// Mutate the value + pub fn mutate R>(f: F) -> R { + >::mutate(f) + } + + /// Mutate the value if closure returns `Ok` + pub fn try_mutate Result>( + f: F, + ) -> Result { + >::try_mutate(f) + } + + /// Clear the storage value. + pub fn kill() { + >::kill() + } + + /// Take a value from storage, removing it afterwards. + pub fn take() -> QueryKind::Query { + >::take() + } + + /// Append the given item to the value in the storage. + /// + /// `Value` is required to implement [`StorageAppend`]. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage item will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(item: EncodeLikeItem) + where + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(item) + } + + /// Read the length of the storage value without decoding the entire value. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len() -> Option + where + Value: StorageDecodeLength, + { + >::decode_len() + } } /// Part of storage metadata for storage value. pub trait StorageValueMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; } impl StorageValueMetadata - for StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + for StorageValue +where + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = - DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use sp_io::{TestExternalities, hashing::twox_128}; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { "test" } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = StorageValue; - type AValueQueryWithAnOnEmpty = StorageValue; - type B = StorageValue; - type WithLen = StorageValue>; - - TestExternalities::default().execute_with(|| { - assert_eq!(A::hashed_key().to_vec(), [twox_128(b"test"), twox_128(b"foo")].concat()); - assert_eq!(A::exists(), false); - assert_eq!(A::get(), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(), 97); - assert_eq!(A::try_get(), Err(())); - - A::put(2); - assert_eq!(A::exists(), true); - assert_eq!(A::get(), Some(2)); - assert_eq!(AValueQueryWithAnOnEmpty::get(), 2); - assert_eq!(A::try_get(), Ok(2)); - assert_eq!(A::try_get(), Ok(2)); - - B::put(4); - A::translate::(|v| v.map(Into::into)).unwrap(); - assert_eq!(A::try_get(), Ok(4)); - - A::set(None); - assert_eq!(A::try_get(), Err(())); - - A::set(Some(2)); - assert_eq!(A::try_get(), Ok(2)); - - A::mutate(|v| *v = Some(v.unwrap() * 2)); - assert_eq!(A::try_get(), Ok(4)); - - A::set(Some(4)); - let _: Result<(), ()> = A::try_mutate(|v| { *v = Some(v.unwrap() * 2); Ok(()) }); - assert_eq!(A::try_get(), Ok(8)); - - let _: Result<(), ()> = A::try_mutate(|v| { *v = Some(v.unwrap() * 2); Err(()) }); - assert_eq!(A::try_get(), Ok(8)); - - A::kill(); - AValueQueryWithAnOnEmpty::mutate(|v| *v = *v * 2); - assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); - - AValueQueryWithAnOnEmpty::kill(); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| { - *v = *v * 2; Ok(()) - }); - assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); - - A::kill(); - assert_eq!(A::try_get(), Err(())); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); - assert_eq!(A::NAME, "foo"); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); - - WithLen::kill(); - assert_eq!(WithLen::decode_len(), None); - WithLen::append(3); - assert_eq!(WithLen::decode_len(), Some(1)); - }); - } + use super::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = StorageValue; + type AValueQueryWithAnOnEmpty = StorageValue; + type B = StorageValue; + type WithLen = StorageValue>; + + TestExternalities::default().execute_with(|| { + assert_eq!( + A::hashed_key().to_vec(), + [twox_128(b"test"), twox_128(b"foo")].concat() + ); + assert_eq!(A::exists(), false); + assert_eq!(A::get(), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(), 97); + assert_eq!(A::try_get(), Err(())); + + A::put(2); + assert_eq!(A::exists(), true); + assert_eq!(A::get(), Some(2)); + assert_eq!(AValueQueryWithAnOnEmpty::get(), 2); + assert_eq!(A::try_get(), Ok(2)); + assert_eq!(A::try_get(), Ok(2)); + + B::put(4); + A::translate::(|v| v.map(Into::into)).unwrap(); + assert_eq!(A::try_get(), Ok(4)); + + A::set(None); + assert_eq!(A::try_get(), Err(())); + + A::set(Some(2)); + assert_eq!(A::try_get(), Ok(2)); + + A::mutate(|v| *v = Some(v.unwrap() * 2)); + assert_eq!(A::try_get(), Ok(4)); + + A::set(Some(4)); + let _: Result<(), ()> = A::try_mutate(|v| { + *v = Some(v.unwrap() * 2); + Ok(()) + }); + assert_eq!(A::try_get(), Ok(8)); + + let _: Result<(), ()> = A::try_mutate(|v| { + *v = Some(v.unwrap() * 2); + Err(()) + }); + assert_eq!(A::try_get(), Ok(8)); + + A::kill(); + AValueQueryWithAnOnEmpty::mutate(|v| *v = *v * 2); + assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); + + AValueQueryWithAnOnEmpty::kill(); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); + + A::kill(); + assert_eq!(A::try_get(), Err(())); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::NAME, "foo"); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + + WithLen::kill(); + assert_eq!(WithLen::decode_len(), None); + WithLen::append(3); + assert_eq!(WithLen::decode_len(), Some(1)); + }); + } } From 69fbed340b80f8f964ef025b5ee0ee503502593d Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 16:29:13 -0700 Subject: [PATCH 11/34] Refactor crate imports in decl_storage macros --- .../src/storage/genesis_config/builder_def.rs | 2 +- .../src/storage/genesis_config/mod.rs | 6 +-- .../support/procedural/src/storage/getters.rs | 5 +- .../procedural/src/storage/instance_trait.rs | 3 +- .../procedural/src/storage/metadata.rs | 3 +- frame/support/procedural/src/storage/mod.rs | 53 ++++++++++--------- .../src/storage/print_pallet_upgrade.rs | 2 +- .../procedural/src/storage/storage_struct.rs | 3 +- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index 8fb15bf04d343..a2a4f1ff15f65 100644 --- a/frame/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/builder_def.rs @@ -121,7 +121,7 @@ impl BuilderDef { }} }, StorageLineTypeDef::NMap(map) => { - let keygen = map.to_keygen_struct(); + let keygen = map.to_keygen_struct(scrate); let key_tuple = map.to_key_tuple(); let key_arg = if map.keys.len() == 1 { quote!((k,)) diff --git a/frame/support/procedural/src/storage/genesis_config/mod.rs b/frame/support/procedural/src/storage/genesis_config/mod.rs index 6dfa5a13fe5b2..abc7af729f064 100644 --- a/frame/support/procedural/src/storage/genesis_config/mod.rs +++ b/frame/support/procedural/src/storage/genesis_config/mod.rs @@ -177,10 +177,8 @@ fn impl_build_storage( } } -pub fn genesis_config_and_build_storage( - scrate: &TokenStream, - def: &DeclStorageDefExt, -) -> TokenStream { +pub fn genesis_config_and_build_storage(def: &DeclStorageDefExt) -> TokenStream { + let scrate = &def.hidden_crate; let builders = BuilderDef::from_def(scrate, def); if !builders.blocks.is_empty() { let genesis_config = match GenesisConfigDef::from_def(def) { diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 0c51ab4c71ed7..8b27af51226db 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -21,7 +21,8 @@ use proc_macro2::TokenStream; use quote::quote; use super::{DeclStorageDefExt, StorageLineTypeDef}; -pub fn impl_getters(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { +pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { + let scrate = &def.hidden_crate; let mut getters = TokenStream::new(); for (get_fn, line) in def.storage_lines.iter() @@ -66,7 +67,7 @@ pub fn impl_getters(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStrea } }, StorageLineTypeDef::NMap(map) => { - let keygen = map.to_keygen_struct(); + let keygen = map.to_keygen_struct(&def.hidden_crate); let value = &map.value; let key_arg = if map.keys.len() == 1 { quote!((key,)) diff --git a/frame/support/procedural/src/storage/instance_trait.rs b/frame/support/procedural/src/storage/instance_trait.rs index a9e06c6299041..55f6ef478054c 100644 --- a/frame/support/procedural/src/storage/instance_trait.rs +++ b/frame/support/procedural/src/storage/instance_trait.rs @@ -34,7 +34,8 @@ struct InstanceDef { index: u8, } -pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { +pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { + let scrate = &def.hidden_crate; let mut impls = TokenStream::new(); impls.extend(reexport_instance_trait(scrate, def)); diff --git a/frame/support/procedural/src/storage/metadata.rs b/frame/support/procedural/src/storage/metadata.rs index ac38892bedb18..8a42dd4308d12 100644 --- a/frame/support/procedural/src/storage/metadata.rs +++ b/frame/support/procedural/src/storage/metadata.rs @@ -161,7 +161,8 @@ fn default_byte_getter( (struct_def, struct_instance) } -pub fn impl_metadata(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { +pub fn impl_metadata(def: &DeclStorageDefExt) -> TokenStream { + let scrate = &def.hidden_crate; let mut entries = TokenStream::new(); let mut default_byte_getter_struct_defs = TokenStream::new(); diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index d780366a156a8..9c27affae9a75 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -70,7 +70,9 @@ impl syn::parse::Parse for DeclStorageDef { /// Extended version of `DeclStorageDef` with useful precomputed value. pub struct DeclStorageDefExt { /// Name of the module used to import hidden imports. - hidden_crate: Option, + hidden_crate: proc_macro2::TokenStream, + /// Hidden imports used by the module. + hidden_imports: proc_macro2::TokenStream, /// Visibility of store trait. visibility: syn::Visibility, /// Name of store trait: usually `Store`. @@ -108,9 +110,15 @@ pub struct DeclStorageDefExt { impl From for DeclStorageDefExt { fn from(mut def: DeclStorageDef) -> Self { + let hidden_crate_name = def.hidden_crate.as_ref().map(|i| i.to_string()) + .unwrap_or_else(|| "decl_storage".to_string()); + + let hidden_crate = generate_crate_access(&hidden_crate_name, "frame-support"); + let hidden_imports = generate_hidden_includes(&hidden_crate_name, "frame-support"); + let storage_lines = def.storage_lines.drain(..).collect::>(); let storage_lines = storage_lines.into_iter() - .map(|line| StorageLineDefExt::from_def(line, &def)) + .map(|line| StorageLineDefExt::from_def(line, &def, &hidden_crate)) .collect(); let ( @@ -144,7 +152,8 @@ impl From for DeclStorageDefExt { ); Self { - hidden_crate: def.hidden_crate, + hidden_crate, + hidden_imports, visibility: def.visibility, store_trait: def.store_trait, module_name: def.module_name, @@ -230,7 +239,11 @@ pub struct StorageLineDefExt { } impl StorageLineDefExt { - fn from_def(storage_def: StorageLineDef, def: &DeclStorageDef) -> Self { + fn from_def( + storage_def: StorageLineDef, + def: &DeclStorageDef, + hidden_crate: &proc_macro2::TokenStream, + ) -> Self { let is_generic = match &storage_def.storage_type { StorageLineTypeDef::Simple(value) => { ext::type_contains_ident(&value, &def.module_runtime_generic) @@ -301,7 +314,7 @@ impl StorageLineDefExt { quote!( StorageDoubleMap<#key1, #key2, #value_type> ) }, StorageLineTypeDef::NMap(map) => { - let keygen = map.to_keygen_struct(); + let keygen = map.to_keygen_struct(hidden_crate); quote!( StorageNMap<#keygen, #value_type> ) } }; @@ -368,10 +381,10 @@ pub struct NMapDef { } impl NMapDef { - fn to_keygen_struct(&self) -> proc_macro2::TokenStream { + fn to_keygen_struct(&self, scrate: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { let key_hasher = self.keys.iter().zip(&self.hashers).map(|(key, hasher)| { let hasher = hasher.to_storage_hasher_struct(); - quote!( Key<#hasher, #key> ) + quote!( Key<#scrate::#hasher, #key> ) }) .collect::>(); quote!(( #(#key_hasher,)* )) @@ -442,18 +455,14 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr print_pallet_upgrade::maybe_print_pallet_upgrade(&def_ext); - let hidden_crate_name = def_ext.hidden_crate.as_ref().map(|i| i.to_string()) - .unwrap_or_else(|| "decl_storage".to_string()); - - let scrate = generate_crate_access(&hidden_crate_name, "frame-support"); - let scrate_decl = generate_hidden_includes(&hidden_crate_name, "frame-support"); - + let scrate = &def_ext.hidden_crate; + let scrate_decl = &def_ext.hidden_imports; let store_trait = store_trait::decl_and_impl(&def_ext); - let getters = getters::impl_getters(&scrate, &def_ext); - let metadata = metadata::impl_metadata(&scrate, &def_ext); - let instance_trait = instance_trait::decl_and_impl(&scrate, &def_ext); - let genesis_config = genesis_config::genesis_config_and_build_storage(&scrate, &def_ext); - let storage_struct = storage_struct::decl_and_impl(&scrate, &def_ext); + let getters = getters::impl_getters(&def_ext); + let metadata = metadata::impl_metadata(&def_ext); + let instance_trait = instance_trait::decl_and_impl(&def_ext); + let genesis_config = genesis_config::genesis_config_and_build_storage(&def_ext); + let storage_struct = storage_struct::decl_and_impl(&def_ext); quote!( use #scrate::{ @@ -465,15 +474,7 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr IterableStorageMap as _, IterableStorageNMap as _, IterableStorageDoubleMap as _, - storage::types::Key, - Blake2_256, - Blake2_128, - Blake2_128Concat, - Twox256, - Twox128, - Twox64Concat, - Identity, }; #scrate_decl diff --git a/frame/support/procedural/src/storage/print_pallet_upgrade.rs b/frame/support/procedural/src/storage/print_pallet_upgrade.rs index ddfdca1b31339..a6f64a588b633 100644 --- a/frame/support/procedural/src/storage/print_pallet_upgrade.rs +++ b/frame/support/procedural/src/storage/print_pallet_upgrade.rs @@ -242,7 +242,7 @@ pub fn maybe_print_pallet_upgrade(def: &super::DeclStorageDefExt) { StorageLineTypeDef::NMap(map) => { format!("StorageNMap<_, {keygen}, {value_type}{comma_query_kind}\ {comma_default_value_getter_name}>", - keygen = map.to_keygen_struct(), + keygen = map.to_keygen_struct(&def.hidden_crate), value_type = to_cleaned_string(&value_type), comma_query_kind = comma_query_kind, comma_default_value_getter_name = comma_default_value_getter_name, diff --git a/frame/support/procedural/src/storage/storage_struct.rs b/frame/support/procedural/src/storage/storage_struct.rs index dfcc4eb2d5490..51b55bdc4f139 100644 --- a/frame/support/procedural/src/storage/storage_struct.rs +++ b/frame/support/procedural/src/storage/storage_struct.rs @@ -47,7 +47,8 @@ fn from_query_to_optional_value(is_option: bool) -> TokenStream { } } -pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { +pub fn decl_and_impl(def: &DeclStorageDefExt) -> TokenStream { + let scrate = &def.hidden_crate; let mut impls = TokenStream::new(); for line in &def.storage_lines { From d5598e569f00d6165582329e8027274cece8e79b Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 16:46:50 -0700 Subject: [PATCH 12/34] Some more line char reductions and doc comment update --- frame/support/src/storage/generator/nmap.rs | 17 +++++++++-------- frame/support/src/storage/mod.rs | 17 +++++++++++++---- frame/support/src/storage/types/nmap.rs | 20 +++++++++++--------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 03d4849656aea..4eee7a2c7417d 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -168,10 +168,11 @@ where } } - fn insert + TupleToEncodedIter, VArg: EncodeLike>( - key: KArg, - val: VArg, - ) { + fn insert(key: KArg, val: VArg) + where + KArg: EncodeLike + TupleToEncodedIter, + VArg: EncodeLike, + { unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); } @@ -264,10 +265,10 @@ where sp_io::storage::append(&final_key, item.encode()); } - fn migrate_keys + TupleToEncodedIter>( - key: KArg, - hash_fns: K::HArg, - ) -> Option { + fn migrate_keys(key: KArg, hash_fns: K::HArg) -> Option + where + KArg: EncodeLike + TupleToEncodedIter, + { let old_key = { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 6b64527c58f85..24ad4a90a288c 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -22,7 +22,10 @@ use sp_std::prelude::*; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, - storage::types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator, TupleToEncodedIter}, + storage::types::{ + HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator, + TupleToEncodedIter, + }, traits::Get, }; use sp_runtime::generic::{Digest, DigestItem}; @@ -362,7 +365,8 @@ pub trait IterableStorageDoubleMap< fn translate Option>(f: F); } -/// A strongly-typed map with arbitrary number of keys in storage whose keys and values can be iterated over. +/// A strongly-typed map with arbitrary number of keys in storage whose keys and values can be +/// iterated over. pub trait IterableStorageNMap: StorageNMap { /// The type that iterates over all `(key1, (key2, (key3, ... (keyN, ()))), value)` tuples type Iterator: Iterator; @@ -574,7 +578,10 @@ pub trait StorageNMap { KArg2: EncodeLike + TupleToEncodedIter; /// Store a value to be associated with the given key from the map. - fn insert + TupleToEncodedIter, VArg: EncodeLike>(key: KArg, val: VArg); + fn insert(key: KArg, val: VArg) + where + KArg: EncodeLike + TupleToEncodedIter, + VArg: EncodeLike; /// Remove the value under a key. fn remove + TupleToEncodedIter>(key: KArg); @@ -652,7 +659,9 @@ pub trait StorageNMap { /// Migrate an item with the given `key` from defunct `hash_fns` to the current hashers. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - fn migrate_keys + TupleToEncodedIter>(key: KArg, hash_fns: K::HArg) -> Option; + fn migrate_keys(key: KArg, hash_fns: K::HArg) -> Option + where + KArg: EncodeLike + TupleToEncodedIter; } /// Iterate over a prefix and decode raw_key and raw_value into `T`. diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 8e6b5792198c6..27542ba7d5f1f 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -29,7 +29,8 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::prelude::*; -/// A type that allow to store values for an arbitrary number of keys in the form of `(key1, (key2, (..., (keyN, ()))))`. +/// A type that allow to store values for an arbitrary number of keys in the form of +/// `(Key, Key, ..., Key)`. /// /// Each value is stored at: /// ```nocompile @@ -139,10 +140,11 @@ where } /// Store a value to be associated with the given keys from the map. - pub fn insert + TupleToEncodedIter, VArg: EncodeLike>( - key: KArg, - val: VArg, - ) { + pub fn insert(key: KArg, val: VArg) + where + KArg: EncodeLike + TupleToEncodedIter, + VArg: EncodeLike, + { >::insert(key, val) } @@ -244,10 +246,10 @@ where /// Migrate an item with the given `key` from defunct `hash_fns` to the current hashers. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_keys + TupleToEncodedIter>( - key: KArg, - hash_fns: Key::HArg, - ) -> Option { + pub fn migrate_keys(key: KArg, hash_fns: Key::HArg) -> Option + where + KArg: EncodeLike + TupleToEncodedIter + { >::migrate_keys::<_>(key, hash_fns) } From bbf84591a7ec1f514d65c903a1dec3192aa36081 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 16:49:01 -0700 Subject: [PATCH 13/34] Update UI test expectations --- .../test/tests/pallet_ui/storage_not_storage_type.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr index ec4bde22ac7a8..73fda60942475 100644 --- a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr +++ b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `StorageDoubleMap` in order to expand metadata, found `u8` +error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8` --> $DIR/storage_not_storage_type.rs:19:16 | 19 | type Foo = u8; From 9fbf1ad5e82be3b8636f5581b6bf39f6bc133a4c Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 23 Apr 2021 18:07:34 -0700 Subject: [PATCH 14/34] Revert whitespace changes to untouched files --- frame/support/src/storage/types/double_map.rs | 1286 ++++++++--------- frame/support/src/storage/types/map.rs | 896 ++++++------ frame/support/src/storage/types/value.rs | 552 +++---- 3 files changed, 1367 insertions(+), 1367 deletions(-) diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index fc256f2b4e3b6..0b6292b3fcb3d 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -19,12 +19,12 @@ //! StoragePrefixedDoubleMap traits and their methods directly. use crate::{ - storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, - StorageAppend, StorageDecodeLength, - }, - traits::{Get, GetDefault, StorageInstance}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; @@ -47,688 +47,688 @@ use sp_std::vec::Vec; /// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values /// in storage can be compromised. pub struct StorageDoubleMap< - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - Value, - QueryKind = OptionQuery, - OnEmpty = GetDefault, + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind = OptionQuery, + OnEmpty = GetDefault, >( - core::marker::PhantomData<( - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - Value, - QueryKind, - OnEmpty, - )>, + core::marker::PhantomData<( + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + Value, + QueryKind, + OnEmpty, + )>, ); impl - crate::storage::generator::StorageDoubleMap - for StorageDoubleMap + crate::storage::generator::StorageDoubleMap + for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - type Hasher1 = Hasher1; - type Hasher2 = Hasher2; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + type Hasher1 = Hasher1; + type Hasher2 = Hasher2; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } impl - crate::storage::StoragePrefixedMap - for StorageDoubleMap + crate::storage::StoragePrefixedMap + for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() - } - fn storage_prefix() -> &'static [u8] { - >::storage_prefix() - } + fn module_prefix() -> &'static [u8] { + >::module_prefix() + } + fn storage_prefix() -> &'static [u8] { + >::storage_prefix() + } } impl - StorageDoubleMap< - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - BoundedVec, - QueryKind, - OnEmpty, - > + StorageDoubleMap< + Prefix, + Hasher1, + Key1, + Hasher2, + Key2, + BoundedVec, + QueryKind, + OnEmpty, + > where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the double map in the storage. - /// - /// Is only available if `Value` of the map is [`BoundedVec`]. - pub fn try_append( - key1: EncodeLikeKey1, - key2: EncodeLikeKey2, - item: EncodeLikeItem, - ) -> Result<(), ()> - where - EncodeLikeKey1: EncodeLike + Clone, - EncodeLikeKey2: EncodeLike + Clone, - EncodeLikeItem: EncodeLike, - { - < + /// Try and append the given item to the double map in the storage. + /// + /// Is only available if `Value` of the map is [`BoundedVec`]. + pub fn try_append( + key1: EncodeLikeKey1, + key2: EncodeLikeKey2, + item: EncodeLikeItem, + ) -> Result<(), ()> + where + EncodeLikeKey1: EncodeLike + Clone, + EncodeLikeKey2: EncodeLike + Clone, + EncodeLikeItem: EncodeLike, + { + < Self as crate::storage::bounded_vec::TryAppendDoubleMap >::try_append( key1, key2, item, ) - } + } } impl - StorageDoubleMap + StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::hashed_key_for(k1, k2) - } - - /// Does the value (explicitly) exist in storage? - pub fn contains_key(k1: KArg1, k2: KArg2) -> bool - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::contains_key(k1, k2) - } - - /// Load the value associated with the given key from the double map. - pub fn get(k1: KArg1, k2: KArg2) -> QueryKind::Query - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::get(k1, k2) - } - - /// Try to get the value for the given key from the double map. - /// - /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get(k1: KArg1, k2: KArg2) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::try_get(k1, k2) - } - - /// Take a value from storage, removing it afterwards. - pub fn take(k1: KArg1, k2: KArg2) -> QueryKind::Query - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::take(k1, k2) - } - - /// Swap the values of two key-pairs. - pub fn swap( - x_k1: XKArg1, - x_k2: XKArg2, - y_k1: YKArg1, - y_k2: YKArg2, - ) where - XKArg1: EncodeLike, - XKArg2: EncodeLike, - YKArg1: EncodeLike, - YKArg2: EncodeLike, - { - >::swap(x_k1, x_k2, y_k1, y_k2) - } - - /// Store a value to be associated with the given keys from the double map. - pub fn insert(k1: KArg1, k2: KArg2, val: VArg) - where - KArg1: EncodeLike, - KArg2: EncodeLike, - VArg: EncodeLike, - { - >::insert(k1, k2, val) - } - - /// Remove the value under the given keys. - pub fn remove(k1: KArg1, k2: KArg2) - where - KArg1: EncodeLike, - KArg2: EncodeLike, - { - >::remove(k1, k2) - } - - /// Remove all values under the first key. - pub fn remove_prefix(k1: KArg1) - where - KArg1: ?Sized + EncodeLike, - { - >::remove_prefix(k1) - } - - /// Iterate over values that share the first key. - pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator - where - KArg1: ?Sized + EncodeLike, - { - >::iter_prefix_values(k1) - } - - /// Mutate the value under the given keys. - pub fn mutate(k1: KArg1, k2: KArg2, f: F) -> R - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> R, - { - >::mutate(k1, k2, f) - } - - /// Mutate the value under the given keys when the closure returns `Ok`. - pub fn try_mutate(k1: KArg1, k2: KArg2, f: F) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> Result, - { - >::try_mutate(k1, k2, f) - } - - /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. - pub fn mutate_exists(k1: KArg1, k2: KArg2, f: F) -> R - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut Option) -> R, - { - >::mutate_exists(k1, k2, f) - } - - /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result - where - KArg1: EncodeLike, - KArg2: EncodeLike, - F: FnOnce(&mut Option) -> Result, - { - >::try_mutate_exists(k1, k2, f) - } - - /// Append the given item to the value in the storage. - /// - /// `Value` is required to implement [`StorageAppend`]. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append(k1: KArg1, k2: KArg2, item: EncodeLikeItem) - where - KArg1: EncodeLike, - KArg2: EncodeLike, - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend, - { - >::append(k1, k2, item) - } - - /// Read the length of the storage value without decoding the entire value under the - /// given `key1` and `key2`. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len(key1: KArg1, key2: KArg2) -> Option - where - KArg1: EncodeLike, - KArg2: EncodeLike, - Value: StorageDecodeLength, - { - >::decode_len(key1, key2) - } - - /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and - /// `OldHasher2` to the current hashers. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_keys< - OldHasher1: crate::StorageHasher, - OldHasher2: crate::StorageHasher, - KeyArg1: EncodeLike, - KeyArg2: EncodeLike, - >( - key1: KeyArg1, - key2: KeyArg2, - ) -> Option { - >::migrate_keys::< - OldHasher1, - OldHasher2, - _, - _, - >(key1, key2) - } - - /// Remove all value of the storage. - pub fn remove_all() { - >::remove_all() - } - - /// Iter over all value of the storage. - /// - /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. - pub fn iter_values() -> crate::storage::PrefixIterator { - >::iter_values() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade. - pub fn translate_values Option>(f: F) { - >::translate_values(f) - } + /// Get the storage key used to fetch a value corresponding to a specific key. + pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::hashed_key_for(k1, k2) + } + + /// Does the value (explicitly) exist in storage? + pub fn contains_key(k1: KArg1, k2: KArg2) -> bool + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::contains_key(k1, k2) + } + + /// Load the value associated with the given key from the double map. + pub fn get(k1: KArg1, k2: KArg2) -> QueryKind::Query + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::get(k1, k2) + } + + /// Try to get the value for the given key from the double map. + /// + /// Returns `Ok` if it exists, `Err` if not. + pub fn try_get(k1: KArg1, k2: KArg2) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::try_get(k1, k2) + } + + /// Take a value from storage, removing it afterwards. + pub fn take(k1: KArg1, k2: KArg2) -> QueryKind::Query + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::take(k1, k2) + } + + /// Swap the values of two key-pairs. + pub fn swap( + x_k1: XKArg1, + x_k2: XKArg2, + y_k1: YKArg1, + y_k2: YKArg2, + ) where + XKArg1: EncodeLike, + XKArg2: EncodeLike, + YKArg1: EncodeLike, + YKArg2: EncodeLike, + { + >::swap(x_k1, x_k2, y_k1, y_k2) + } + + /// Store a value to be associated with the given keys from the double map. + pub fn insert(k1: KArg1, k2: KArg2, val: VArg) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + VArg: EncodeLike, + { + >::insert(k1, k2, val) + } + + /// Remove the value under the given keys. + pub fn remove(k1: KArg1, k2: KArg2) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + { + >::remove(k1, k2) + } + + /// Remove all values under the first key. + pub fn remove_prefix(k1: KArg1) + where + KArg1: ?Sized + EncodeLike, + { + >::remove_prefix(k1) + } + + /// Iterate over values that share the first key. + pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator + where + KArg1: ?Sized + EncodeLike, + { + >::iter_prefix_values(k1) + } + + /// Mutate the value under the given keys. + pub fn mutate(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> R, + { + >::mutate(k1, k2, f) + } + + /// Mutate the value under the given keys when the closure returns `Ok`. + pub fn try_mutate(k1: KArg1, k2: KArg2, f: F) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> Result, + { + >::try_mutate(k1, k2, f) + } + + /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. + pub fn mutate_exists(k1: KArg1, k2: KArg2, f: F) -> R + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut Option) -> R, + { + >::mutate_exists(k1, k2, f) + } + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists(k1: KArg1, k2: KArg2, f: F) -> Result + where + KArg1: EncodeLike, + KArg2: EncodeLike, + F: FnOnce(&mut Option) -> Result, + { + >::try_mutate_exists(k1, k2, f) + } + + /// Append the given item to the value in the storage. + /// + /// `Value` is required to implement [`StorageAppend`]. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(k1: KArg1, k2: KArg2, item: EncodeLikeItem) + where + KArg1: EncodeLike, + KArg2: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(k1, k2, item) + } + + /// Read the length of the storage value without decoding the entire value under the + /// given `key1` and `key2`. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len(key1: KArg1, key2: KArg2) -> Option + where + KArg1: EncodeLike, + KArg2: EncodeLike, + Value: StorageDecodeLength, + { + >::decode_len(key1, key2) + } + + /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and + /// `OldHasher2` to the current hashers. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_keys< + OldHasher1: crate::StorageHasher, + OldHasher2: crate::StorageHasher, + KeyArg1: EncodeLike, + KeyArg2: EncodeLike, + >( + key1: KeyArg1, + key2: KeyArg2, + ) -> Option { + >::migrate_keys::< + OldHasher1, + OldHasher2, + _, + _, + >(key1, key2) + } + + /// Remove all value of the storage. + pub fn remove_all() { + >::remove_all() + } + + /// Iter over all value of the storage. + /// + /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. + pub fn iter_values() -> crate::storage::PrefixIterator { + >::iter_values() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade. + pub fn translate_values Option>(f: F) { + >::translate_values(f) + } } impl - StorageDoubleMap + StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Hasher2: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Hasher2: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Enumerate all elements in the map with first key `k1` in no particular order. - /// - /// If you add or remove values whose first key is `k1` to the map while doing this, you'll get - /// undefined results. - pub fn iter_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { - >::iter_prefix(k1) - } - - /// Remove all elements from the map with first key `k1` and iterate through them in no - /// particular order. - /// - /// If you add elements with first key `k1` to the map while doing this, you'll get undefined - /// results. - pub fn drain_prefix( - k1: impl EncodeLike, - ) -> crate::storage::PrefixIterator<(Key2, Value)> { - >::drain_prefix(k1) - } - - /// Enumerate all elements in the map in no particular order. - /// - /// If you add or remove values to the map while doing this, you'll get undefined results. - pub fn iter() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { - >::iter() - } - - /// Remove all elements from the map and iterate through them in no particular order. - /// - /// If you add elements to the map while doing this, you'll get undefined results. - pub fn drain() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { - >::drain() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - pub fn translate Option>(f: F) { - >::translate(f) - } + /// Enumerate all elements in the map with first key `k1` in no particular order. + /// + /// If you add or remove values whose first key is `k1` to the map while doing this, you'll get + /// undefined results. + pub fn iter_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { + >::iter_prefix(k1) + } + + /// Remove all elements from the map with first key `k1` and iterate through them in no + /// particular order. + /// + /// If you add elements with first key `k1` to the map while doing this, you'll get undefined + /// results. + pub fn drain_prefix( + k1: impl EncodeLike, + ) -> crate::storage::PrefixIterator<(Key2, Value)> { + >::drain_prefix(k1) + } + + /// Enumerate all elements in the map in no particular order. + /// + /// If you add or remove values to the map while doing this, you'll get undefined results. + pub fn iter() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { + >::iter() + } + + /// Remove all elements from the map and iterate through them in no particular order. + /// + /// If you add elements to the map while doing this, you'll get undefined results. + pub fn drain() -> crate::storage::PrefixIterator<(Key1, Key2, Value)> { + >::drain() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + pub fn translate Option>(f: F) { + >::translate(f) + } } /// Part of storage metadata for a storage double map. /// /// NOTE: Generic hashers is supported. pub trait StorageDoubleMapMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; - const HASHER1: frame_metadata::StorageHasher; - const HASHER2: frame_metadata::StorageHasher; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; + const HASHER1: frame_metadata::StorageHasher; + const HASHER2: frame_metadata::StorageHasher; } impl StorageDoubleMapMetadata - for StorageDoubleMap + for StorageDoubleMap where - Prefix: StorageInstance, - Hasher1: crate::hash::StorageHasher, - Hasher2: crate::hash::StorageHasher, - Key1: FullCodec, - Key2: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher1: crate::hash::StorageHasher, + Hasher2: crate::hash::StorageHasher, + Key1: FullCodec, + Key2: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; - const HASHER2: frame_metadata::StorageHasher = Hasher2::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; + const HASHER2: frame_metadata::StorageHasher = Hasher2::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use crate::hash::*; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = - StorageDoubleMap; - type AValueQueryWithAnOnEmpty = StorageDoubleMap< - Prefix, - Blake2_128Concat, - u16, - Twox64Concat, - u8, - u32, - ValueQuery, - ADefault, - >; - type B = StorageDoubleMap; - type C = StorageDoubleMap; - type WithLen = StorageDoubleMap>; - - TestExternalities::default().execute_with(|| { - let mut k: Vec = vec![]; - k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"foo")); - k.extend(&3u16.blake2_128_concat()); - k.extend(&30u8.twox_64_concat()); - assert_eq!(A::hashed_key_for(3, 30).to_vec(), k); - - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::get(3, 30), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); - - A::insert(3, 30, 10); - assert_eq!(A::contains_key(3, 30), true); - assert_eq!(A::get(3, 30), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 10); - - A::swap(3, 30, 2, 20); - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(3, 30), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); - assert_eq!(A::get(2, 20), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(2, 20), 10); - - A::remove(2, 20); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(A::get(2, 20), None); - - AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(97 * 4)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Ok(()) - }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(97 * 4)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Err(()) - }); - assert_eq!(A::contains_key(2, 20), false); - - A::remove(2, 20); - AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { - assert!(v.is_none()); - *v = Some(10); - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - - A::remove(2, 20); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - assert!(v.is_none()); - *v = Some(10); - Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - Ok(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - assert_eq!(A::try_get(2, 20), Ok(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { - *v = Some(v.unwrap() * 10); - Err(()) - }); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(100)); - - A::insert(2, 20, 10); - assert_eq!(A::take(2, 20), Some(10)); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(AValueQueryWithAnOnEmpty::take(2, 20), 97); - assert_eq!(A::contains_key(2, 20), false); - assert_eq!(A::try_get(2, 20), Err(())); - - B::insert(2, 20, 10); - assert_eq!( - A::migrate_keys::(2, 20), - Some(10) - ); - assert_eq!(A::contains_key(2, 20), true); - assert_eq!(A::get(2, 20), Some(10)); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - A::remove_all(); - assert_eq!(A::contains_key(3, 30), false); - assert_eq!(A::contains_key(4, 40), false); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - - C::insert(3, 30, 10); - C::insert(4, 40, 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 20), (3, 30, 20)] - ); - - A::insert(3, 30, 10); - A::insert(4, 40, 10); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 10), (3, 30, 10)] - ); - assert_eq!( - A::drain().collect::>(), - vec![(4, 40, 10), (3, 30, 10)] - ); - assert_eq!(A::iter().collect::>(), vec![]); - - C::insert(3, 30, 10); - C::insert(4, 40, 10); - A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 1600), (3, 30, 900)] - ); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); - assert_eq!(A::HASHER1, frame_metadata::StorageHasher::Blake2_128Concat); - assert_eq!(A::HASHER2, frame_metadata::StorageHasher::Twox64Concat); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER1, - frame_metadata::StorageHasher::Blake2_128Concat - ); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER2, - frame_metadata::StorageHasher::Twox64Concat - ); - assert_eq!(A::NAME, "foo"); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - - WithLen::remove_all(); - assert_eq!(WithLen::decode_len(3, 30), None); - WithLen::append(0, 100, 10); - assert_eq!(WithLen::decode_len(0, 100), Some(1)); - - A::insert(3, 30, 11); - A::insert(3, 31, 12); - A::insert(4, 40, 13); - A::insert(4, 41, 14); - assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); - assert_eq!( - A::iter_prefix(3).collect::>(), - vec![(31, 12), (30, 11)] - ); - assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); - assert_eq!( - A::iter_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); - - A::remove_prefix(3); - assert_eq!(A::iter_prefix(3).collect::>(), vec![]); - assert_eq!( - A::iter_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); - - assert_eq!( - A::drain_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); - assert_eq!(A::iter_prefix(4).collect::>(), vec![]); - assert_eq!(A::drain_prefix(4).collect::>(), vec![]); - }) - } + use super::*; + use crate::hash::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = + StorageDoubleMap; + type AValueQueryWithAnOnEmpty = StorageDoubleMap< + Prefix, + Blake2_128Concat, + u16, + Twox64Concat, + u8, + u32, + ValueQuery, + ADefault, + >; + type B = StorageDoubleMap; + type C = StorageDoubleMap; + type WithLen = StorageDoubleMap>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + k.extend(&30u8.twox_64_concat()); + assert_eq!(A::hashed_key_for(3, 30).to_vec(), k); + + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::get(3, 30), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); + + A::insert(3, 30, 10); + assert_eq!(A::contains_key(3, 30), true); + assert_eq!(A::get(3, 30), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 10); + + A::swap(3, 30, 2, 20); + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(3, 30), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3, 30), 97); + assert_eq!(A::get(2, 20), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(2, 20), 10); + + A::remove(2, 20); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(A::get(2, 20), None); + + AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate(2, 20, |v| *v = *v * 2); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(97 * 4)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Ok(()) + }); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(97 * 4)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { + *v = *v * 2; + Err(()) + }); + assert_eq!(A::contains_key(2, 20), false); + + A::remove(2, 20); + AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + + A::remove(2, 20); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + assert_eq!(A::try_get(2, 20), Ok(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, 20, |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(100)); + + A::insert(2, 20, 10); + assert_eq!(A::take(2, 20), Some(10)); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(AValueQueryWithAnOnEmpty::take(2, 20), 97); + assert_eq!(A::contains_key(2, 20), false); + assert_eq!(A::try_get(2, 20), Err(())); + + B::insert(2, 20, 10); + assert_eq!( + A::migrate_keys::(2, 20), + Some(10) + ); + assert_eq!(A::contains_key(2, 20), true); + assert_eq!(A::get(2, 20), Some(10)); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + A::remove_all(); + assert_eq!(A::contains_key(3, 30), false); + assert_eq!(A::contains_key(4, 40), false); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert(3, 30, 10); + C::insert(4, 40, 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 20), (3, 30, 20)] + ); + + A::insert(3, 30, 10); + A::insert(4, 40, 10); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 10), (3, 30, 10)] + ); + assert_eq!( + A::drain().collect::>(), + vec![(4, 40, 10), (3, 30, 10)] + ); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert(3, 30, 10); + C::insert(4, 40, 10); + A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!( + A::iter().collect::>(), + vec![(4, 40, 1600), (3, 30, 900)] + ); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::HASHER1, frame_metadata::StorageHasher::Blake2_128Concat); + assert_eq!(A::HASHER2, frame_metadata::StorageHasher::Twox64Concat); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER1, + frame_metadata::StorageHasher::Blake2_128Concat + ); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER2, + frame_metadata::StorageHasher::Twox64Concat + ); + assert_eq!(A::NAME, "foo"); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len(3, 30), None); + WithLen::append(0, 100, 10); + assert_eq!(WithLen::decode_len(0, 100), Some(1)); + + A::insert(3, 30, 11); + A::insert(3, 31, 12); + A::insert(4, 40, 13); + A::insert(4, 41, 14); + assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); + assert_eq!( + A::iter_prefix(3).collect::>(), + vec![(31, 12), (30, 11)] + ); + assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); + assert_eq!( + A::iter_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + + A::remove_prefix(3); + assert_eq!(A::iter_prefix(3).collect::>(), vec![]); + assert_eq!( + A::iter_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + + assert_eq!( + A::drain_prefix(4).collect::>(), + vec![(40, 13), (41, 14)] + ); + assert_eq!(A::iter_prefix(4).collect::>(), vec![]); + assert_eq!(A::drain_prefix(4).collect::>(), vec![]); + }) + } } diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index e01a4b14f2920..dc8e3324dffa2 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -19,12 +19,12 @@ //! methods directly. use crate::{ - storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, - StorageAppend, StorageDecodeLength, - }, - traits::{Get, GetDefault, StorageInstance}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; @@ -44,486 +44,486 @@ use sp_std::prelude::*; /// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as /// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised. pub struct StorageMap( - core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>, + core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>, ); impl - crate::storage::generator::StorageMap - for StorageMap + crate::storage::generator::StorageMap + for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - type Hasher = Hasher; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + type Hasher = Hasher; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } impl crate::storage::StoragePrefixedMap - for StorageMap + for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - fn module_prefix() -> &'static [u8] { - >::module_prefix() - } - fn storage_prefix() -> &'static [u8] { - >::storage_prefix() - } + fn module_prefix() -> &'static [u8] { + >::module_prefix() + } + fn storage_prefix() -> &'static [u8] { + >::storage_prefix() + } } impl - StorageMap, QueryKind, OnEmpty> + StorageMap, QueryKind, OnEmpty> where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the map in the storage. - /// - /// Is only available if `Value` of the map is [`BoundedVec`]. - pub fn try_append( - key: EncodeLikeKey, - item: EncodeLikeItem, - ) -> Result<(), ()> - where - EncodeLikeKey: EncodeLike + Clone, - EncodeLikeItem: EncodeLike, - { - >::try_append( - key, item, - ) - } + /// Try and append the given item to the map in the storage. + /// + /// Is only available if `Value` of the map is [`BoundedVec`]. + pub fn try_append( + key: EncodeLikeKey, + item: EncodeLikeItem, + ) -> Result<(), ()> + where + EncodeLikeKey: EncodeLike + Clone, + EncodeLikeItem: EncodeLike, + { + >::try_append( + key, item, + ) + } } impl - StorageMap + StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for>(key: KeyArg) -> Vec { - >::hashed_key_for(key) - } - - /// Does the value (explicitly) exist in storage? - pub fn contains_key>(key: KeyArg) -> bool { - >::contains_key(key) - } - - /// Load the value associated with the given key from the map. - pub fn get>(key: KeyArg) -> QueryKind::Query { - >::get(key) - } - - /// Try to get the value for the given key from the map. - /// - /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get>(key: KeyArg) -> Result { - >::try_get(key) - } - - /// Swap the values of two keys. - pub fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2) { - >::swap(key1, key2) - } - - /// Store a value to be associated with the given key from the map. - pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { - >::insert(key, val) - } - - /// Remove the value under a key. - pub fn remove>(key: KeyArg) { - >::remove(key) - } - - /// Mutate the value under a key. - pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( - key: KeyArg, - f: F, - ) -> R { - >::mutate(key, f) - } - - /// Mutate the item, only if an `Ok` value is returned. - pub fn try_mutate(key: KeyArg, f: F) -> Result - where - KeyArg: EncodeLike, - F: FnOnce(&mut QueryKind::Query) -> Result, - { - >::try_mutate(key, f) - } - - /// Mutate the value under a key. Deletes the item if mutated to a `None`. - pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( - key: KeyArg, - f: F, - ) -> R { - >::mutate_exists(key, f) - } - - /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. - pub fn try_mutate_exists(key: KeyArg, f: F) -> Result - where - KeyArg: EncodeLike, - F: FnOnce(&mut Option) -> Result, - { - >::try_mutate_exists(key, f) - } - - /// Take the value under a key. - pub fn take>(key: KeyArg) -> QueryKind::Query { - >::take(key) - } - - /// Append the given items to the value in the storage. - /// - /// `Value` is required to implement `codec::EncodeAppend`. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) - where - EncodeLikeKey: EncodeLike, - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend, - { - >::append(key, item) - } - - /// Read the length of the storage value without decoding the entire value under the - /// given `key`. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len>(key: KeyArg) -> Option - where - Value: StorageDecodeLength, - { - >::decode_len(key) - } - - /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. - /// - /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. - pub fn migrate_key>( - key: KeyArg, - ) -> Option { - >::migrate_key::(key) - } - - /// Remove all value of the storage. - pub fn remove_all() { - >::remove_all() - } - - /// Iter over all value of the storage. - /// - /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. - pub fn iter_values() -> crate::storage::PrefixIterator { - >::iter_values() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade. - pub fn translate_values Option>(f: F) { - >::translate_values(f) - } + /// Get the storage key used to fetch a value corresponding to a specific key. + pub fn hashed_key_for>(key: KeyArg) -> Vec { + >::hashed_key_for(key) + } + + /// Does the value (explicitly) exist in storage? + pub fn contains_key>(key: KeyArg) -> bool { + >::contains_key(key) + } + + /// Load the value associated with the given key from the map. + pub fn get>(key: KeyArg) -> QueryKind::Query { + >::get(key) + } + + /// Try to get the value for the given key from the map. + /// + /// Returns `Ok` if it exists, `Err` if not. + pub fn try_get>(key: KeyArg) -> Result { + >::try_get(key) + } + + /// Swap the values of two keys. + pub fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2) { + >::swap(key1, key2) + } + + /// Store a value to be associated with the given key from the map. + pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { + >::insert(key, val) + } + + /// Remove the value under a key. + pub fn remove>(key: KeyArg) { + >::remove(key) + } + + /// Mutate the value under a key. + pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( + key: KeyArg, + f: F, + ) -> R { + >::mutate(key, f) + } + + /// Mutate the item, only if an `Ok` value is returned. + pub fn try_mutate(key: KeyArg, f: F) -> Result + where + KeyArg: EncodeLike, + F: FnOnce(&mut QueryKind::Query) -> Result, + { + >::try_mutate(key, f) + } + + /// Mutate the value under a key. Deletes the item if mutated to a `None`. + pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( + key: KeyArg, + f: F, + ) -> R { + >::mutate_exists(key, f) + } + + /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists(key: KeyArg, f: F) -> Result + where + KeyArg: EncodeLike, + F: FnOnce(&mut Option) -> Result, + { + >::try_mutate_exists(key, f) + } + + /// Take the value under a key. + pub fn take>(key: KeyArg) -> QueryKind::Query { + >::take(key) + } + + /// Append the given items to the value in the storage. + /// + /// `Value` is required to implement `codec::EncodeAppend`. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) + where + EncodeLikeKey: EncodeLike, + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(key, item) + } + + /// Read the length of the storage value without decoding the entire value under the + /// given `key`. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len>(key: KeyArg) -> Option + where + Value: StorageDecodeLength, + { + >::decode_len(key) + } + + /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. + /// + /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. + pub fn migrate_key>( + key: KeyArg, + ) -> Option { + >::migrate_key::(key) + } + + /// Remove all value of the storage. + pub fn remove_all() { + >::remove_all() + } + + /// Iter over all value of the storage. + /// + /// NOTE: If a value failed to decode becaues storage is corrupted then it is skipped. + pub fn iter_values() -> crate::storage::PrefixIterator { + >::iter_values() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade. + pub fn translate_values Option>(f: F) { + >::translate_values(f) + } } impl - StorageMap + StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Enumerate all elements in the map in no particular order. - /// - /// If you alter the map while doing this, you'll get undefined results. - pub fn iter() -> crate::storage::PrefixIterator<(Key, Value)> { - >::iter() - } - - /// Remove all elements from the map and iterate through them in no particular order. - /// - /// If you add elements to the map while doing this, you'll get undefined results. - pub fn drain() -> crate::storage::PrefixIterator<(Key, Value)> { - >::drain() - } - - /// Translate the values of all elements by a function `f`, in the map in no particular order. - /// - /// By returning `None` from `f` for an element, you'll remove it from the map. - /// - /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. - pub fn translate Option>(f: F) { - >::translate(f) - } + /// Enumerate all elements in the map in no particular order. + /// + /// If you alter the map while doing this, you'll get undefined results. + pub fn iter() -> crate::storage::PrefixIterator<(Key, Value)> { + >::iter() + } + + /// Remove all elements from the map and iterate through them in no particular order. + /// + /// If you add elements to the map while doing this, you'll get undefined results. + pub fn drain() -> crate::storage::PrefixIterator<(Key, Value)> { + >::drain() + } + + /// Translate the values of all elements by a function `f`, in the map in no particular order. + /// + /// By returning `None` from `f` for an element, you'll remove it from the map. + /// + /// NOTE: If a value fail to decode because storage is corrupted then it is skipped. + pub fn translate Option>(f: F) { + >::translate(f) + } } /// Part of storage metadata for a storage map. /// /// NOTE: Generic hasher is supported. pub trait StorageMapMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; - const HASHER: frame_metadata::StorageHasher; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; + const HASHER: frame_metadata::StorageHasher; } impl StorageMapMetadata - for StorageMap + for StorageMap where - Prefix: StorageInstance, - Hasher: crate::hash::StorageHasher, - Key: FullCodec, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Hasher: crate::hash::StorageHasher, + Key: FullCodec, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use crate::hash::*; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = StorageMap; - type AValueQueryWithAnOnEmpty = - StorageMap; - type B = StorageMap; - type C = StorageMap; - type WithLen = StorageMap>; - - TestExternalities::default().execute_with(|| { - let mut k: Vec = vec![]; - k.extend(&twox_128(b"test")); - k.extend(&twox_128(b"foo")); - k.extend(&3u16.blake2_128_concat()); - assert_eq!(A::hashed_key_for(3).to_vec(), k); - - assert_eq!(A::contains_key(3), false); - assert_eq!(A::get(3), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); - - A::insert(3, 10); - assert_eq!(A::contains_key(3), true); - assert_eq!(A::get(3), Some(10)); - assert_eq!(A::try_get(3), Ok(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); - - A::swap(3, 2); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(3), None); - assert_eq!(A::try_get(3), Err(())); - assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); - assert_eq!(A::get(2), Some(10)); - assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); - - A::remove(2); - assert_eq!(A::contains_key(2), false); - assert_eq!(A::get(2), None); - - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); - assert_eq!(AValueQueryWithAnOnEmpty::contains_key(2), true); - assert_eq!(AValueQueryWithAnOnEmpty::get(2), 97 * 4); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Ok(()) - }); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(97 * 4)); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Err(()) - }); - assert_eq!(A::contains_key(2), false); - - A::remove(2); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { - assert!(v.is_none()); - *v = Some(10); - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - - A::remove(2); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - assert!(v.is_none()); - *v = Some(10); - Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - Ok(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { - *v = Some(v.unwrap() * 10); - Err(()) - }); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(100)); - - A::insert(2, 10); - assert_eq!(A::take(2), Some(10)); - assert_eq!(A::contains_key(2), false); - assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97); - assert_eq!(A::contains_key(2), false); - - B::insert(2, 10); - assert_eq!(A::migrate_key::(2), Some(10)); - assert_eq!(A::contains_key(2), true); - assert_eq!(A::get(2), Some(10)); - - A::insert(3, 10); - A::insert(4, 10); - A::remove_all(); - assert_eq!(A::contains_key(3), false); - assert_eq!(A::contains_key(4), false); - - A::insert(3, 10); - A::insert(4, 10); - assert_eq!(A::iter_values().collect::>(), vec![10, 10]); - - C::insert(3, 10); - C::insert(4, 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); - - A::insert(3, 10); - A::insert(4, 10); - assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); - assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); - assert_eq!(A::iter().collect::>(), vec![]); - - C::insert(3, 10); - C::insert(4, 10); - A::translate::(|k, v| Some((k * v as u16).into())); - assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); - assert_eq!(A::HASHER, frame_metadata::StorageHasher::Blake2_128Concat); - assert_eq!( - AValueQueryWithAnOnEmpty::HASHER, - frame_metadata::StorageHasher::Blake2_128Concat - ); - assert_eq!(A::NAME, "foo"); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - - WithLen::remove_all(); - assert_eq!(WithLen::decode_len(3), None); - WithLen::append(0, 10); - assert_eq!(WithLen::decode_len(0), Some(1)); - }) - } + use super::*; + use crate::hash::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = StorageMap; + type AValueQueryWithAnOnEmpty = + StorageMap; + type B = StorageMap; + type C = StorageMap; + type WithLen = StorageMap>; + + TestExternalities::default().execute_with(|| { + let mut k: Vec = vec![]; + k.extend(&twox_128(b"test")); + k.extend(&twox_128(b"foo")); + k.extend(&3u16.blake2_128_concat()); + assert_eq!(A::hashed_key_for(3).to_vec(), k); + + assert_eq!(A::contains_key(3), false); + assert_eq!(A::get(3), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); + + A::insert(3, 10); + assert_eq!(A::contains_key(3), true); + assert_eq!(A::get(3), Some(10)); + assert_eq!(A::try_get(3), Ok(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 10); + + A::swap(3, 2); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(3), None); + assert_eq!(A::try_get(3), Err(())); + assert_eq!(AValueQueryWithAnOnEmpty::get(3), 97); + assert_eq!(A::get(2), Some(10)); + assert_eq!(AValueQueryWithAnOnEmpty::get(2), 10); + + A::remove(2); + assert_eq!(A::contains_key(2), false); + assert_eq!(A::get(2), None); + + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + AValueQueryWithAnOnEmpty::mutate(2, |v| *v = *v * 2); + assert_eq!(AValueQueryWithAnOnEmpty::contains_key(2), true); + assert_eq!(AValueQueryWithAnOnEmpty::get(2), 97 * 4); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Ok(()) + }); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(97 * 4)); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { + *v = *v * 2; + Err(()) + }); + assert_eq!(A::contains_key(2), false); + + A::remove(2); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + assert!(v.is_none()); + *v = Some(10); + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + AValueQueryWithAnOnEmpty::mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + + A::remove(2); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + assert!(v.is_none()); + *v = Some(10); + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + Ok(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate_exists(2, |v| { + *v = Some(v.unwrap() * 10); + Err(()) + }); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(100)); + + A::insert(2, 10); + assert_eq!(A::take(2), Some(10)); + assert_eq!(A::contains_key(2), false); + assert_eq!(AValueQueryWithAnOnEmpty::take(2), 97); + assert_eq!(A::contains_key(2), false); + + B::insert(2, 10); + assert_eq!(A::migrate_key::(2), Some(10)); + assert_eq!(A::contains_key(2), true); + assert_eq!(A::get(2), Some(10)); + + A::insert(3, 10); + A::insert(4, 10); + A::remove_all(); + assert_eq!(A::contains_key(3), false); + assert_eq!(A::contains_key(4), false); + + A::insert(3, 10); + A::insert(4, 10); + assert_eq!(A::iter_values().collect::>(), vec![10, 10]); + + C::insert(3, 10); + C::insert(4, 10); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); + + A::insert(3, 10); + A::insert(4, 10); + assert_eq!(A::iter().collect::>(), vec![(4, 10), (3, 10)]); + assert_eq!(A::drain().collect::>(), vec![(4, 10), (3, 10)]); + assert_eq!(A::iter().collect::>(), vec![]); + + C::insert(3, 10); + C::insert(4, 10); + A::translate::(|k, v| Some((k * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::HASHER, frame_metadata::StorageHasher::Blake2_128Concat); + assert_eq!( + AValueQueryWithAnOnEmpty::HASHER, + frame_metadata::StorageHasher::Blake2_128Concat + ); + assert_eq!(A::NAME, "foo"); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + + WithLen::remove_all(); + assert_eq!(WithLen::decode_len(3), None); + WithLen::append(0, 10); + assert_eq!(WithLen::decode_len(0), Some(1)); + }) + } } diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index a96ad7d84d551..79a0892960b51 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -18,12 +18,12 @@ //! Storage value type. Implements StorageValue trait and its method directly. use crate::{ - storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, - StorageAppend, StorageDecodeLength, - }, - traits::{Get, GetDefault, StorageInstance}, + storage::{ + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, + StorageAppend, StorageDecodeLength, + }, + traits::{Get, GetDefault, StorageInstance}, }; use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; @@ -35,302 +35,302 @@ use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; /// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) /// ``` pub struct StorageValue( - core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, + core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, ); impl crate::storage::generator::StorageValue - for StorageValue + for StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - type Query = QueryKind::Query; - fn module_prefix() -> &'static [u8] { - Prefix::pallet_prefix().as_bytes() - } - fn storage_prefix() -> &'static [u8] { - Prefix::STORAGE_PREFIX.as_bytes() - } - fn from_optional_value_to_query(v: Option) -> Self::Query { - QueryKind::from_optional_value_to_query(v) - } - fn from_query_to_optional_value(v: Self::Query) -> Option { - QueryKind::from_query_to_optional_value(v) - } + type Query = QueryKind::Query; + fn module_prefix() -> &'static [u8] { + Prefix::pallet_prefix().as_bytes() + } + fn storage_prefix() -> &'static [u8] { + Prefix::STORAGE_PREFIX.as_bytes() + } + fn from_optional_value_to_query(v: Option) -> Self::Query { + QueryKind::from_optional_value_to_query(v) + } + fn from_query_to_optional_value(v: Self::Query) -> Option { + QueryKind::from_query_to_optional_value(v) + } } impl - StorageValue, QueryKind, OnEmpty> + StorageValue, QueryKind, OnEmpty> where - Prefix: StorageInstance, - QueryKind: QueryKindTrait, OnEmpty>, - OnEmpty: crate::traits::Get + 'static, - VecValue: BoundedVecValue, - VecBound: Get, + Prefix: StorageInstance, + QueryKind: QueryKindTrait, OnEmpty>, + OnEmpty: crate::traits::Get + 'static, + VecValue: BoundedVecValue, + VecBound: Get, { - /// Try and append the given item to the value in the storage. - /// - /// Is only available if `Value` of the storage is [`BoundedVec`]. - pub fn try_append(item: EncodeLikeItem) -> Result<(), ()> - where - EncodeLikeItem: EncodeLike, - { - >::try_append(item) - } + /// Try and append the given item to the value in the storage. + /// + /// Is only available if `Value` of the storage is [`BoundedVec`]. + pub fn try_append(item: EncodeLikeItem) -> Result<(), ()> + where + EncodeLikeItem: EncodeLike, + { + >::try_append(item) + } } impl StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - /// Get the storage key. - pub fn hashed_key() -> [u8; 32] { - >::hashed_key() - } - - /// Does the value (explicitly) exist in storage? - pub fn exists() -> bool { - >::exists() - } - - /// Load the value from the provided storage instance. - pub fn get() -> QueryKind::Query { - >::get() - } - - /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, - /// `Err` if not. - pub fn try_get() -> Result { - >::try_get() - } - - /// Translate a value from some previous type (`O`) to the current type. - /// - /// `f: F` is the translation function. - /// - /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along - /// with the new value if it could. - /// - /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default - /// value of the original type. - /// - /// # Warning - /// - /// This function must be used with care, before being updated the storage still contains the - /// old type, thus other calls (such as `get`) will fail at decoding it. - /// - /// # Usage - /// - /// This would typically be called inside the module implementation of on_runtime_upgrade, - /// while ensuring **no usage of this storage are made before the call to - /// `on_runtime_upgrade`**. (More precisely prior initialized modules doesn't make use of this - /// storage). - pub fn translate) -> Option>( - f: F, - ) -> Result, ()> { - >::translate(f) - } - - /// Store a value under this key into the provided storage instance. - pub fn put>(val: Arg) { - >::put(val) - } - - /// Store a value under this key into the provided storage instance. - /// - /// this uses the query type rather than the underlying value. - pub fn set(val: QueryKind::Query) { - >::set(val) - } - - /// Mutate the value - pub fn mutate R>(f: F) -> R { - >::mutate(f) - } - - /// Mutate the value if closure returns `Ok` - pub fn try_mutate Result>( - f: F, - ) -> Result { - >::try_mutate(f) - } - - /// Clear the storage value. - pub fn kill() { - >::kill() - } - - /// Take a value from storage, removing it afterwards. - pub fn take() -> QueryKind::Query { - >::take() - } - - /// Append the given item to the value in the storage. - /// - /// `Value` is required to implement [`StorageAppend`]. - /// - /// # Warning - /// - /// If the storage item is not encoded properly, the storage item will be overwritten - /// and set to `[item]`. Any default value set for the storage item will be ignored - /// on overwrite. - pub fn append(item: EncodeLikeItem) - where - Item: Encode, - EncodeLikeItem: EncodeLike, - Value: StorageAppend, - { - >::append(item) - } - - /// Read the length of the storage value without decoding the entire value. - /// - /// `Value` is required to implement [`StorageDecodeLength`]. - /// - /// If the value does not exists or it fails to decode the length, `None` is returned. - /// Otherwise `Some(len)` is returned. - /// - /// # Warning - /// - /// `None` does not mean that `get()` does not return a value. The default value is completly - /// ignored by this function. - pub fn decode_len() -> Option - where - Value: StorageDecodeLength, - { - >::decode_len() - } + /// Get the storage key. + pub fn hashed_key() -> [u8; 32] { + >::hashed_key() + } + + /// Does the value (explicitly) exist in storage? + pub fn exists() -> bool { + >::exists() + } + + /// Load the value from the provided storage instance. + pub fn get() -> QueryKind::Query { + >::get() + } + + /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, + /// `Err` if not. + pub fn try_get() -> Result { + >::try_get() + } + + /// Translate a value from some previous type (`O`) to the current type. + /// + /// `f: F` is the translation function. + /// + /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along + /// with the new value if it could. + /// + /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default + /// value of the original type. + /// + /// # Warning + /// + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_runtime_upgrade, + /// while ensuring **no usage of this storage are made before the call to + /// `on_runtime_upgrade`**. (More precisely prior initialized modules doesn't make use of this + /// storage). + pub fn translate) -> Option>( + f: F, + ) -> Result, ()> { + >::translate(f) + } + + /// Store a value under this key into the provided storage instance. + pub fn put>(val: Arg) { + >::put(val) + } + + /// Store a value under this key into the provided storage instance. + /// + /// this uses the query type rather than the underlying value. + pub fn set(val: QueryKind::Query) { + >::set(val) + } + + /// Mutate the value + pub fn mutate R>(f: F) -> R { + >::mutate(f) + } + + /// Mutate the value if closure returns `Ok` + pub fn try_mutate Result>( + f: F, + ) -> Result { + >::try_mutate(f) + } + + /// Clear the storage value. + pub fn kill() { + >::kill() + } + + /// Take a value from storage, removing it afterwards. + pub fn take() -> QueryKind::Query { + >::take() + } + + /// Append the given item to the value in the storage. + /// + /// `Value` is required to implement [`StorageAppend`]. + /// + /// # Warning + /// + /// If the storage item is not encoded properly, the storage item will be overwritten + /// and set to `[item]`. Any default value set for the storage item will be ignored + /// on overwrite. + pub fn append(item: EncodeLikeItem) + where + Item: Encode, + EncodeLikeItem: EncodeLike, + Value: StorageAppend, + { + >::append(item) + } + + /// Read the length of the storage value without decoding the entire value. + /// + /// `Value` is required to implement [`StorageDecodeLength`]. + /// + /// If the value does not exists or it fails to decode the length, `None` is returned. + /// Otherwise `Some(len)` is returned. + /// + /// # Warning + /// + /// `None` does not mean that `get()` does not return a value. The default value is completly + /// ignored by this function. + pub fn decode_len() -> Option + where + Value: StorageDecodeLength, + { + >::decode_len() + } } /// Part of storage metadata for storage value. pub trait StorageValueMetadata { - const MODIFIER: StorageEntryModifier; - const NAME: &'static str; - const DEFAULT: DefaultByteGetter; + const MODIFIER: StorageEntryModifier; + const NAME: &'static str; + const DEFAULT: DefaultByteGetter; } impl StorageValueMetadata - for StorageValue + for StorageValue where - Prefix: StorageInstance, - Value: FullCodec, - QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + Prefix: StorageInstance, + Value: FullCodec, + QueryKind: QueryKindTrait, + OnEmpty: crate::traits::Get + 'static, { - const MODIFIER: StorageEntryModifier = QueryKind::METADATA; - const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const MODIFIER: StorageEntryModifier = QueryKind::METADATA; + const NAME: &'static str = Prefix::STORAGE_PREFIX; + const DEFAULT: DefaultByteGetter = DefaultByteGetter( + &OnEmptyGetter::(core::marker::PhantomData), + ); } #[cfg(test)] mod test { - use super::*; - use crate::storage::types::ValueQuery; - use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; - - struct Prefix; - impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } - const STORAGE_PREFIX: &'static str = "foo"; - } - - struct ADefault; - impl crate::traits::Get for ADefault { - fn get() -> u32 { - 97 - } - } - - #[test] - fn test() { - type A = StorageValue; - type AValueQueryWithAnOnEmpty = StorageValue; - type B = StorageValue; - type WithLen = StorageValue>; - - TestExternalities::default().execute_with(|| { - assert_eq!( - A::hashed_key().to_vec(), - [twox_128(b"test"), twox_128(b"foo")].concat() - ); - assert_eq!(A::exists(), false); - assert_eq!(A::get(), None); - assert_eq!(AValueQueryWithAnOnEmpty::get(), 97); - assert_eq!(A::try_get(), Err(())); - - A::put(2); - assert_eq!(A::exists(), true); - assert_eq!(A::get(), Some(2)); - assert_eq!(AValueQueryWithAnOnEmpty::get(), 2); - assert_eq!(A::try_get(), Ok(2)); - assert_eq!(A::try_get(), Ok(2)); - - B::put(4); - A::translate::(|v| v.map(Into::into)).unwrap(); - assert_eq!(A::try_get(), Ok(4)); - - A::set(None); - assert_eq!(A::try_get(), Err(())); - - A::set(Some(2)); - assert_eq!(A::try_get(), Ok(2)); - - A::mutate(|v| *v = Some(v.unwrap() * 2)); - assert_eq!(A::try_get(), Ok(4)); - - A::set(Some(4)); - let _: Result<(), ()> = A::try_mutate(|v| { - *v = Some(v.unwrap() * 2); - Ok(()) - }); - assert_eq!(A::try_get(), Ok(8)); - - let _: Result<(), ()> = A::try_mutate(|v| { - *v = Some(v.unwrap() * 2); - Err(()) - }); - assert_eq!(A::try_get(), Ok(8)); - - A::kill(); - AValueQueryWithAnOnEmpty::mutate(|v| *v = *v * 2); - assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); - - AValueQueryWithAnOnEmpty::kill(); - let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| { - *v = *v * 2; - Ok(()) - }); - assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); - - A::kill(); - assert_eq!(A::try_get(), Err(())); - - assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); - assert_eq!(A::NAME, "foo"); - assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); - - WithLen::kill(); - assert_eq!(WithLen::decode_len(), None); - WithLen::append(3); - assert_eq!(WithLen::decode_len(), Some(1)); - }); - } + use super::*; + use crate::storage::types::ValueQuery; + use frame_metadata::StorageEntryModifier; + use sp_io::{hashing::twox_128, TestExternalities}; + + struct Prefix; + impl StorageInstance for Prefix { + fn pallet_prefix() -> &'static str { + "test" + } + const STORAGE_PREFIX: &'static str = "foo"; + } + + struct ADefault; + impl crate::traits::Get for ADefault { + fn get() -> u32 { + 97 + } + } + + #[test] + fn test() { + type A = StorageValue; + type AValueQueryWithAnOnEmpty = StorageValue; + type B = StorageValue; + type WithLen = StorageValue>; + + TestExternalities::default().execute_with(|| { + assert_eq!( + A::hashed_key().to_vec(), + [twox_128(b"test"), twox_128(b"foo")].concat() + ); + assert_eq!(A::exists(), false); + assert_eq!(A::get(), None); + assert_eq!(AValueQueryWithAnOnEmpty::get(), 97); + assert_eq!(A::try_get(), Err(())); + + A::put(2); + assert_eq!(A::exists(), true); + assert_eq!(A::get(), Some(2)); + assert_eq!(AValueQueryWithAnOnEmpty::get(), 2); + assert_eq!(A::try_get(), Ok(2)); + assert_eq!(A::try_get(), Ok(2)); + + B::put(4); + A::translate::(|v| v.map(Into::into)).unwrap(); + assert_eq!(A::try_get(), Ok(4)); + + A::set(None); + assert_eq!(A::try_get(), Err(())); + + A::set(Some(2)); + assert_eq!(A::try_get(), Ok(2)); + + A::mutate(|v| *v = Some(v.unwrap() * 2)); + assert_eq!(A::try_get(), Ok(4)); + + A::set(Some(4)); + let _: Result<(), ()> = A::try_mutate(|v| { + *v = Some(v.unwrap() * 2); + Ok(()) + }); + assert_eq!(A::try_get(), Ok(8)); + + let _: Result<(), ()> = A::try_mutate(|v| { + *v = Some(v.unwrap() * 2); + Err(()) + }); + assert_eq!(A::try_get(), Ok(8)); + + A::kill(); + AValueQueryWithAnOnEmpty::mutate(|v| *v = *v * 2); + assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); + + AValueQueryWithAnOnEmpty::kill(); + let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| { + *v = *v * 2; + Ok(()) + }); + assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); + + A::kill(); + assert_eq!(A::try_get(), Err(())); + + assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); + assert_eq!( + AValueQueryWithAnOnEmpty::MODIFIER, + StorageEntryModifier::Default + ); + assert_eq!(A::NAME, "foo"); + assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); + assert_eq!( + AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), + 97u32.encode() + ); + + WithLen::kill(); + assert_eq!(WithLen::decode_len(), None); + WithLen::append(3); + assert_eq!(WithLen::decode_len(), Some(1)); + }); + } } From 7686c7b4ed5aed041b50116f144c825228a3a008 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sat, 24 Apr 2021 02:01:11 -0700 Subject: [PATCH 15/34] Generate Key struct instead of a 1-tuple when only 1 pair of key and hasher is provided --- frame/support/procedural/src/storage/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 9c27affae9a75..864179e4c6195 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -382,6 +382,12 @@ pub struct NMapDef { impl NMapDef { fn to_keygen_struct(&self, scrate: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { + if self.keys.len() == 1 { + let hasher = &self.hashers[0].to_storage_hasher_struct(); + let key = &self.keys[0]; + return quote!( Key<#scrate::#hasher, #key> ); + } + let key_hasher = self.keys.iter().zip(&self.hashers).map(|(key, hasher)| { let hasher = hasher.to_storage_hasher_struct(); quote!( Key<#scrate::#hasher, #key> ) From b83dbf27b25f46f750d4c424a156397cc3de03e4 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 10:59:11 -0700 Subject: [PATCH 16/34] Revert formatting changes to unrelated files --- frame/support/src/storage/types/double_map.rs | 190 ++++++------------ frame/support/src/storage/types/map.rs | 70 +++---- frame/support/src/storage/types/value.rs | 89 +++----- 3 files changed, 113 insertions(+), 236 deletions(-) diff --git a/frame/support/src/storage/types/double_map.rs b/frame/support/src/storage/types/double_map.rs index 0b6292b3fcb3d..184d96b3a54f9 100644 --- a/frame/support/src/storage/types/double_map.rs +++ b/frame/support/src/storage/types/double_map.rs @@ -18,15 +18,15 @@ //! Storage map type. Implements StorageDoubleMap, StorageIterableDoubleMap, //! StoragePrefixedDoubleMap traits and their methods directly. +use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, StorageAppend, StorageDecodeLength, + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{Get, GetDefault, StorageInstance}, + traits::{GetDefault, StorageInstance, Get}, }; -use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::vec::Vec; @@ -47,30 +47,14 @@ use sp_std::vec::Vec; /// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values /// in storage can be compromised. pub struct StorageDoubleMap< - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - Value, - QueryKind = OptionQuery, - OnEmpty = GetDefault, + Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind=OptionQuery, OnEmpty=GetDefault >( - core::marker::PhantomData<( - Prefix, - Hasher1, - Key1, - Hasher2, - Key2, - Value, - QueryKind, - OnEmpty, - )>, + core::marker::PhantomData<(Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty)> ); impl - crate::storage::generator::StorageDoubleMap - for StorageDoubleMap + crate::storage::generator::StorageDoubleMap for + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -79,7 +63,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: crate::traits::Get + 'static { type Query = QueryKind::Query; type Hasher1 = Hasher1; @@ -99,8 +83,8 @@ where } impl - crate::storage::StoragePrefixedMap - for StorageDoubleMap + crate::storage::StoragePrefixedMap for + StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, @@ -109,7 +93,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: crate::traits::Get + 'static { fn module_prefix() -> &'static [u8] { >::module_prefix() @@ -129,8 +113,7 @@ impl, QueryKind, OnEmpty, - > -where + > where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, Hasher2: crate::hash::StorageHasher, @@ -174,7 +157,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: crate::traits::Get + 'static { /// Get the storage key used to fetch a value corresponding to a specific key. pub fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec @@ -209,8 +192,7 @@ where pub fn try_get(k1: KArg1, k2: KArg2) -> Result where KArg1: EncodeLike, - KArg2: EncodeLike, - { + KArg2: EncodeLike { >::try_get(k1, k2) } @@ -224,12 +206,8 @@ where } /// Swap the values of two key-pairs. - pub fn swap( - x_k1: XKArg1, - x_k2: XKArg2, - y_k1: YKArg1, - y_k2: YKArg2, - ) where + pub fn swap(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2) + where XKArg1: EncodeLike, XKArg2: EncodeLike, YKArg1: EncodeLike, @@ -258,17 +236,13 @@ where } /// Remove all values under the first key. - pub fn remove_prefix(k1: KArg1) - where - KArg1: ?Sized + EncodeLike, - { + pub fn remove_prefix(k1: KArg1) where KArg1: ?Sized + EncodeLike { >::remove_prefix(k1) } /// Iterate over values that share the first key. pub fn iter_prefix_values(k1: KArg1) -> crate::storage::PrefixIterator - where - KArg1: ?Sized + EncodeLike, + where KArg1: ?Sized + EncodeLike { >::iter_prefix_values(k1) } @@ -322,8 +296,11 @@ where /// If the storage item is not encoded properly, the storage will be overwritten /// and set to `[item]`. Any default value set for the storage item will be ignored /// on overwrite. - pub fn append(k1: KArg1, k2: KArg2, item: EncodeLikeItem) - where + pub fn append( + k1: KArg1, + k2: KArg2, + item: EncodeLikeItem, + ) where KArg1: EncodeLike, KArg2: EncodeLike, Item: Encode, @@ -363,16 +340,10 @@ where OldHasher2: crate::StorageHasher, KeyArg1: EncodeLike, KeyArg2: EncodeLike, - >( - key1: KeyArg1, - key2: KeyArg2, - ) -> Option { - >::migrate_keys::< - OldHasher1, - OldHasher2, - _, - _, - >(key1, key2) + >(key1: KeyArg1, key2: KeyArg2) -> Option { + < + Self as crate::storage::StorageDoubleMap + >::migrate_keys::(key1, key2) } /// Remove all value of the storage. @@ -415,7 +386,7 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: crate::traits::Get + 'static { /// Enumerate all elements in the map with first key `k1` in no particular order. /// @@ -430,9 +401,7 @@ where /// /// If you add elements with first key `k1` to the map while doing this, you'll get undefined /// results. - pub fn drain_prefix( - k1: impl EncodeLike, - ) -> crate::storage::PrefixIterator<(Key2, Value)> { + pub fn drain_prefix(k1: impl EncodeLike) -> crate::storage::PrefixIterator<(Key2, Value)> { >::drain_prefix(k1) } @@ -472,8 +441,7 @@ pub trait StorageDoubleMapMetadata { } impl StorageDoubleMapMetadata - for StorageDoubleMap -where + for StorageDoubleMap where Prefix: StorageInstance, Hasher1: crate::hash::StorageHasher, Hasher2: crate::hash::StorageHasher, @@ -481,30 +449,27 @@ where Key2: FullCodec, Value: FullCodec, QueryKind: QueryKindTrait, - OnEmpty: crate::traits::Get + 'static, + OnEmpty: crate::traits::Get + 'static { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA; const HASHER2: frame_metadata::StorageHasher = Hasher2::METADATA; const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const DEFAULT: DefaultByteGetter = + DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } #[cfg(test)] mod test { use super::*; + use sp_io::{TestExternalities, hashing::twox_128}; use crate::hash::*; use crate::storage::types::ValueQuery; use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } + fn pallet_prefix() -> &'static str { "test" } const STORAGE_PREFIX: &'static str = "foo"; } @@ -517,17 +482,11 @@ mod test { #[test] fn test() { - type A = - StorageDoubleMap; + type A = StorageDoubleMap< + Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u32, OptionQuery + >; type AValueQueryWithAnOnEmpty = StorageDoubleMap< - Prefix, - Blake2_128Concat, - u16, - Twox64Concat, - u8, - u32, - ValueQuery, - ADefault, + Prefix, Blake2_128Concat, u16, Twox64Concat, u8, u32, ValueQuery, ADefault >; type B = StorageDoubleMap; type C = StorageDoubleMap; @@ -569,20 +528,17 @@ mod test { A::remove(2, 20); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Ok(()) + *v = *v * 2; Ok(()) }); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Ok(()) + *v = *v * 2; Ok(()) }); assert_eq!(A::contains_key(2, 20), true); assert_eq!(A::get(2, 20), Some(97 * 4)); A::remove(2, 20); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, 20, |v| { - *v = *v * 2; - Err(()) + *v = *v * 2; Err(()) }); assert_eq!(A::contains_key(2, 20), false); @@ -621,6 +577,7 @@ mod test { assert_eq!(A::contains_key(2, 20), true); assert_eq!(A::get(2, 20), Some(100)); + A::insert(2, 20, 10); assert_eq!(A::take(2, 20), Some(10)); assert_eq!(A::contains_key(2, 20), false); @@ -629,10 +586,7 @@ mod test { assert_eq!(A::try_get(2, 20), Err(())); B::insert(2, 20, 10); - assert_eq!( - A::migrate_keys::(2, 20), - Some(10) - ); + assert_eq!(A::migrate_keys::(2, 20), Some(10)); assert_eq!(A::contains_key(2, 20), true); assert_eq!(A::get(2, 20), Some(10)); @@ -648,37 +602,22 @@ mod test { C::insert(3, 30, 10); C::insert(4, 40, 10); - A::translate_values::(|v| Some((v * 2).into())); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 20), (3, 30, 20)] - ); + A::translate_values::(|v| Some((v * 2).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 40, 20), (3, 30, 20)]); A::insert(3, 30, 10); A::insert(4, 40, 10); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 10), (3, 30, 10)] - ); - assert_eq!( - A::drain().collect::>(), - vec![(4, 40, 10), (3, 30, 10)] - ); + assert_eq!(A::iter().collect::>(), vec![(4, 40, 10), (3, 30, 10)]); + assert_eq!(A::drain().collect::>(), vec![(4, 40, 10), (3, 30, 10)]); assert_eq!(A::iter().collect::>(), vec![]); C::insert(3, 30, 10); C::insert(4, 40, 10); - A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); - assert_eq!( - A::iter().collect::>(), - vec![(4, 40, 1600), (3, 30, 900)] - ); + A::translate::(|k1, k2, v| Some((k1 * k2 as u16 * v as u16).into())); + assert_eq!(A::iter().collect::>(), vec![(4, 40, 1600), (3, 30, 900)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); assert_eq!(A::HASHER1, frame_metadata::StorageHasher::Blake2_128Concat); assert_eq!(A::HASHER2, frame_metadata::StorageHasher::Twox64Concat); assert_eq!( @@ -690,10 +629,7 @@ mod test { frame_metadata::StorageHasher::Twox64Concat ); assert_eq!(A::NAME, "foo"); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); @@ -706,27 +642,15 @@ mod test { A::insert(4, 40, 13); A::insert(4, 41, 14); assert_eq!(A::iter_prefix_values(3).collect::>(), vec![12, 11]); - assert_eq!( - A::iter_prefix(3).collect::>(), - vec![(31, 12), (30, 11)] - ); + assert_eq!(A::iter_prefix(3).collect::>(), vec![(31, 12), (30, 11)]); assert_eq!(A::iter_prefix_values(4).collect::>(), vec![13, 14]); - assert_eq!( - A::iter_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); + assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); A::remove_prefix(3); assert_eq!(A::iter_prefix(3).collect::>(), vec![]); - assert_eq!( - A::iter_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); + assert_eq!(A::iter_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); - assert_eq!( - A::drain_prefix(4).collect::>(), - vec![(40, 13), (41, 14)] - ); + assert_eq!(A::drain_prefix(4).collect::>(), vec![(40, 13), (41, 14)]); assert_eq!(A::iter_prefix(4).collect::>(), vec![]); assert_eq!(A::drain_prefix(4).collect::>(), vec![]); }) diff --git a/frame/support/src/storage/types/map.rs b/frame/support/src/storage/types/map.rs index dc8e3324dffa2..187323b4ad1ee 100644 --- a/frame/support/src/storage/types/map.rs +++ b/frame/support/src/storage/types/map.rs @@ -18,15 +18,15 @@ //! Storage map type. Implements StorageMap, StorageIterableMap, StoragePrefixedMap traits and their //! methods directly. +use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, StorageAppend, StorageDecodeLength, + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{Get, GetDefault, StorageInstance}, + traits::{GetDefault, StorageInstance, Get}, }; -use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; use sp_std::prelude::*; @@ -43,8 +43,8 @@ use sp_std::prelude::*; /// /// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as /// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised. -pub struct StorageMap( - core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>, +pub struct StorageMap( + core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)> ); impl @@ -74,8 +74,8 @@ where } } -impl crate::storage::StoragePrefixedMap - for StorageMap +impl crate::storage::StoragePrefixedMap for + StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, @@ -170,7 +170,7 @@ where /// Mutate the value under a key. pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( key: KeyArg, - f: F, + f: F ) -> R { >::mutate(key, f) } @@ -187,7 +187,7 @@ where /// Mutate the value under a key. Deletes the item if mutated to a `None`. pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( key: KeyArg, - f: F, + f: F ) -> R { >::mutate_exists(key, f) } @@ -220,7 +220,7 @@ where EncodeLikeKey: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, - Value: StorageAppend, + Value: StorageAppend { >::append(key, item) } @@ -238,8 +238,7 @@ where /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. pub fn decode_len>(key: KeyArg) -> Option - where - Value: StorageDecodeLength, + where Value: StorageDecodeLength, { >::decode_len(key) } @@ -248,7 +247,7 @@ where /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. pub fn migrate_key>( - key: KeyArg, + key: KeyArg ) -> Option { >::migrate_key::(key) } @@ -329,8 +328,7 @@ pub trait StorageMapMetadata { } impl StorageMapMetadata - for StorageMap -where + for StorageMap where Prefix: StorageInstance, Hasher: crate::hash::StorageHasher, Key: FullCodec, @@ -341,24 +339,21 @@ where const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const HASHER: frame_metadata::StorageHasher = Hasher::METADATA; const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const DEFAULT: DefaultByteGetter = + DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } #[cfg(test)] mod test { use super::*; + use sp_io::{TestExternalities, hashing::twox_128}; use crate::hash::*; use crate::storage::types::ValueQuery; use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } + fn pallet_prefix() -> &'static str { "test" } const STORAGE_PREFIX: &'static str = "foo"; } @@ -372,8 +367,9 @@ mod test { #[test] fn test() { type A = StorageMap; - type AValueQueryWithAnOnEmpty = - StorageMap; + type AValueQueryWithAnOnEmpty = StorageMap< + Prefix, Blake2_128Concat, u16, u32, ValueQuery, ADefault + >; type B = StorageMap; type C = StorageMap; type WithLen = StorageMap>; @@ -415,20 +411,17 @@ mod test { A::remove(2); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Ok(()) + *v = *v * 2; Ok(()) }); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Ok(()) + *v = *v * 2; Ok(()) }); assert_eq!(A::contains_key(2), true); assert_eq!(A::get(2), Some(97 * 4)); A::remove(2); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(2, |v| { - *v = *v * 2; - Err(()) + *v = *v * 2; Err(()) }); assert_eq!(A::contains_key(2), false); @@ -466,6 +459,7 @@ mod test { assert_eq!(A::contains_key(2), true); assert_eq!(A::get(2), Some(100)); + A::insert(2, 10); assert_eq!(A::take(2), Some(10)); assert_eq!(A::contains_key(2), false); @@ -489,7 +483,7 @@ mod test { C::insert(3, 10); C::insert(4, 10); - A::translate_values::(|v| Some((v * 2).into())); + A::translate_values::(|v| Some((v * 2).into())); assert_eq!(A::iter().collect::>(), vec![(4, 20), (3, 20)]); A::insert(3, 10); @@ -500,24 +494,18 @@ mod test { C::insert(3, 10); C::insert(4, 10); - A::translate::(|k, v| Some((k * v as u16).into())); + A::translate::(|k, v| Some((k * v as u16).into())); assert_eq!(A::iter().collect::>(), vec![(4, 40), (3, 30)]); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); assert_eq!(A::HASHER, frame_metadata::StorageHasher::Blake2_128Concat); assert_eq!( AValueQueryWithAnOnEmpty::HASHER, frame_metadata::StorageHasher::Blake2_128Concat ); assert_eq!(A::NAME, "foo"); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); WithLen::remove_all(); diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index 79a0892960b51..d536d76d76b8e 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -17,15 +17,15 @@ //! Storage value type. Implements StorageValue trait and its method directly. +use codec::{FullCodec, Decode, EncodeLike, Encode}; use crate::{ storage::{ - bounded_vec::{BoundedVec, BoundedVecValue}, - types::{OnEmptyGetter, OptionQuery, QueryKindTrait}, StorageAppend, StorageDecodeLength, + bounded_vec::{BoundedVec, BoundedVecValue}, + types::{OptionQuery, QueryKindTrait, OnEmptyGetter}, }, - traits::{Get, GetDefault, StorageInstance}, + traits::{GetDefault, StorageInstance, Get}, }; -use codec::{Decode, Encode, EncodeLike, FullCodec}; use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; /// A type that allow to store a value. @@ -34,12 +34,12 @@ use frame_metadata::{DefaultByteGetter, StorageEntryModifier}; /// ```nocompile /// Twox128(Prefix::pallet_prefix()) ++ Twox128(Prefix::STORAGE_PREFIX) /// ``` -pub struct StorageValue( - core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>, +pub struct StorageValue( + core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)> ); -impl crate::storage::generator::StorageValue - for StorageValue +impl crate::storage::generator::StorageValue for + StorageValue where Prefix: StorageInstance, Value: FullCodec, @@ -89,19 +89,13 @@ where OnEmpty: crate::traits::Get + 'static, { /// Get the storage key. - pub fn hashed_key() -> [u8; 32] { - >::hashed_key() - } + pub fn hashed_key() -> [u8; 32] { >::hashed_key() } /// Does the value (explicitly) exist in storage? - pub fn exists() -> bool { - >::exists() - } + pub fn exists() -> bool { >::exists() } /// Load the value from the provided storage instance. - pub fn get() -> QueryKind::Query { - >::get() - } + pub fn get() -> QueryKind::Query { >::get() } /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, /// `Err` if not. @@ -144,9 +138,7 @@ where /// Store a value under this key into the provided storage instance. /// /// this uses the query type rather than the underlying value. - pub fn set(val: QueryKind::Query) { - >::set(val) - } + pub fn set(val: QueryKind::Query) { >::set(val) } /// Mutate the value pub fn mutate R>(f: F) -> R { @@ -161,14 +153,10 @@ where } /// Clear the storage value. - pub fn kill() { - >::kill() - } + pub fn kill() { >::kill() } /// Take a value from storage, removing it afterwards. - pub fn take() -> QueryKind::Query { - >::take() - } + pub fn take() -> QueryKind::Query { >::take() } /// Append the given item to the value in the storage. /// @@ -183,7 +171,7 @@ where where Item: Encode, EncodeLikeItem: EncodeLike, - Value: StorageAppend, + Value: StorageAppend { >::append(item) } @@ -199,10 +187,7 @@ where /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - pub fn decode_len() -> Option - where - Value: StorageDecodeLength, - { + pub fn decode_len() -> Option where Value: StorageDecodeLength { >::decode_len() } } @@ -215,8 +200,7 @@ pub trait StorageValueMetadata { } impl StorageValueMetadata - for StorageValue -where + for StorageValue where Prefix: StorageInstance, Value: FullCodec, QueryKind: QueryKindTrait, @@ -224,23 +208,20 @@ where { const MODIFIER: StorageEntryModifier = QueryKind::METADATA; const NAME: &'static str = Prefix::STORAGE_PREFIX; - const DEFAULT: DefaultByteGetter = DefaultByteGetter( - &OnEmptyGetter::(core::marker::PhantomData), - ); + const DEFAULT: DefaultByteGetter = + DefaultByteGetter(&OnEmptyGetter::(core::marker::PhantomData)); } #[cfg(test)] mod test { use super::*; + use sp_io::{TestExternalities, hashing::twox_128}; use crate::storage::types::ValueQuery; use frame_metadata::StorageEntryModifier; - use sp_io::{hashing::twox_128, TestExternalities}; struct Prefix; impl StorageInstance for Prefix { - fn pallet_prefix() -> &'static str { - "test" - } + fn pallet_prefix() -> &'static str { "test" } const STORAGE_PREFIX: &'static str = "foo"; } @@ -259,10 +240,7 @@ mod test { type WithLen = StorageValue>; TestExternalities::default().execute_with(|| { - assert_eq!( - A::hashed_key().to_vec(), - [twox_128(b"test"), twox_128(b"foo")].concat() - ); + assert_eq!(A::hashed_key().to_vec(), [twox_128(b"test"), twox_128(b"foo")].concat()); assert_eq!(A::exists(), false); assert_eq!(A::get(), None); assert_eq!(AValueQueryWithAnOnEmpty::get(), 97); @@ -289,16 +267,10 @@ mod test { assert_eq!(A::try_get(), Ok(4)); A::set(Some(4)); - let _: Result<(), ()> = A::try_mutate(|v| { - *v = Some(v.unwrap() * 2); - Ok(()) - }); + let _: Result<(), ()> = A::try_mutate(|v| { *v = Some(v.unwrap() * 2); Ok(()) }); assert_eq!(A::try_get(), Ok(8)); - let _: Result<(), ()> = A::try_mutate(|v| { - *v = Some(v.unwrap() * 2); - Err(()) - }); + let _: Result<(), ()> = A::try_mutate(|v| { *v = Some(v.unwrap() * 2); Err(()) }); assert_eq!(A::try_get(), Ok(8)); A::kill(); @@ -307,8 +279,7 @@ mod test { AValueQueryWithAnOnEmpty::kill(); let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| { - *v = *v * 2; - Ok(()) + *v = *v * 2; Ok(()) }); assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2)); @@ -316,16 +287,10 @@ mod test { assert_eq!(A::try_get(), Err(())); assert_eq!(A::MODIFIER, StorageEntryModifier::Optional); - assert_eq!( - AValueQueryWithAnOnEmpty::MODIFIER, - StorageEntryModifier::Default - ); + assert_eq!(AValueQueryWithAnOnEmpty::MODIFIER, StorageEntryModifier::Default); assert_eq!(A::NAME, "foo"); assert_eq!(A::DEFAULT.0.default_byte(), Option::::None.encode()); - assert_eq!( - AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), - 97u32.encode() - ); + assert_eq!(AValueQueryWithAnOnEmpty::DEFAULT.0.default_byte(), 97u32.encode()); WithLen::kill(); assert_eq!(WithLen::decode_len(), None); From 994e17004c8c3d2d9bcf7312b673d6d550032a72 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 11:32:16 -0700 Subject: [PATCH 17/34] Introduce KeyGeneratorInner --- frame/support/src/storage/types/key.rs | 946 +++++++++++++------------ 1 file changed, 475 insertions(+), 471 deletions(-) diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index f1cd07d302c74..d0fb0fd1cd8b9 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -35,157 +35,161 @@ pub struct Key(core::marker::PhantomData<(Hasher, KeyType)>); /// A trait that contains the current key as an associated type. pub trait KeyGenerator { - type Key: EncodeLike; - type KArg: Encode; - type HashFn: FnOnce(&[u8]) -> Vec; - type HArg; - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; - fn migrate_key + TupleToEncodedIter>( - key: &KArg, - hash_fns: Self::HArg, - ) -> Vec; - fn final_hash(encoded: &[u8]) -> Vec; + type Key: EncodeLike; + type KArg: Encode; + type HashFn: FnOnce(&[u8]) -> Vec; + type HArg; + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec; +} + +/// A trait containing methods that are only implemented on the Key struct instead of the entire tuple. +pub trait KeyGeneratorInner: KeyGenerator { + fn final_hash(encoded: &[u8]) -> Vec; } impl KeyGenerator for Key { - type Key = K; - type KArg = (K,); - type HashFn = Box Vec>; - type HArg = (Self::HashFn,); - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { - H::hash( - &key.to_encoded_iter() - .next() - .expect("should have at least one element!"), - ) - .as_ref() - .to_vec() - } - - fn migrate_key + TupleToEncodedIter>( - key: &KArg, - hash_fns: Self::HArg, - ) -> Vec { - (hash_fns.0)( - &key.to_encoded_iter() - .next() - .expect("should have at least one element!"), - ) - } - - fn final_hash(encoded: &[u8]) -> Vec { - H::hash(encoded).as_ref().to_vec() - } + type Key = K; + type KArg = (K,); + type HashFn = Box Vec>; + type HArg = (Self::HashFn,); + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + H::hash( + &key.to_encoded_iter() + .next() + .expect("should have at least one element!"), + ) + .as_ref() + .to_vec() + } + + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec { + (hash_fns.0)( + &key.to_encoded_iter() + .next() + .expect("should have at least one element!"), + ) + } +} + +impl KeyGeneratorInner for Key { + fn final_hash(encoded: &[u8]) -> Vec { + H::hash(encoded).as_ref().to_vec() + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] +#[tuple_types_custom_trait_bound(KeyGeneratorInner)] impl KeyGenerator for Tuple { - for_tuples!( type Key = ( #(Tuple::Key),* ); ); - for_tuples!( type KArg = ( #(Tuple::Key),* ); ); - for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); - type HashFn = Box Vec>; - - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { - let mut final_key = Vec::new(); - let mut iter = key.to_encoded_iter(); - for_tuples!( - #( - let next_encoded = iter.next().expect("KArg number should be equal to Key number"); - final_key.extend_from_slice(&Tuple::final_hash(&next_encoded)); - )* - ); - final_key - } - - fn migrate_key + TupleToEncodedIter>( - key: &KArg, - hash_fns: Self::HArg, - ) -> Vec { - let mut migrated_key = Vec::new(); - let mut iter = key.to_encoded_iter(); - for_tuples!( - #( - let next_encoded = iter.next().expect("KArg number should be equal to Key number"); - migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded)); - )* - ); - migrated_key - } - - fn final_hash(encoded: &[u8]) -> Vec { - panic!("final_hash called on KeyGenerator tuple") - } + for_tuples!( type Key = ( #(Tuple::Key),* ); ); + for_tuples!( type KArg = ( #(Tuple::Key),* ); ); + for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); + type HashFn = Box Vec>; + + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + let mut final_key = Vec::new(); + let mut iter = key.to_encoded_iter(); + for_tuples!( + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + final_key.extend_from_slice(&Tuple::final_hash(&next_encoded)); + )* + ); + final_key + } + + fn migrate_key + TupleToEncodedIter>( + key: &KArg, + hash_fns: Self::HArg, + ) -> Vec { + let mut migrated_key = Vec::new(); + let mut iter = key.to_encoded_iter(); + for_tuples!( + #( + let next_encoded = iter.next().expect("KArg number should be equal to Key number"); + migrated_key.extend_from_slice(&(hash_fns.Tuple)(&next_encoded)); + )* + ); + migrated_key + } } /// Trait to indicate that a tuple can be converted into an iterator of a vector of encoded bytes. pub trait TupleToEncodedIter { - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; } impl TupleToEncodedIter for (A,) { - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { - vec![self.0.encode()].into_iter() - } + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + vec![self.0.encode()].into_iter() + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] #[tuple_types_no_default_trait_bound] impl TupleToEncodedIter for Tuple { - for_tuples!( where #(Tuple: Encode),* ); - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { - [for_tuples!( #(self.Tuple.encode()),* )] - .to_vec() - .into_iter() - } + for_tuples!( where #(Tuple: Encode),* ); + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + [for_tuples!( #(self.Tuple.encode()),* )] + .to_vec() + .into_iter() + } } /// A trait that indicates the hashers for the keys generated are all reversible. pub trait ReversibleKeyGenerator: KeyGenerator { - type Hasher; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; + type Hasher; + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; } impl ReversibleKeyGenerator for Key { - type Hasher = H; + type Hasher = H; - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { - let mut current_key_material = Self::Hasher::reverse(key_material); - let key = K::decode(&mut current_key_material)?; - Ok((key, current_key_material)) - } + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = Self::Hasher::reverse(key_material); + let key = K::decode(&mut current_key_material)?; + Ok((key, current_key_material)) + } } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] +#[tuple_types_custom_trait_bound(ReversibleKeyGenerator + KeyGeneratorInner)] impl ReversibleKeyGenerator for Tuple { - for_tuples!( type Hasher = ( #(Tuple::Hasher),* ); ); - - fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { - let mut current_key_material = key_material; - Ok(( - (for_tuples! { - #({ - let (key, material) = Tuple::decode_final_key(current_key_material)?; - current_key_material = material; - key - }),* - }), - current_key_material, - )) - } + for_tuples!( type Hasher = ( #(Tuple::Hasher),* ); ); + + fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { + let mut current_key_material = key_material; + Ok(( + (for_tuples! { + #({ + let (key, material) = Tuple::decode_final_key(current_key_material)?; + current_key_material = material; + key + }),* + }), + current_key_material, + )) + } } /// Trait indicating whether a KeyGenerator has the prefix P. pub trait HasKeyPrefix

: KeyGenerator { - type Suffix; + type Suffix; - fn partial_key(prefix: P) -> Vec; + fn partial_key(prefix: P) -> Vec; } /// Trait indicating whether a ReversibleKeyGenerator has the prefix P. pub trait HasReversibleKeyPrefix

: ReversibleKeyGenerator + HasKeyPrefix

{ - fn decode_partial_key(key_material: &[u8]) -> Result; + fn decode_partial_key(key_material: &[u8]) -> Result; } macro_rules! impl_key_prefix_for { @@ -261,21 +265,21 @@ macro_rules! impl_key_prefix_for { } impl HasKeyPrefix<(A,)> - for (Key, Key) + for (Key, Key) { - type Suffix = B; + type Suffix = B; - fn partial_key(prefix: (A,)) -> Vec { - >::final_key(prefix) - } + fn partial_key(prefix: (A,)) -> Vec { + >::final_key(prefix) + } } impl - HasReversibleKeyPrefix<(A,)> for (Key, Key) + HasReversibleKeyPrefix<(A,)> for (Key, Key) { - fn decode_partial_key(key_material: &[u8]) -> Result { - >::decode_final_key(key_material).map(|k| k.0) - } + fn decode_partial_key(key_material: &[u8]) -> Result { + >::decode_final_key(key_material).map(|k| k.0) + } } impl_key_prefix_for!((A, B, C), (A, B), C); @@ -314,587 +318,587 @@ impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B, C), (D, E, F, G, H, I)) impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), (A, B), (C, D, E, F, G, H, I)); impl_key_prefix_for!((A, B, C, D, E, F, G, H, I), A, (B, C, D, E, F, G, H, I)); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D, E, F, G, H, I), - J + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G, H, I), + J ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D, E, F, G, H), - (I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G, H), + (I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D, E, F, G), - (H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F, G), + (H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D, E, F), - (G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E, F), + (G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D, E), - (F, G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D, E), + (F, G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C, D), - (E, F, G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C, D), + (E, F, G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B, C), - (D, E, F, G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B, C), + (D, E, F, G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - (A, B), - (C, D, E, F, G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + (A, B), + (C, D, E, F, G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J), - A, - (B, C, D, E, F, G, H, I, J) + (A, B, C, D, E, F, G, H, I, J), + A, + (B, C, D, E, F, G, H, I, J) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E, F, G, H, I, J), - K + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H, I, J), + K ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E, F, G, H, I), - (J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H, I), + (J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E, F, G, H), - (I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G, H), + (I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E, F, G), - (H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F, G), + (H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E, F), - (G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E, F), + (G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D, E), - (F, G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D, E), + (F, G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C, D), - (E, F, G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C, D), + (E, F, G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B, C), - (D, E, F, G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B, C), + (D, E, F, G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - (A, B), - (C, D, E, F, G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + (A, B), + (C, D, E, F, G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K), - A, - (B, C, D, E, F, G, H, I, J, K) + (A, B, C, D, E, F, G, H, I, J, K), + A, + (B, C, D, E, F, G, H, I, J, K) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F, G, H, I, J, K), - L + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I, J, K), + L ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F, G, H, I, J), - (K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I, J), + (K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F, G, H, I), - (J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H, I), + (J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F, G, H), - (I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G, H), + (I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F, G), - (H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F, G), + (H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E, F), - (G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E, F), + (G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D, E), - (F, G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D, E), + (F, G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C, D), - (E, F, G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C, D), + (E, F, G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B, C), - (D, E, F, G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B, C), + (D, E, F, G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - (A, B), - (C, D, E, F, G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + (A, B), + (C, D, E, F, G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L), - A, - (B, C, D, E, F, G, H, I, J, K, L) + (A, B, C, D, E, F, G, H, I, J, K, L), + A, + (B, C, D, E, F, G, H, I, J, K, L) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G, H, I, J, K, L), - M + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J, K, L), + M ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M), - A, - (B, C, D, E, F, G, H, I, J, K, L, M) + (A, B, C, D, E, F, G, H, I, J, K, L, M), + A, + (B, C, D, E, F, G, H, I, J, K, L, M) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H, I, J, K, L, M), - N + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + N ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H, I, J, K, L), - (M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - A, - (B, C, D, E, F, G, H, I, J, K, L, M, N) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - O + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + O ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I, J, K, L), - (M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - A, - (B, C, D, E, F, G, H, I, J, K, L, M, N, O) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - P + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + P ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J, K, L), - (M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - A, - (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - Q + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + Q ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K, L), - (M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - A, - (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), - R + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q), + R ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), - (Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), + (Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), - (P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), + (P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L, M, N), - (O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M, N), + (O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L, M), - (N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L, M), + (N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K, L), - (M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K, L), + (M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J, K), - (L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J, K), + (L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I, J), - (K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I, J), + (K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H, I), - (J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H, I), + (J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G, H), - (I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G, H), + (I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F, G), - (H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F, G), + (H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E, F), - (G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E, F), + (G, H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D, E), - (F, G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D, E), + (F, G, H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C, D), - (E, F, G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C, D), + (E, F, G, H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B, C), - (D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B, C), + (D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - (A, B), - (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + (A, B), + (C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) ); impl_key_prefix_for!( - (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), - A, - (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) + (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R), + A, + (B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R) ); From c3e4b9fa32202cf3c08d397e00a45a1702c83711 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 17:00:05 -0700 Subject: [PATCH 18/34] Add tests for StorageNMap in FRAMEv2 pallet macro --- .../procedural/src/pallet/expand/storage.rs | 4 +- .../support/procedural/src/storage/getters.rs | 4 +- frame/support/test/tests/pallet.rs | 83 +++++++++++++++++++ frame/support/test/tests/pallet_instance.rs | 69 +++++++++++++++ 4 files changed, 158 insertions(+), 2 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 386bc59e6a0d2..50a9ad4c706f0 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -274,7 +274,9 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #( #docs )* pub fn #getter(key: KArg) -> #query where - KArg: #frame_support::codec::EncodeLike<<#keygen as KeyGenerator>::KArg> + KArg: #frame_support::codec::EncodeLike< + <#keygen as #frame_support::storage::types::KeyGenerator>::KArg + > + #frame_support::storage::types::TupleToEncodedIter, { < diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 8b27af51226db..b307fec1cca6f 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -77,7 +77,9 @@ pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { quote!{ pub fn #get_fn(key: KArg) -> #value where - KArg: #scrate::codec::EncodeLike<<#keygen as KeyGenerator>::KArg> + KArg: #scrate::codec::EncodeLike< + <#keygen as #scrate::storage::types::KeyGenerator>::KArg + > + #scrate::storage::types::TupleToEncodedIter, { <#storage_struct as #scrate::#storage_trait>::get(#key_arg) diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 8fc056a2f36a5..0ffd713427550 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -217,6 +217,19 @@ pub mod pallet { #[pallet::storage] pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; + #[pallet::storage] + pub type NMap = StorageNMap<_, storage::Key, u32>; + + #[pallet::storage] + pub type NMap2 = StorageNMap< + _, + ( + storage::Key, + storage::Key, + ), + u64, + >; + #[pallet::storage] #[pallet::getter(fn conditional_value)] #[cfg(feature = "conditional-storage")] @@ -239,6 +252,18 @@ pub mod pallet { u32, >; + #[cfg(feature = "conditional-storage")] + #[pallet::storage] + #[pallet::getter(fn conditional_nmap)] + pub type ConditionalNMap = StorageNMap< + _, + ( + storage::Key, + storage::Key, + ), + u32, + >; + #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { @@ -569,11 +594,25 @@ fn storage_expand() { assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + pallet::NMap::::insert((&1,), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u32)); + assert_eq!(&k[..32], &>::final_prefix()); + + pallet::NMap2::::insert((&1, &2), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap2")].concat(); + k.extend(1u16.using_encoded(twox_64_concat)); + k.extend(2u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u64)); + assert_eq!(&k[..32], &>::final_prefix()); + #[cfg(feature = "conditional-storage")] { pallet::ConditionalValue::::put(1); pallet::ConditionalMap::::insert(1, 2); pallet::ConditionalDoubleMap::::insert(1, 2, 3); + pallet::ConditionalNMap::::insert((1, 2), 3); } }) } @@ -699,6 +738,36 @@ fn metadata() { default: DecodeDifferent::Decoded(vec![0]), documentation: DecodeDifferent::Decoded(vec![]), }, + StorageEntryMetadata { + name: DecodeDifferent::Decoded("NMap".to_string()), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Decoded(vec!["u8".to_string()]), + hashers: DecodeDifferent::Decoded(vec![ + StorageHasher::Blake2_128Concat, + ]), + value: DecodeDifferent::Decoded("u32".to_string()), + }, + default: DecodeDifferent::Decoded(vec![0]), + documentation: DecodeDifferent::Decoded(vec![]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Decoded("NMap2".to_string()), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Decoded(vec![ + "u16".to_string(), + "u32".to_string(), + ]), + hashers: DecodeDifferent::Decoded(vec![ + StorageHasher::Twox64Concat, + StorageHasher::Blake2_128Concat, + ]), + value: DecodeDifferent::Decoded("u64".to_string()), + }, + default: DecodeDifferent::Decoded(vec![0]), + documentation: DecodeDifferent::Decoded(vec![]), + }, #[cfg(feature = "conditional-storage")] StorageEntryMetadata { name: DecodeDifferent::Decoded("ConditionalValue".to_string()), modifier: StorageEntryModifier::Optional, @@ -731,6 +800,20 @@ fn metadata() { default: DecodeDifferent::Decoded(vec![0]), documentation: DecodeDifferent::Decoded(vec![]), }, + #[cfg(feature = "conditional-storage")] StorageEntryMetadata { + name: DecodeDifferent::Decoded("ConditionalNMap".to_string()), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Decoded(vec!["u8".to_string(), "u16".to_string()]), + hashers: DecodeDifferent::Decoded(vec![ + StorageHasher::Blake2_128Concat, + StorageHasher::Twox64Concat, + ]), + value: DecodeDifferent::Decoded("u32".to_string()), + }, + default: DecodeDifferent::Decoded(vec![0]), + documentation: DecodeDifferent::Decoded(vec![]), + }, ]), })), calls: Some(DecodeDifferent::Decoded(vec![ diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 232a25ff5bf27..dc2c967add67d 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -134,6 +134,19 @@ pub mod pallet { pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; + #[pallet::storage] + pub type NMap = StorageNMap<_, storage::Key, u32>; + + #[pallet::storage] + pub type NMap2 = StorageNMap< + _, + ( + storage::Key, + storage::Key, + ), + u64, + >; + #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { @@ -447,6 +460,19 @@ fn storage_expand() { k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1,), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u32)); + assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1, &2), &3); + let mut k = [twox_128(b"Example"), twox_128(b"NMap2")].concat(); + k.extend(1u16.using_encoded(twox_64_concat)); + k.extend(2u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u64)); + assert_eq!(&k[..32], &>::final_prefix()); }); TestExternalities::default().execute_with(|| { @@ -479,6 +505,19 @@ fn storage_expand() { k.extend(2u32.using_encoded(blake2_128_concat)); assert_eq!(unhashed::get::(&k), Some(3u64)); assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1,), &3); + let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap")].concat(); + k.extend(1u8.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u32)); + assert_eq!(&k[..32], &>::final_prefix()); + + >::insert((&1, &2), &3); + let mut k = [twox_128(b"Instance1Example"), twox_128(b"NMap2")].concat(); + k.extend(1u16.using_encoded(twox_64_concat)); + k.extend(2u32.using_encoded(blake2_128_concat)); + assert_eq!(unhashed::get::(&k), Some(3u64)); + assert_eq!(&k[..32], &>::final_prefix()); }); } @@ -617,6 +656,36 @@ fn metadata() { default: DecodeDifferent::Decoded(vec![0]), documentation: DecodeDifferent::Decoded(vec![]), }, + StorageEntryMetadata { + name: DecodeDifferent::Decoded("NMap".to_string()), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Decoded(vec!["u8".to_string()]), + hashers: DecodeDifferent::Decoded(vec![ + StorageHasher::Blake2_128Concat, + ]), + value: DecodeDifferent::Decoded("u32".to_string()), + }, + default: DecodeDifferent::Decoded(vec![0]), + documentation: DecodeDifferent::Decoded(vec![]), + }, + StorageEntryMetadata { + name: DecodeDifferent::Decoded("NMap2".to_string()), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::NMap { + keys: DecodeDifferent::Decoded(vec![ + "u16".to_string(), + "u32".to_string(), + ]), + hashers: DecodeDifferent::Decoded(vec![ + StorageHasher::Twox64Concat, + StorageHasher::Blake2_128Concat, + ]), + value: DecodeDifferent::Decoded("u64".to_string()), + }, + default: DecodeDifferent::Decoded(vec![0]), + documentation: DecodeDifferent::Decoded(vec![]), + }, ]), })), calls: Some(DecodeDifferent::Decoded(vec![ From 55c85441ad0f631a177bf480be90eca517d75cf8 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 17:11:17 -0700 Subject: [PATCH 19/34] Small fixes to unit tests for StorageNMap --- frame/support/src/storage/generator/nmap.rs | 2 +- frame/support/src/storage/types/nmap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 4eee7a2c7417d..33f04ca8b0487 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -173,7 +173,7 @@ where KArg: EncodeLike + TupleToEncodedIter, VArg: EncodeLike, { - unhashed::put(&Self::storage_n_map_final_key::(key), &val.borrow()); + unhashed::put(&Self::storage_n_map_final_key::(key), &val); } fn remove + TupleToEncodedIter>(key: KArg) { diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 27542ba7d5f1f..e4fba90753d22 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -404,7 +404,7 @@ mod test { k.extend(&twox_128(b"test")); k.extend(&twox_128(b"foo")); k.extend(&3u16.blake2_128_concat()); - assert_eq!(A::hashed_key_for((3,)).to_vec(), k); + assert_eq!(A::hashed_key_for((&3,)).to_vec(), k); assert_eq!(A::contains_key((3,)), false); assert_eq!(A::get((3,)), None); From c0b1516097d5bade5ae3c542426e32ceb5f6a6ef Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 17:21:22 -0700 Subject: [PATCH 20/34] Bump runtime metadata version --- frame/metadata/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frame/metadata/src/lib.rs b/frame/metadata/src/lib.rs index a502af079862c..ba232a88f11c4 100644 --- a/frame/metadata/src/lib.rs +++ b/frame/metadata/src/lib.rs @@ -369,8 +369,10 @@ pub enum RuntimeMetadata { V10(RuntimeMetadataDeprecated), /// Version 11 for runtime metadata. No longer used. V11(RuntimeMetadataDeprecated), - /// Version 12 for runtime metadata. - V12(RuntimeMetadataV12), + /// Version 12 for runtime metadata. No longer used. + V12(RuntimeMetadataDeprecated), + /// Version 13 for runtime metadata. + V13(RuntimeMetadataV13), } /// Enum that should fail. @@ -394,7 +396,7 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, Serialize))] -pub struct RuntimeMetadataV12 { +pub struct RuntimeMetadataV13 { /// Metadata of all the modules. pub modules: DecodeDifferentArray, /// Metadata of the extrinsic. @@ -402,7 +404,7 @@ pub struct RuntimeMetadataV12 { } /// The latest version of the metadata. -pub type RuntimeMetadataLastVersion = RuntimeMetadataV12; +pub type RuntimeMetadataLastVersion = RuntimeMetadataV13; /// All metadata about an runtime module. #[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] @@ -430,6 +432,6 @@ impl Into for RuntimeMetadataPrefixed { impl Into for RuntimeMetadataLastVersion { fn into(self) -> RuntimeMetadataPrefixed { - RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V12(self)) + RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V13(self)) } } From fdc3e13087ed0dd8b0d883ff256d4a22efd3a31a Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 17:34:39 -0700 Subject: [PATCH 21/34] Remove unused import --- frame/support/src/storage/generator/nmap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 33f04ca8b0487..a76db6c5c6e7b 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -25,7 +25,6 @@ use crate::{ Never, }; use codec::{Decode, Encode, EncodeLike, FullCodec}; -use sp_std::borrow::Borrow; #[cfg(not(feature = "std"))] use sp_std::prelude::*; From c041a6c943de7aedca7032dc5e77795d80cc1029 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Mon, 26 Apr 2021 18:46:29 -0700 Subject: [PATCH 22/34] Update tests to use runtime metadata v13 --- frame/support/test/tests/construct_runtime.rs | 2 +- frame/support/test/tests/pallet.rs | 2 +- frame/support/test/tests/pallet_compatibility.rs | 2 +- frame/support/test/tests/pallet_compatibility_instance.rs | 2 +- frame/support/test/tests/pallet_instance.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index a1ec744e42733..76e28a3b152ff 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -505,7 +505,7 @@ fn test_metadata() { signed_extensions: vec![DecodeDifferent::Encode("UnitSignedExtension")], }, }; - pretty_assertions::assert_eq!(Runtime::metadata().1, RuntimeMetadata::V12(expected_metadata)); + pretty_assertions::assert_eq!(Runtime::metadata().1, RuntimeMetadata::V13(expected_metadata)); } #[test] diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 0ffd713427550..d969e23d85d47 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -931,7 +931,7 @@ fn metadata() { }; let metadata = match Runtime::metadata().1 { - RuntimeMetadata::V12(metadata) => metadata, + RuntimeMetadata::V13(metadata) => metadata, _ => panic!("metadata has been bump, test needs to be updated"), }; diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index a953b19607d90..130014f1e9eb1 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -266,7 +266,7 @@ mod test { fn metadata() { let metadata = Runtime::metadata(); let modules = match metadata.1 { - frame_metadata::RuntimeMetadata::V12(frame_metadata::RuntimeMetadataV12 { + frame_metadata::RuntimeMetadata::V13(frame_metadata::RuntimeMetadataV13 { modules: frame_metadata::DecodeDifferent::Encode(m), .. }) => m, diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 5ce20012c736d..d80d9ba3dff7d 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -281,7 +281,7 @@ mod test { fn metadata() { let metadata = Runtime::metadata(); let modules = match metadata.1 { - frame_metadata::RuntimeMetadata::V12(frame_metadata::RuntimeMetadataV12 { + frame_metadata::RuntimeMetadata::V13(frame_metadata::RuntimeMetadataV13 { modules: frame_metadata::DecodeDifferent::Encode(m), .. }) => m, diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index dc2c967add67d..906199091b0ee 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -765,7 +765,7 @@ fn metadata() { let metadata = match Runtime::metadata().1 { - RuntimeMetadata::V12(metadata) => metadata, + RuntimeMetadata::V13(metadata) => metadata, _ => panic!("metadata has been bump, test needs to be updated"), }; From ce13f5ed52f324aaaca6284bf4a12343d30f6819 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 28 Apr 2021 14:01:52 -0700 Subject: [PATCH 23/34] Introduce and use EncodeLikeTuple as a trait bound for KArg --- .../procedural/src/pallet/expand/storage.rs | 2 +- .../support/procedural/src/storage/getters.rs | 2 +- frame/support/src/storage/generator/nmap.rs | 39 ++++++++-------- frame/support/src/storage/mod.rs | 36 +++++++-------- frame/support/src/storage/types/key.rs | 44 ++++++++++++++++--- frame/support/src/storage/types/mod.rs | 4 +- frame/support/src/storage/types/nmap.rs | 39 ++++++++-------- 7 files changed, 102 insertions(+), 64 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 50a9ad4c706f0..709398c497aeb 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -274,7 +274,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { #( #docs )* pub fn #getter(key: KArg) -> #query where - KArg: #frame_support::codec::EncodeLike< + KArg: #frame_support::storage::types::EncodeLikeTuple< <#keygen as #frame_support::storage::types::KeyGenerator>::KArg > + #frame_support::storage::types::TupleToEncodedIter, diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index b307fec1cca6f..8cec7cc65e4b2 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -77,7 +77,7 @@ pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { quote!{ pub fn #get_fn(key: KArg) -> #value where - KArg: #scrate::codec::EncodeLike< + KArg: #scrate::storage::types::EncodeLikeTuple< <#keygen as #scrate::storage::types::KeyGenerator>::KArg > + #scrate::storage::types::TupleToEncodedIter, diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index a76db6c5c6e7b..0f4bbf8f67b8e 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -19,8 +19,11 @@ use crate::{ hash::{StorageHasher, Twox128}, storage::{ self, - types::{HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator}, - unhashed, PrefixIterator, StorageAppend, TupleToEncodedIter, + types::{ + EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, + ReversibleKeyGenerator, TupleToEncodedIter, + }, + unhashed, PrefixIterator, StorageAppend, }, Never, }; @@ -96,7 +99,7 @@ pub trait StorageNMap { fn storage_n_map_final_key(key: KArg) -> Vec where KG: KeyGenerator, - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); @@ -122,23 +125,23 @@ where { type Query = G::Query; - fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { Self::storage_n_map_final_key::(key) } - fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { unhashed::exists(&Self::storage_n_map_final_key::(key)) } - fn get + TupleToEncodedIter>(key: KArg) -> Self::Query { + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query { G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::(key))) } - fn try_get + TupleToEncodedIter>(key: KArg) -> Result { + fn try_get + TupleToEncodedIter>(key: KArg) -> Result { unhashed::get(&Self::storage_n_map_final_key::(key)).ok_or(()) } - fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query { let final_key = Self::storage_n_map_final_key::(key); let value = unhashed::take(&final_key); @@ -148,8 +151,8 @@ where fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter, + KArg1: EncodeLikeTuple + TupleToEncodedIter, + KArg2: EncodeLikeTuple + TupleToEncodedIter, { let final_x_key = Self::storage_n_map_final_key::(key1); let final_y_key = Self::storage_n_map_final_key::(key2); @@ -169,13 +172,13 @@ where fn insert(key: KArg, val: VArg) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, VArg: EncodeLike, { unhashed::put(&Self::storage_n_map_final_key::(key), &val); } - fn remove + TupleToEncodedIter>(key: KArg) { + fn remove + TupleToEncodedIter>(key: KArg) { unhashed::kill(&Self::storage_n_map_final_key::(key)); } @@ -201,7 +204,7 @@ where fn mutate(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Self::Query) -> R, { Self::try_mutate(key, |v| Ok::(f(v))) @@ -210,7 +213,7 @@ where fn try_mutate(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Self::Query) -> Result { let final_key = Self::storage_n_map_final_key::(key); @@ -228,7 +231,7 @@ where fn mutate_exists(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> R, { Self::try_mutate_exists(key, |v| Ok::(f(v))) @@ -237,7 +240,7 @@ where fn try_mutate_exists(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> Result, { let final_key = Self::storage_n_map_final_key::(key); @@ -255,7 +258,7 @@ where fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend, @@ -266,7 +269,7 @@ where fn migrate_keys(key: KArg, hash_fns: K::HArg) -> Option where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, { let old_key = { let module_prefix_hashed = Twox128::hash(Self::module_prefix()); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 24ad4a90a288c..7232087aaac54 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -23,8 +23,8 @@ use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode}; use crate::{ hash::{Twox128, StorageHasher, ReversibleStorageHasher}, storage::types::{ - HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, ReversibleKeyGenerator, - TupleToEncodedIter, + EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator, + ReversibleKeyGenerator, TupleToEncodedIter, }, traits::Get, }; @@ -557,34 +557,34 @@ pub trait StorageNMap { type Query; /// Get the storage key used to fetch a value corresponding to a specific key. - fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec; + fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec; /// Does the value (explicitly) exist in storage? - fn contains_key + TupleToEncodedIter>(key: KArg) -> bool; + fn contains_key + TupleToEncodedIter>(key: KArg) -> bool; /// Load the value associated with the given key from the map. - fn get + TupleToEncodedIter>(key: KArg) -> Self::Query; + fn get + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - fn try_get + TupleToEncodedIter>(key: KArg) -> Result; + fn try_get + TupleToEncodedIter>(key: KArg) -> Result; /// Swap the values of two keys. fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter; + KArg1: EncodeLikeTuple + TupleToEncodedIter, + KArg2: EncodeLikeTuple + TupleToEncodedIter; /// Store a value to be associated with the given key from the map. fn insert(key: KArg, val: VArg) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, VArg: EncodeLike; /// Remove the value under a key. - fn remove + TupleToEncodedIter>(key: KArg); + fn remove + TupleToEncodedIter>(key: KArg); /// Remove all values under the partial prefix key. fn remove_prefix(partial_key: KP) where K: HasKeyPrefix; @@ -595,13 +595,13 @@ pub trait StorageNMap { /// Mutate the value under a key. fn mutate(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Self::Query) -> R; /// Mutate the item, only if an `Ok` value is returned. fn try_mutate(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Self::Query) -> Result; /// Mutate the value under a key. @@ -609,17 +609,17 @@ pub trait StorageNMap { /// Deletes the item if mutated to a `None`. fn mutate_exists(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. fn try_mutate_exists(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> Result; /// Take the value under a key. - fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; + fn take + TupleToEncodedIter>(key: KArg) -> Self::Query; /// Append the given items to the value in the storage. /// @@ -632,7 +632,7 @@ pub trait StorageNMap { /// on overwrite. fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, V: StorageAppend; @@ -649,7 +649,7 @@ pub trait StorageNMap { /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - fn decode_len + TupleToEncodedIter>(key: KArg) -> Option + fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where V: StorageDecodeLength, { @@ -661,7 +661,7 @@ pub trait StorageNMap { /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. fn migrate_keys(key: KArg, hash_fns: K::HArg) -> Option where - KArg: EncodeLike + TupleToEncodedIter; + KArg: EncodeLikeTuple + TupleToEncodedIter; } /// Iterate over a prefix and decode raw_key and raw_value into `T`. diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index d0fb0fd1cd8b9..65b15756a17bd 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -40,8 +40,8 @@ pub trait KeyGenerator { type HashFn: FnOnce(&[u8]) -> Vec; type HArg; - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; - fn migrate_key + TupleToEncodedIter>( + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + fn migrate_key + TupleToEncodedIter>( key: &KArg, hash_fns: Self::HArg, ) -> Vec; @@ -58,7 +58,7 @@ impl KeyGenerator for Key { type HashFn = Box Vec>; type HArg = (Self::HashFn,); - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { H::hash( &key.to_encoded_iter() .next() @@ -68,7 +68,7 @@ impl KeyGenerator for Key { .to_vec() } - fn migrate_key + TupleToEncodedIter>( + fn migrate_key + TupleToEncodedIter>( key: &KArg, hash_fns: Self::HArg, ) -> Vec { @@ -94,7 +94,7 @@ impl KeyGenerator for Tuple { for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); type HashFn = Box Vec>; - fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { let mut final_key = Vec::new(); let mut iter = key.to_encoded_iter(); for_tuples!( @@ -106,7 +106,7 @@ impl KeyGenerator for Tuple { final_key } - fn migrate_key + TupleToEncodedIter>( + fn migrate_key + TupleToEncodedIter>( key: &KArg, hash_fns: Self::HArg, ) -> Vec { @@ -122,6 +122,38 @@ impl KeyGenerator for Tuple { } } +/// Marker trait to indicate that each element in the tuple encodes like the +/// corresponding element in another tuple. +pub trait EncodeLikeTuple {} + +macro_rules! impl_encode_like_tuples { + ($($elem:ident),+) => { + paste! { + impl<$($elem: Encode,)+ $([<$elem $elem>]: Encode + EncodeLike<$elem>,)+> + EncodeLikeTuple<($($elem,)+)> for + ($([<$elem $elem>],)+) {} + } + }; +} + +impl_encode_like_tuples!(A); +impl_encode_like_tuples!(A, B); +impl_encode_like_tuples!(A, B, C); +impl_encode_like_tuples!(A, B, C, D); +impl_encode_like_tuples!(A, B, C, D, E); +impl_encode_like_tuples!(A, B, C, D, E, F); +impl_encode_like_tuples!(A, B, C, D, E, F, G); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M); +impl_encode_like_tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, O); +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, R); + /// Trait to indicate that a tuple can be converted into an iterator of a vector of encoded bytes. pub trait TupleToEncodedIter { fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; diff --git a/frame/support/src/storage/types/mod.rs b/frame/support/src/storage/types/mod.rs index 001a6e1f23408..5b7aa61d37693 100644 --- a/frame/support/src/storage/types/mod.rs +++ b/frame/support/src/storage/types/mod.rs @@ -29,8 +29,8 @@ mod value; pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata}; pub use key::{ - HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, ReversibleKeyGenerator, - TupleToEncodedIter, + EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator, + ReversibleKeyGenerator, TupleToEncodedIter, }; pub use map::{StorageMap, StorageMapMetadata}; pub use nmap::{StorageNMap, StorageNMapMetadata}; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index e4fba90753d22..6e29c05b1d9b8 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -20,8 +20,11 @@ use crate::{ storage::{ - types::{HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter, OptionQuery, QueryKindTrait}, - KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, TupleToEncodedIter, + types::{ + EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter, + OptionQuery, QueryKindTrait, TupleToEncodedIter, + }, + KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, }, traits::{GetDefault, StorageInstance}, }; @@ -101,31 +104,31 @@ where OnEmpty: crate::traits::Get + 'static, { /// Get the storage key used to fetch a value corresponding to a specific key. - pub fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { + pub fn hashed_key_for + TupleToEncodedIter>(key: KArg) -> Vec { >::hashed_key_for(key) } /// Does the value (explicitly) exist in storage? - pub fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { + pub fn contains_key + TupleToEncodedIter>(key: KArg) -> bool { >::contains_key(key) } /// Load the value associated with the given key from the map. - pub fn get + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { + pub fn get + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::get(key) } /// Try to get the value for the given key from the map. /// /// Returns `Ok` if it exists, `Err` if not. - pub fn try_get + TupleToEncodedIter>( + pub fn try_get + TupleToEncodedIter>( key: KArg, ) -> Result { >::try_get(key) } /// Take a value from storage, removing it afterwards. - pub fn take + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { + pub fn take + TupleToEncodedIter>(key: KArg) -> QueryKind::Query { >::take(key) } @@ -133,8 +136,8 @@ where pub fn swap(key1: KArg1, key2: KArg2) where KOther: KeyGenerator, - KArg1: EncodeLike + TupleToEncodedIter, - KArg2: EncodeLike + TupleToEncodedIter, + KArg1: EncodeLikeTuple + TupleToEncodedIter, + KArg2: EncodeLikeTuple + TupleToEncodedIter, { >::swap::(key1, key2) } @@ -142,14 +145,14 @@ where /// Store a value to be associated with the given keys from the map. pub fn insert(key: KArg, val: VArg) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, VArg: EncodeLike, { >::insert(key, val) } /// Remove the value under the given keys. - pub fn remove + TupleToEncodedIter>(key: KArg) { + pub fn remove + TupleToEncodedIter>(key: KArg) { >::remove(key) } @@ -172,7 +175,7 @@ where /// Mutate the value under the given keys. pub fn mutate(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> R, { >::mutate(key, f) @@ -181,7 +184,7 @@ where /// Mutate the value under the given keys when the closure returns `Ok`. pub fn try_mutate(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut QueryKind::Query) -> Result, { >::try_mutate(key, f) @@ -190,7 +193,7 @@ where /// Mutate the value under the given keys. Deletes the item if mutated to a `None`. pub fn mutate_exists(key: KArg, f: F) -> R where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> R, { >::mutate_exists(key, f) @@ -199,7 +202,7 @@ where /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. pub fn try_mutate_exists(key: KArg, f: F) -> Result where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, F: FnOnce(&mut Option) -> Result, { >::try_mutate_exists(key, f) @@ -216,7 +219,7 @@ where /// on overwrite. pub fn append(key: KArg, item: EncodeLikeItem) where - KArg: EncodeLike + TupleToEncodedIter, + KArg: EncodeLikeTuple + TupleToEncodedIter, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend, @@ -236,7 +239,7 @@ where /// /// `None` does not mean that `get()` does not return a value. The default value is completly /// ignored by this function. - pub fn decode_len + TupleToEncodedIter>(key: KArg) -> Option + pub fn decode_len + TupleToEncodedIter>(key: KArg) -> Option where Value: StorageDecodeLength, { @@ -248,7 +251,7 @@ where /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. pub fn migrate_keys(key: KArg, hash_fns: Key::HArg) -> Option where - KArg: EncodeLike + TupleToEncodedIter + KArg: EncodeLikeTuple + TupleToEncodedIter { >::migrate_keys::<_>(key, hash_fns) } From 1aeda765870aaf27a7cb6140862aa7fcaa262c45 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 29 Apr 2021 19:00:37 -0700 Subject: [PATCH 24/34] Add some rustdocs --- frame/support/src/storage/generator/nmap.rs | 2 +- frame/support/src/storage/types/key.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 0f4bbf8f67b8e..1b926cc3f7182 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -31,7 +31,7 @@ use codec::{Decode, Encode, EncodeLike, FullCodec}; #[cfg(not(feature = "std"))] use sp_std::prelude::*; -/// Generator for `StorageNMap` used by `decl_storage`. +/// Generator for `StorageNMap` used by `decl_storage` and storage types. /// /// By default each key value is stored at: /// ```nocompile diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 65b15756a17bd..99ccefead216a 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -40,7 +40,11 @@ pub trait KeyGenerator { type HashFn: FnOnce(&[u8]) -> Vec; type HArg; + /// Given a `key` tuple, calculate the final key by encoding each element individuallly and + /// hashing them using the corresponding hasher in the `KeyGenerator`. fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; + /// Given a `key` tuple, migrate the keys from using the old hashers as given by `hash_fns` + /// to using the newer hashers as specified by this `KeyGenerator`. fn migrate_key + TupleToEncodedIter>( key: &KArg, hash_fns: Self::HArg, From 3671857aec8fec477322a5e5b18fd3e5a13e3146 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 29 Apr 2021 19:54:36 -0700 Subject: [PATCH 25/34] Revert usage of StorageNMap in assets pallet --- frame/assets/src/lib.rs | 42 ++++++++++++++++++++------------------- frame/assets/src/types.rs | 9 +++++++++ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index 0c14e917b4307..e8dfd50f4086a 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -158,7 +158,6 @@ pub use pallet::*; pub mod pallet { use frame_support::{ dispatch::DispatchResult, - storage, pallet_prelude::*, }; use frame_system::pallet_prelude::*; @@ -238,13 +237,12 @@ pub mod pallet { #[pallet::storage] /// Approved balance transfers. First balance is the amount approved for transfer. Second /// is the amount of `T::Currency` reserved for storing this. - pub(super) type Approvals, I: 'static = ()> = StorageNMap< + pub(super) type Approvals, I: 'static = ()> = StorageDoubleMap< _, - ( - storage::Key, - storage::Key, - storage::Key, - ), + Blake2_128Concat, + T::AssetId, + Blake2_128Concat, + ApprovalKey, Approval>, OptionQuery, >; @@ -506,7 +504,7 @@ pub mod pallet { details.deposit.saturating_add(metadata.deposit), ); - Approvals::::remove_prefix((id,)); + Approvals::::remove_prefix(&id); Self::deposit_event(Event::Destroyed(id)); // NOTE: could use postinfo to reflect the actual number of accounts/sufficient/approvals @@ -1122,18 +1120,19 @@ pub mod pallet { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - Approvals::::try_mutate((id, &owner, &delegate), |maybe_approved| -> DispatchResult { + let key = ApprovalKey { owner, delegate }; + Approvals::::try_mutate(id, &key, |maybe_approved| -> DispatchResult { let mut approved = maybe_approved.take().unwrap_or_default(); let deposit_required = T::ApprovalDeposit::get(); if approved.deposit < deposit_required { - T::Currency::reserve(&owner, deposit_required - approved.deposit)?; + T::Currency::reserve(&key.owner, deposit_required - approved.deposit)?; approved.deposit = deposit_required; } approved.amount = approved.amount.saturating_add(amount); *maybe_approved = Some(approved); Ok(()) })?; - Self::deposit_event(Event::ApprovedTransfer(id, owner, delegate, amount)); + Self::deposit_event(Event::ApprovedTransfer(id, key.owner, key.delegate, amount)); Ok(()) } @@ -1159,10 +1158,11 @@ pub mod pallet { ) -> DispatchResult { let owner = ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; - let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; - T::Currency::unreserve(&owner, approval.deposit); + let key = ApprovalKey { owner, delegate }; + let approval = Approvals::::take(id, &key).ok_or(Error::::Unknown)?; + T::Currency::unreserve(&key.owner, approval.deposit); - Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); + Self::deposit_event(Event::ApprovalCancelled(id, key.owner, key.delegate)); Ok(()) } @@ -1198,10 +1198,11 @@ pub mod pallet { let owner = T::Lookup::lookup(owner)?; let delegate = T::Lookup::lookup(delegate)?; - let approval = Approvals::::take((id, &owner, &delegate)).ok_or(Error::::Unknown)?; - T::Currency::unreserve(&owner, approval.deposit); + let key = ApprovalKey { owner, delegate }; + let approval = Approvals::::take(id, &key).ok_or(Error::::Unknown)?; + T::Currency::unreserve(&key.owner, approval.deposit); - Self::deposit_event(Event::ApprovalCancelled(id, owner, delegate)); + Self::deposit_event(Event::ApprovalCancelled(id, key.owner, key.delegate)); Ok(()) } @@ -1235,7 +1236,8 @@ pub mod pallet { let owner = T::Lookup::lookup(owner)?; let destination = T::Lookup::lookup(destination)?; - Approvals::::try_mutate_exists((id, &owner, delegate), |maybe_approved| -> DispatchResult { + let key = ApprovalKey { owner, delegate }; + Approvals::::try_mutate_exists(id, &key, |maybe_approved| -> DispatchResult { let mut approved = maybe_approved.take().ok_or(Error::::Unapproved)?; let remaining = approved .amount @@ -1247,10 +1249,10 @@ pub mod pallet { best_effort: false, burn_dust: false }; - Self::do_transfer(id, &owner, &destination, amount, None, f)?; + Self::do_transfer(id, &key.owner, &destination, amount, None, f)?; if remaining.is_zero() { - T::Currency::unreserve(&owner, approved.deposit); + T::Currency::unreserve(&key.owner, approved.deposit); } else { approved.amount = remaining; *maybe_approved = Some(approved); diff --git a/frame/assets/src/types.rs b/frame/assets/src/types.rs index 0cfcb64e137f2..f3f17c00a218f 100644 --- a/frame/assets/src/types.rs +++ b/frame/assets/src/types.rs @@ -65,6 +65,15 @@ impl AssetDetails { + /// The owner of the funds that are being approved. + pub(super) owner: AccountId, + /// The party to whom transfer of the funds is being delegated. + pub(super) delegate: AccountId, +} + /// Data concerning an approval. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] pub struct Approval { From 707cf4526331aa4d0bc71102c8ca240a9e222fe9 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 29 Apr 2021 22:11:35 -0700 Subject: [PATCH 26/34] Make use of ext::PunctuatedTrailing --- frame/support/procedural/src/storage/parse.rs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/frame/support/procedural/src/storage/parse.rs b/frame/support/procedural/src/storage/parse.rs index 1c3c9c0ebf6d7..93a1b844a84a2 100644 --- a/frame/support/procedural/src/storage/parse.rs +++ b/frame/support/procedural/src/storage/parse.rs @@ -18,7 +18,7 @@ //! Parsing of decl_storage input. use frame_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; -use syn::{Ident, Token, punctuated::Punctuated, spanned::Spanned}; +use syn::{Ident, Token, spanned::Spanned}; mod keyword { syn::custom_keyword!(hiddencrate); @@ -245,25 +245,14 @@ struct DeclStorageKey { pub key: syn::Type, } -#[derive(ToTokens, Debug)] +#[derive(Parse, ToTokens, Debug)] struct DeclStorageNMap { pub map_keyword: keyword::nmap, - pub storage_keys: Punctuated, + pub storage_keys: ext::PunctuatedTrailing, pub ass_keyword: Token![=>], pub value: syn::Type, } -impl syn::parse::Parse for DeclStorageNMap { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - Ok(DeclStorageNMap { - map_keyword: input.parse()?, - storage_keys: >::parse_separated_nonempty(input)?, - ass_keyword: input.parse()?, - value: input.parse()?, - }) - } -} - #[derive(Clone, ToTokens, Debug)] enum Hasher { Blake2_256(keyword::opaque_blake2_256), @@ -528,10 +517,11 @@ fn parse_storage_line_defs( super::NMapDef { hashers: map .storage_keys + .inner .iter() .map(|pair| Ok(pair.hasher.inner.clone().ok_or_else(no_hasher_error)?.into())) .collect::, syn::Error>>()?, - keys: map.storage_keys.iter().map(|pair| pair.key.clone()).collect(), + keys: map.storage_keys.inner.iter().map(|pair| pair.key.clone()).collect(), value: map.value, } ), From 2ff4de0594285cb8c1d0cfd0ef92eefd328facb7 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 12 May 2021 10:45:48 -0700 Subject: [PATCH 27/34] Add rustdoc for final_hash --- frame/support/src/storage/types/key.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 99ccefead216a..a00159c5b4ece 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -53,6 +53,7 @@ pub trait KeyGenerator { /// A trait containing methods that are only implemented on the Key struct instead of the entire tuple. pub trait KeyGeneratorInner: KeyGenerator { + /// Hash a given `encoded` byte slice using the `KeyGenerator`'s associated `StorageHasher`. fn final_hash(encoded: &[u8]) -> Vec; } From f75bc5a8cb66e565e1494ef15cbb5d67d15ba10f Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 12 May 2021 15:02:54 -0700 Subject: [PATCH 28/34] Fix StorageNMap proc macro expansions for single key cases --- .../support/procedural/src/pallet/expand/storage.rs | 9 ++------- .../src/storage/genesis_config/builder_def.rs | 5 +---- frame/support/procedural/src/storage/getters.rs | 7 +------ frame/support/src/storage/types/key.rs | 12 ++++++++++-- frame/support/test/tests/pallet.rs | 2 ++ frame/support/test/tests/pallet_instance.rs | 2 ++ 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 709398c497aeb..3ca250a6288c7 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -256,18 +256,13 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { } ) }, - Metadata::NMap { keys, keygen, value, .. } => { + Metadata::NMap { 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::ValueQuery => quote::quote!(#value), }; - let key_arg = if keys.len() == 1 { - quote::quote!((key,)) - } else { - quote::quote!(key) - }; quote::quote_spanned!(storage.attr_span => #(#cfg_attrs)* impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause { @@ -282,7 +277,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { < #full_ident as #frame_support::storage::StorageNMap<#keygen, #value> - >::get(#key_arg) + >::get(key) } } ) diff --git a/frame/support/procedural/src/storage/genesis_config/builder_def.rs b/frame/support/procedural/src/storage/genesis_config/builder_def.rs index a2a4f1ff15f65..5b73928951cfa 100644 --- a/frame/support/procedural/src/storage/genesis_config/builder_def.rs +++ b/frame/support/procedural/src/storage/genesis_config/builder_def.rs @@ -121,7 +121,6 @@ impl BuilderDef { }} }, StorageLineTypeDef::NMap(map) => { - let keygen = map.to_keygen_struct(scrate); let key_tuple = map.to_key_tuple(); let key_arg = if map.keys.len() == 1 { quote!((k,)) @@ -132,9 +131,7 @@ impl BuilderDef { #data let data: &#scrate::sp_std::vec::Vec<(#key_tuple, #value_type)> = data; data.iter().for_each(|(k, v)| { - <#storage_struct as #scrate::#storage_trait>::insert::< - &#keygen, &#value_type - >(#key_arg, v); + <#storage_struct as #scrate::#storage_trait>::insert(#key_arg, v); }); }} }, diff --git a/frame/support/procedural/src/storage/getters.rs b/frame/support/procedural/src/storage/getters.rs index 8cec7cc65e4b2..32155239acdc6 100644 --- a/frame/support/procedural/src/storage/getters.rs +++ b/frame/support/procedural/src/storage/getters.rs @@ -69,11 +69,6 @@ pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { StorageLineTypeDef::NMap(map) => { let keygen = map.to_keygen_struct(&def.hidden_crate); let value = &map.value; - let key_arg = if map.keys.len() == 1 { - quote!((key,)) - } else { - quote!(key) - }; quote!{ pub fn #get_fn(key: KArg) -> #value where @@ -82,7 +77,7 @@ pub fn impl_getters(def: &DeclStorageDefExt) -> TokenStream { > + #scrate::storage::types::TupleToEncodedIter, { - <#storage_struct as #scrate::#storage_trait>::get(#key_arg) + <#storage_struct as #scrate::#storage_trait>::get(key) } } } diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index a00159c5b4ece..9b3bee1e6f1a2 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -137,6 +137,9 @@ macro_rules! impl_encode_like_tuples { impl<$($elem: Encode,)+ $([<$elem $elem>]: Encode + EncodeLike<$elem>,)+> EncodeLikeTuple<($($elem,)+)> for ($([<$elem $elem>],)+) {} + impl<$($elem: Encode,)+ $([<$elem $elem>]: Encode + EncodeLike<$elem>,)+> + EncodeLikeTuple<($($elem,)+)> for + &($([<$elem $elem>],)+) {} } }; } @@ -171,9 +174,8 @@ impl TupleToEncodedIter for (A,) { } #[impl_trait_for_tuples::impl_for_tuples(2, 18)] -#[tuple_types_no_default_trait_bound] +#[tuple_types_custom_trait_bound(Encode)] impl TupleToEncodedIter for Tuple { - for_tuples!( where #(Tuple: Encode),* ); fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { [for_tuples!( #(self.Tuple.encode()),* )] .to_vec() @@ -181,6 +183,12 @@ impl TupleToEncodedIter for Tuple { } } +impl TupleToEncodedIter for &T { + fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { + (*self).to_encoded_iter() + } +} + /// A trait that indicates the hashers for the keys generated are all reversible. pub trait ReversibleKeyGenerator: KeyGenerator { type Hasher; diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 11ebcb669669a..6bb0ce7d2fbec 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -218,9 +218,11 @@ pub mod pallet { pub type DoubleMap2 = StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; #[pallet::storage] + #[pallet::getter(fn nmap)] pub type NMap = StorageNMap<_, storage::Key, u32>; #[pallet::storage] + #[pallet::getter(fn nmap2)] pub type NMap2 = StorageNMap< _, ( diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 3d8c740ab3979..46ff301f6712d 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -135,9 +135,11 @@ pub mod pallet { StorageDoubleMap<_, Twox64Concat, u16, Blake2_128Concat, u32, u64>; #[pallet::storage] + #[pallet::getter(fn nmap)] pub type NMap = StorageNMap<_, storage::Key, u32>; #[pallet::storage] + #[pallet::getter(fn nmap2)] pub type NMap2 = StorageNMap< _, ( From 02b7ce3e03947cf1ab410438ec4eba2151d78f82 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 12 May 2021 16:04:19 -0700 Subject: [PATCH 29/34] Create associated const in KeyGenerator for hasher metadata --- .../procedural/src/pallet/expand/storage.rs | 16 +++------ .../procedural/src/pallet/parse/storage.rs | 34 ++++++------------- frame/support/src/storage/types/key.rs | 20 ++++++++--- frame/support/src/storage/types/nmap.rs | 2 ++ 4 files changed, 33 insertions(+), 39 deletions(-) diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 3ca250a6288c7..c78e93e1d6391 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -18,7 +18,6 @@ use crate::pallet::Def; use crate::pallet::parse::storage::{Metadata, QueryKind}; use frame_support_procedural_tools::clean_type_string; -use syn::spanned::Spanned; /// Generate the prefix_ident related the the storage. /// prefix_ident is used for the prefix struct to be given to storage as first generic param. @@ -131,27 +130,20 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { } ) }, - Metadata::NMap { keys, hashers, value, .. } => { + Metadata::NMap { keys, value, .. } => { let keys = keys .iter() .map(|key| clean_type_string("e::quote!(#key).to_string())) .collect::>(); - let hashers = hashers - .iter() - .map(|hasher| syn::Ident::new( - &clean_type_string("e::quote!(#hasher).to_string()), - hasher.span(), - )) - .collect::>(); let value = clean_type_string("e::quote!(#value).to_string()); quote::quote_spanned!(storage.attr_span => #frame_support::metadata::StorageEntryType::NMap { keys: #frame_support::metadata::DecodeDifferent::Encode(&[ #( #keys, )* ]), - hashers: #frame_support::metadata::DecodeDifferent::Encode(&[ - #( #frame_support::metadata::StorageHasher::#hashers, )* - ]), + hashers: #frame_support::metadata::DecodeDifferent::Encode( + <#full_ident as #metadata_trait>::HASHERS, + ), value: #frame_support::metadata::DecodeDifferent::Encode(#value), } ) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 36a92fd4670b8..9d49917535e58 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -60,7 +60,6 @@ pub enum Metadata { }, NMap { keys: Vec, - hashers: Vec, keygen: syn::GenericArgument, value: syn::GenericArgument, }, @@ -121,33 +120,30 @@ fn retrieve_arg( } } -/// Parse the 2nd type argument to `StorageNMap` and return its keys and hashers. -fn collect_keys_and_hashers( - keygen: &syn::GenericArgument, -) -> syn::Result<(Vec, Vec)> { +/// Parse the 2nd type argument to `StorageNMap` and return its keys. +fn collect_keys(keygen: &syn::GenericArgument) -> syn::Result> { if let syn::GenericArgument::Type(syn::Type::Tuple(tup)) = keygen { tup .elems .iter() - .try_fold((vec![], vec![]), |mut acc, ty| { - let (key, hasher) = extract_key_and_hasher(ty)?; + .try_fold(vec![], |mut acc, ty| { + let key = extract_key(ty)?; - acc.0.push(key); - acc.1.push(hasher); + acc.push(key); Ok(acc) }) } else if let syn::GenericArgument::Type(ty) = keygen { - let (key, hasher) = extract_key_and_hasher(ty)?; + let key = extract_key(ty)?; - Ok((vec![key], vec![hasher])) + Ok(vec![key]) } else { let msg = format!("Invalid pallet::storage, expected tuple of Key structs or Key struct"); Err(syn::Error::new(keygen.span(), msg)) } } -/// In `Key`, extract H and K and return (K, H). -fn extract_key_and_hasher(ty: &syn::Type) -> syn::Result<(syn::Type, syn::Type)> { +/// In `Key`, extract K and return it. +fn extract_key(ty: &syn::Type) -> syn::Result { let typ = if let syn::Type::Path(typ) = ty { typ } else { @@ -177,13 +173,6 @@ fn extract_key_and_hasher(ty: &syn::Type) -> syn::Result<(syn::Type, syn::Type)> return Err(syn::Error::new(ty_params.span(), msg)); } - let hasher = match &ty_params.args[0] { - syn::GenericArgument::Type(hasher_ty) => hasher_ty.clone(), - _ => { - let msg = format!("Invalid pallet::storage, expected type"); - return Err(syn::Error::new(ty_params.args[0].span(), msg)); - } - }; let key = match &ty_params.args[1] { syn::GenericArgument::Type(key_ty) => key_ty.clone(), _ => { @@ -192,7 +181,7 @@ fn extract_key_and_hasher(ty: &syn::Type) -> syn::Result<(syn::Type, syn::Type)> } }; - Ok((key, hasher)) + Ok(key) } impl StorageDef { @@ -260,10 +249,9 @@ impl StorageDef { "StorageNMap" => { query_kind = retrieve_arg(&typ.path.segments[0], 3); let keygen = retrieve_arg(&typ.path.segments[0], 1)?; - let (keys, hashers) = collect_keys_and_hashers(&keygen)?; + let keys = collect_keys(&keygen)?; Metadata::NMap { keys, - hashers, keygen, value: retrieve_arg(&typ.path.segments[0], 2)?, } diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 9b3bee1e6f1a2..b6c4f55434b28 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -40,6 +40,8 @@ pub trait KeyGenerator { type HashFn: FnOnce(&[u8]) -> Vec; type HArg; + const HASHER_METADATA: &'static [frame_metadata::StorageHasher]; + /// Given a `key` tuple, calculate the final key by encoding each element individuallly and /// hashing them using the corresponding hasher in the `KeyGenerator`. fn final_key + TupleToEncodedIter>(key: KArg) -> Vec; @@ -53,6 +55,8 @@ pub trait KeyGenerator { /// A trait containing methods that are only implemented on the Key struct instead of the entire tuple. pub trait KeyGeneratorInner: KeyGenerator { + type Hasher: StorageHasher; + /// Hash a given `encoded` byte slice using the `KeyGenerator`'s associated `StorageHasher`. fn final_hash(encoded: &[u8]) -> Vec; } @@ -63,6 +67,8 @@ impl KeyGenerator for Key { type HashFn = Box Vec>; type HArg = (Self::HashFn,); + const HASHER_METADATA: &'static [frame_metadata::StorageHasher] = &[H::METADATA]; + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { H::hash( &key.to_encoded_iter() @@ -86,6 +92,8 @@ impl KeyGenerator for Key { } impl KeyGeneratorInner for Key { + type Hasher = H; + fn final_hash(encoded: &[u8]) -> Vec { H::hash(encoded).as_ref().to_vec() } @@ -99,6 +107,10 @@ impl KeyGenerator for Tuple { for_tuples!( type HArg = ( #(Tuple::HashFn),* ); ); type HashFn = Box Vec>; + const HASHER_METADATA: &'static [frame_metadata::StorageHasher] = &[ + for_tuples!( #(Tuple::Hasher::METADATA),* ) + ]; + fn final_key + TupleToEncodedIter>(key: KArg) -> Vec { let mut final_key = Vec::new(); let mut iter = key.to_encoded_iter(); @@ -191,15 +203,15 @@ impl TupleToEncodedIter for &T { /// A trait that indicates the hashers for the keys generated are all reversible. pub trait ReversibleKeyGenerator: KeyGenerator { - type Hasher; + type ReversibleHasher; fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>; } impl ReversibleKeyGenerator for Key { - type Hasher = H; + type ReversibleHasher = H; fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> { - let mut current_key_material = Self::Hasher::reverse(key_material); + let mut current_key_material = Self::ReversibleHasher::reverse(key_material); let key = K::decode(&mut current_key_material)?; Ok((key, current_key_material)) } @@ -208,7 +220,7 @@ impl ReversibleKeyGenerator for Key Result<(Self::Key, &[u8]), codec::Error> { let mut current_key_material = key_material; diff --git a/frame/support/src/storage/types/nmap.rs b/frame/support/src/storage/types/nmap.rs index 6e29c05b1d9b8..1a2b6d4d55dcc 100755 --- a/frame/support/src/storage/types/nmap.rs +++ b/frame/support/src/storage/types/nmap.rs @@ -352,6 +352,7 @@ pub trait StorageNMapMetadata { const MODIFIER: StorageEntryModifier; const NAME: &'static str; const DEFAULT: DefaultByteGetter; + const HASHERS: &'static [frame_metadata::StorageHasher]; } impl StorageNMapMetadata @@ -368,6 +369,7 @@ where const DEFAULT: DefaultByteGetter = DefaultByteGetter( &OnEmptyGetter::(core::marker::PhantomData), ); + const HASHERS: &'static [frame_metadata::StorageHasher] = Key::HASHER_METADATA; } #[cfg(test)] From e142267268dfe8023f811fd36c2265c4079a1757 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 13 May 2021 11:09:58 -0700 Subject: [PATCH 30/34] Refactor code according to comments from Basti --- .../procedural/src/pallet/parse/storage.rs | 22 +++++++------------ frame/support/procedural/src/storage/mod.rs | 5 ++--- frame/support/src/storage/generator/nmap.rs | 2 +- frame/support/src/storage/types/key.rs | 8 +------ 4 files changed, 12 insertions(+), 25 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 9d49917535e58..076d90c65a546 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -126,16 +126,10 @@ fn collect_keys(keygen: &syn::GenericArgument) -> syn::Result> { tup .elems .iter() - .try_fold(vec![], |mut acc, ty| { - let key = extract_key(ty)?; - - acc.push(key); - Ok(acc) - }) + .map(extract_key) + .collect::>>() } else if let syn::GenericArgument::Type(ty) = keygen { - let key = extract_key(ty)?; - - Ok(vec![key]) + Ok(vec![extract_key(ty)?]) } else { let msg = format!("Invalid pallet::storage, expected tuple of Key structs or Key struct"); Err(syn::Error::new(keygen.span(), msg)) @@ -147,23 +141,23 @@ fn extract_key(ty: &syn::Type) -> syn::Result { let typ = if let syn::Type::Path(typ) = ty { typ } else { - let msg = format!("Invalid pallet::storage, expected type path"); + let msg = "Invalid pallet::storage, expected type path"; return Err(syn::Error::new(ty.span(), msg)); }; let key_struct = typ.path.segments.last().ok_or_else(|| { - let msg = format!("Invalid pallet::storage, expected type path with at least one segment"); + let msg = "Invalid pallet::storage, expected type path with at least one segment"; syn::Error::new(typ.path.span(), msg) })?; if key_struct.ident != "Key" { - let msg = format!("Invalid pallet::storage, expected Key struct"); + let msg = "Invalid pallet::storage, expected Key struct"; return Err(syn::Error::new(key_struct.ident.span(), msg)); } let ty_params = if let syn::PathArguments::AngleBracketed(args) = &key_struct.arguments { args } else { - let msg = format!("Invalid pallet::storage, expected angle bracketed arguments"); + let msg = "Invalid pallet::storage, expected angle bracketed arguments"; return Err(syn::Error::new(key_struct.arguments.span(), msg)); }; @@ -176,7 +170,7 @@ fn extract_key(ty: &syn::Type) -> syn::Result { let key = match &ty_params.args[1] { syn::GenericArgument::Type(key_ty) => key_ty.clone(), _ => { - let msg = format!("Invalid pallet::storage, expected type"); + let msg = "Invalid pallet::storage, expected type"; return Err(syn::Error::new(ty_params.args[1].span(), msg)); } }; diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 864179e4c6195..71bcf704f0d73 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -385,12 +385,12 @@ impl NMapDef { if self.keys.len() == 1 { let hasher = &self.hashers[0].to_storage_hasher_struct(); let key = &self.keys[0]; - return quote!( Key<#scrate::#hasher, #key> ); + return quote!( #scrate::storage::types::Key<#scrate::#hasher, #key> ); } let key_hasher = self.keys.iter().zip(&self.hashers).map(|(key, hasher)| { let hasher = hasher.to_storage_hasher_struct(); - quote!( Key<#scrate::#hasher, #key> ) + quote!( #scrate::storage::types::Key<#scrate::#hasher, #key> ) }) .collect::>(); quote!(( #(#key_hasher,)* )) @@ -480,7 +480,6 @@ pub fn decl_storage_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStr IterableStorageMap as _, IterableStorageNMap as _, IterableStorageDoubleMap as _, - storage::types::Key, }; #scrate_decl diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index 1b926cc3f7182..c3f0c556add39 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -35,7 +35,7 @@ use sp_std::prelude::*; /// /// By default each key value is stored at: /// ```nocompile -/// Twox128(module_prefix) ++ Twox128(storage_prefix) +/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) /// ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) ++ ... ++ HasherN(encode(keyN)) /// ``` /// diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index b6c4f55434b28..425210d17fa26 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -179,13 +179,7 @@ pub trait TupleToEncodedIter { fn to_encoded_iter(&self) -> sp_std::vec::IntoIter>; } -impl TupleToEncodedIter for (A,) { - fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { - vec![self.0.encode()].into_iter() - } -} - -#[impl_trait_for_tuples::impl_for_tuples(2, 18)] +#[impl_trait_for_tuples::impl_for_tuples(1, 18)] #[tuple_types_custom_trait_bound(Encode)] impl TupleToEncodedIter for Tuple { fn to_encoded_iter(&self) -> sp_std::vec::IntoIter> { From dbcb1f6c67d3fde671c823676cad6c6a176d2289 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 13 May 2021 11:14:09 -0700 Subject: [PATCH 31/34] Add module docs for generator/nmap.rs --- frame/support/src/storage/generator/nmap.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index c3f0c556add39..d1f00adda5e55 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -15,6 +15,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +//! Generator for `StorageNMap` used by `decl_storage` and storage types. +//! +//! By default each key value is stored at: +//! ```nocompile +//! Twox128(pallet_prefix) ++ Twox128(storage_prefix) +//! ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) ++ ... ++ HasherN(encode(keyN)) +//! ``` +//! +//! # Warning +//! +//! If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as +//! `blake2_256` must be used. Otherwise, other values in storage with the same prefix can +//! be compromised. + use crate::{ hash::{StorageHasher, Twox128}, storage::{ From d207d7719e4b9c686ffa9c251c0a92da0bee9ec3 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 13 May 2021 11:34:13 -0700 Subject: [PATCH 32/34] Re-export storage::Key as NMapKey in pallet prelude --- frame/support/procedural/src/pallet/parse/storage.rs | 4 ++-- frame/support/src/lib.rs | 5 ++++- frame/support/test/tests/pallet.rs | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index 076d90c65a546..80c2e10a25206 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -149,8 +149,8 @@ fn extract_key(ty: &syn::Type) -> syn::Result { let msg = "Invalid pallet::storage, expected type path with at least one segment"; syn::Error::new(typ.path.span(), msg) })?; - if key_struct.ident != "Key" { - let msg = "Invalid pallet::storage, expected Key struct"; + if key_struct.ident != "Key" && key_struct.ident != "NMapKey" { + let msg = "Invalid pallet::storage, expected Key or NMapKey struct"; return Err(syn::Error::new(key_struct.ident.span(), msg)); } diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index fc9536156731d..d87ab8e6ed460 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1237,7 +1237,10 @@ pub mod pallet_prelude { traits::{Get, Hooks, IsType, GetPalletVersion, EnsureOrigin, PalletInfoAccess}, dispatch::{DispatchResultWithPostInfo, Parameter, DispatchError, DispatchResult}, weights::{DispatchClass, Pays, Weight}, - storage::types::{StorageValue, StorageMap, StorageDoubleMap, StorageNMap, ValueQuery, OptionQuery}, + storage::types::{ + Key as NMapKey, StorageDoubleMap, StorageMap, StorageNMap, StorageValue, ValueQuery, + OptionQuery, + }, storage::bounded_vec::BoundedVec, }; pub use codec::{Encode, Decode}; diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 6bb0ce7d2fbec..5db5856fd9d97 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -226,8 +226,8 @@ pub mod pallet { pub type NMap2 = StorageNMap< _, ( - storage::Key, - storage::Key, + NMapKey, + NMapKey, ), u64, >; From f259f4693c863457d323f282cc0142ce499cd606 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 13 May 2021 14:57:41 -0700 Subject: [PATCH 33/34] Seal the EncodeLikeTuple trait --- frame/support/src/storage/types/key.rs | 36 ++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 425210d17fa26..7997471263614 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -139,9 +139,41 @@ impl KeyGenerator for Tuple { } } +mod private { + pub trait Sealed {} + + macro_rules! impl_sealed { + ($($elem:ident),+) => { + paste::paste! { + impl<$($elem,)+> Sealed for ($($elem,)+) {} + impl<$($elem,)+> Sealed for &($($elem,)+) {} + } + }; + } + + impl_sealed!(A); + impl_sealed!(A, B); + impl_sealed!(A, B, C); + impl_sealed!(A, B, C, D); + impl_sealed!(A, B, C, D, E); + impl_sealed!(A, B, C, D, E, F); + impl_sealed!(A, B, C, D, E, F, G); + impl_sealed!(A, B, C, D, E, F, G, H); + impl_sealed!(A, B, C, D, E, F, G, H, I); + impl_sealed!(A, B, C, D, E, F, G, H, I, J); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q); + impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R); +} + /// Marker trait to indicate that each element in the tuple encodes like the -/// corresponding element in another tuple. -pub trait EncodeLikeTuple {} +/// corresponding element in another tuple. This trait is sealed and cannot be +/// implemented by types outside of this crate. +pub trait EncodeLikeTuple: private::Sealed {} macro_rules! impl_encode_like_tuples { ($($elem:ident),+) => { From b081885b609906fd537f83e3bf4576d52e0503b0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Thu, 13 May 2021 23:37:14 -0700 Subject: [PATCH 34/34] Extract sealing code out of key.rs --- frame/support/src/storage/mod.rs | 29 ++++++++++++++++++- frame/support/src/storage/types/key.rs | 40 ++++---------------------- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 85fe4f6195e64..b779e064ac206 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -961,7 +961,7 @@ pub trait StorageDecodeLength: private::Sealed + codec::DecodeLength { } /// Provides `Sealed` trait to prevent implementing trait `StorageAppend` & `StorageDecodeLength` -/// outside of this crate. +/// & `EncodeLikeTuple` outside of this crate. mod private { use super::*; use bounded_vec::BoundedVec; @@ -973,6 +973,33 @@ mod private { impl Sealed for BoundedVec {} impl Sealed for bounded_btree_map::BoundedBTreeMap {} impl Sealed for bounded_btree_set::BoundedBTreeSet {} + + macro_rules! impl_sealed_for_tuple { + ($($elem:ident),+) => { + paste::paste! { + impl<$($elem: Encode,)+> Sealed for ($($elem,)+) {} + impl<$($elem: Encode,)+> Sealed for &($($elem,)+) {} + } + }; + } + + impl_sealed_for_tuple!(A); + impl_sealed_for_tuple!(A, B); + impl_sealed_for_tuple!(A, B, C); + impl_sealed_for_tuple!(A, B, C, D); + impl_sealed_for_tuple!(A, B, C, D, E); + impl_sealed_for_tuple!(A, B, C, D, E, F); + impl_sealed_for_tuple!(A, B, C, D, E, F, G); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q); + impl_sealed_for_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R); } impl StorageAppend for Vec {} diff --git a/frame/support/src/storage/types/key.rs b/frame/support/src/storage/types/key.rs index 7997471263614..fb3c69ff20cde 100755 --- a/frame/support/src/storage/types/key.rs +++ b/frame/support/src/storage/types/key.rs @@ -139,41 +139,11 @@ impl KeyGenerator for Tuple { } } -mod private { - pub trait Sealed {} - - macro_rules! impl_sealed { - ($($elem:ident),+) => { - paste::paste! { - impl<$($elem,)+> Sealed for ($($elem,)+) {} - impl<$($elem,)+> Sealed for &($($elem,)+) {} - } - }; - } - - impl_sealed!(A); - impl_sealed!(A, B); - impl_sealed!(A, B, C); - impl_sealed!(A, B, C, D); - impl_sealed!(A, B, C, D, E); - impl_sealed!(A, B, C, D, E, F); - impl_sealed!(A, B, C, D, E, F, G); - impl_sealed!(A, B, C, D, E, F, G, H); - impl_sealed!(A, B, C, D, E, F, G, H, I); - impl_sealed!(A, B, C, D, E, F, G, H, I, J); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q); - impl_sealed!(A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R); -} - -/// Marker trait to indicate that each element in the tuple encodes like the -/// corresponding element in another tuple. This trait is sealed and cannot be -/// implemented by types outside of this crate. -pub trait EncodeLikeTuple: private::Sealed {} +/// Marker trait to indicate that each element in the tuple encodes like the corresponding element +/// in another tuple. +/// +/// This trait is sealed. +pub trait EncodeLikeTuple: crate::storage::private::Sealed {} macro_rules! impl_encode_like_tuples { ($($elem:ident),+) => {