mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 08:07:58 +00:00
Implement StorageNMap (#8635)
* Implement StorageNMap * Change copyright date to 2021 * Rewrite keys to use impl_for_tuples instead of recursion * Implement prefix iteration on StorageNMap * Implement EncodeLike for key arguments * Rename KeyGenerator::Arg to KeyGenerator::KArg * Support StorageNMap in decl_storage and #[pallet::storage] macros * Use StorageNMap in assets pallet * Support migrate_keys in StorageNMap * Reduce line characters on select files * Refactor crate imports in decl_storage macros * Some more line char reductions and doc comment update * Update UI test expectations * Revert whitespace changes to untouched files * Generate Key struct instead of a 1-tuple when only 1 pair of key and hasher is provided * Revert formatting changes to unrelated files * Introduce KeyGeneratorInner * Add tests for StorageNMap in FRAMEv2 pallet macro * Small fixes to unit tests for StorageNMap * Bump runtime metadata version * Remove unused import * Update tests to use runtime metadata v13 * Introduce and use EncodeLikeTuple as a trait bound for KArg * Add some rustdocs * Revert usage of StorageNMap in assets pallet * Make use of ext::PunctuatedTrailing * Add rustdoc for final_hash * Fix StorageNMap proc macro expansions for single key cases * Create associated const in KeyGenerator for hasher metadata * Refactor code according to comments from Basti * Add module docs for generator/nmap.rs * Re-export storage::Key as NMapKey in pallet prelude * Seal the EncodeLikeTuple trait * Extract sealing code out of key.rs Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
+541
@@ -0,0 +1,541 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
//! 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::{
|
||||
self,
|
||||
types::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator,
|
||||
ReversibleKeyGenerator, TupleToEncodedIter,
|
||||
},
|
||||
unhashed, PrefixIterator, StorageAppend,
|
||||
},
|
||||
Never,
|
||||
};
|
||||
use codec::{Decode, Encode, EncodeLike, FullCodec};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// 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.
|
||||
pub trait StorageNMap<K: KeyGenerator, V: FullCodec> {
|
||||
/// 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<u8> {
|
||||
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<V>) -> Self::Query;
|
||||
|
||||
/// Convert a query to an optional value into storage.
|
||||
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
|
||||
|
||||
/// Generate a partial key used in top storage.
|
||||
fn storage_n_map_partial_key<KP>(key: KP) -> Vec<u8>
|
||||
where
|
||||
K: HasKeyPrefix<KP>,
|
||||
{
|
||||
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
|
||||
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());
|
||||
let key_hashed = <K as HasKeyPrefix<KP>>::partial_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<KG, KArg>(key: KArg) -> Vec<u8>
|
||||
where
|
||||
KG: KeyGenerator,
|
||||
KArg: EncodeLikeTuple<KG::KArg> + 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);
|
||||
|
||||
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<K, V, G> storage::StorageNMap<K, V> for G
|
||||
where
|
||||
K: KeyGenerator,
|
||||
V: FullCodec,
|
||||
G: StorageNMap<K, V>,
|
||||
{
|
||||
type Query = G::Query;
|
||||
|
||||
fn hashed_key_for<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
|
||||
Self::storage_n_map_final_key::<K, _>(key)
|
||||
}
|
||||
|
||||
fn contains_key<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> bool {
|
||||
unhashed::exists(&Self::storage_n_map_final_key::<K, _>(key))
|
||||
}
|
||||
|
||||
fn get<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Self::Query {
|
||||
G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::<K, _>(key)))
|
||||
}
|
||||
|
||||
fn try_get<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Result<V, ()> {
|
||||
unhashed::get(&Self::storage_n_map_final_key::<K, _>(key)).ok_or(())
|
||||
}
|
||||
|
||||
fn take<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Self::Query {
|
||||
let final_key = Self::storage_n_map_final_key::<K, _>(key);
|
||||
|
||||
let value = unhashed::take(&final_key);
|
||||
G::from_optional_value_to_query(value)
|
||||
}
|
||||
|
||||
fn swap<KOther, KArg1, KArg2>(key1: KArg1, key2: KArg2)
|
||||
where
|
||||
KOther: KeyGenerator,
|
||||
KArg1: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
KArg2: EncodeLikeTuple<KOther::KArg> + TupleToEncodedIter,
|
||||
{
|
||||
let final_x_key = Self::storage_n_map_final_key::<K, _>(key1);
|
||||
let final_y_key = Self::storage_n_map_final_key::<KOther, _>(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<KArg, VArg>(key: KArg, val: VArg)
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
VArg: EncodeLike<V>,
|
||||
{
|
||||
unhashed::put(&Self::storage_n_map_final_key::<K, _>(key), &val);
|
||||
}
|
||||
|
||||
fn remove<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) {
|
||||
unhashed::kill(&Self::storage_n_map_final_key::<K, _>(key));
|
||||
}
|
||||
|
||||
fn remove_prefix<KP>(partial_key: KP)
|
||||
where
|
||||
K: HasKeyPrefix<KP>,
|
||||
{
|
||||
unhashed::kill_prefix(&Self::storage_n_map_partial_key(partial_key));
|
||||
}
|
||||
|
||||
fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<V>
|
||||
where
|
||||
K: HasKeyPrefix<KP>,
|
||||
{
|
||||
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<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Self::Query) -> R,
|
||||
{
|
||||
Self::try_mutate(key, |v| Ok::<R, Never>(f(v)))
|
||||
.expect("`Never` can not be constructed; qed")
|
||||
}
|
||||
|
||||
fn try_mutate<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Self::Query) -> Result<R, E>
|
||||
{
|
||||
let final_key = Self::storage_n_map_final_key::<K, _>(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<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<V>) -> R,
|
||||
{
|
||||
Self::try_mutate_exists(key, |v| Ok::<R, Never>(f(v)))
|
||||
.expect("`Never` can not be constructed; qed")
|
||||
}
|
||||
|
||||
fn try_mutate_exists<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<V>) -> Result<R, E>,
|
||||
{
|
||||
let final_key = Self::storage_n_map_final_key::<K, _>(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<Item, EncodeLikeItem, KArg>(key: KArg, item: EncodeLikeItem)
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: StorageAppend<Item>,
|
||||
{
|
||||
let final_key = Self::storage_n_map_final_key::<K, _>(key);
|
||||
sp_io::storage::append(&final_key, item.encode());
|
||||
}
|
||||
|
||||
fn migrate_keys<KArg>(key: KArg, hash_fns: K::HArg) -> Option<V>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
{
|
||||
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::<K, _>(key).as_ref(), &value);
|
||||
value
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
|
||||
storage::IterableStorageNMap<K, V> for G
|
||||
{
|
||||
type Iterator = PrefixIterator<(K::Key, V)>;
|
||||
|
||||
fn iter_prefix<KP>(kp: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
|
||||
where
|
||||
K: HasReversibleKeyPrefix<KP>,
|
||||
{
|
||||
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: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
|
||||
where
|
||||
K: HasReversibleKeyPrefix<KP>,
|
||||
{
|
||||
let mut iter = Self::iter_prefix(kp);
|
||||
iter.drain = true;
|
||||
iter
|
||||
}
|
||||
|
||||
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<O: Decode, F: FnMut(K::Key, O) -> Option<V>>(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::<O>(&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::<V>(&previous_key, &new),
|
||||
None => unhashed::kill(&previous_key),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Test iterators for StorageNMap
|
||||
#[cfg(test)]
|
||||
mod test_iterators {
|
||||
use crate::{
|
||||
hash::StorageHasher,
|
||||
storage::{generator::StorageNMap, unhashed, IterableStorageNMap},
|
||||
};
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
pub trait Config: 'static {
|
||||
type Origin;
|
||||
type BlockNumber;
|
||||
type PalletInfo: crate::traits::PalletInfo;
|
||||
type DbWeight: crate::traits::Get<crate::weights::RuntimeDbWeight>;
|
||||
}
|
||||
|
||||
crate::decl_module! {
|
||||
pub struct Module<T: Config> 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<T: Config> as Test {
|
||||
NMap: nmap hasher(blake2_128_concat) u16, hasher(twox_64_concat) u32 => u64;
|
||||
}
|
||||
}
|
||||
|
||||
fn key_before_prefix(mut prefix: Vec<u8>) -> Vec<u8> {
|
||||
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<u8>) -> Vec<u8> {
|
||||
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<_>>(),
|
||||
vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)],
|
||||
);
|
||||
|
||||
assert_eq!(NMap::iter_values().collect::<Vec<_>>(), vec![3, 0, 2, 1],);
|
||||
|
||||
assert_eq!(
|
||||
NMap::drain().collect::<Vec<_>>(),
|
||||
vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)],
|
||||
);
|
||||
|
||||
assert_eq!(NMap::iter().collect::<Vec<_>>(), 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<_>>(),
|
||||
vec![(1, 1), (2, 2), (0, 0), (3, 3)],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
NMap::iter_prefix_values((k1,)).collect::<Vec<_>>(),
|
||||
vec![1, 2, 0, 3],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
NMap::drain_prefix((k1,)).collect::<Vec<_>>(),
|
||||
vec![(1, 1), (2, 2), (0, 0), (3, 3)],
|
||||
);
|
||||
|
||||
assert_eq!(NMap::iter_prefix((k1,)).collect::<Vec<_>>(), 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<_>>(),
|
||||
vec![((3, 3), 6), ((0, 0), 0), ((2, 2), 4), ((1, 1), 2)],
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,16 @@
|
||||
use sp_core::storage::ChildInfo;
|
||||
use sp_std::prelude::*;
|
||||
use codec::{FullCodec, FullEncode, Encode, EncodeLike, Decode};
|
||||
use crate::hash::{Twox128, StorageHasher, ReversibleStorageHasher};
|
||||
use crate::{
|
||||
hash::{Twox128, StorageHasher, ReversibleStorageHasher},
|
||||
storage::types::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator,
|
||||
ReversibleKeyGenerator, TupleToEncodedIter,
|
||||
},
|
||||
};
|
||||
use sp_runtime::generic::{Digest, DigestItem};
|
||||
pub use sp_runtime::TransactionOutcome;
|
||||
pub use types::Key;
|
||||
|
||||
pub mod unhashed;
|
||||
pub mod hashed;
|
||||
@@ -359,6 +366,39 @@ pub trait IterableStorageDoubleMap<
|
||||
fn translate<O: Decode, F: FnMut(K1, K2, O) -> Option<V>>(f: F);
|
||||
}
|
||||
|
||||
/// A strongly-typed map with arbitrary number of keys in storage whose keys and values can be
|
||||
/// iterated over.
|
||||
pub trait IterableStorageNMap<K: ReversibleKeyGenerator, V: FullCodec>: StorageNMap<K, V> {
|
||||
/// The type that iterates over all `(key1, (key2, (key3, ... (keyN, ()))), value)` tuples
|
||||
type Iterator: Iterator<Item = (K::Key, V)>;
|
||||
|
||||
/// 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: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
|
||||
where K: HasReversibleKeyPrefix<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 `kp` to the map while doing this,
|
||||
/// you'll get undefined results.
|
||||
fn drain_prefix<KP>(kp: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
|
||||
where K: HasReversibleKeyPrefix<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.
|
||||
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<O: Decode, F: FnMut(K::Key, O) -> Option<V>>(f: F);
|
||||
}
|
||||
|
||||
/// An implementation of a map with a two keys.
|
||||
///
|
||||
/// It provides an important ability to efficiently remove all entries
|
||||
@@ -510,6 +550,121 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
|
||||
>(key1: KeyArg1, key2: KeyArg2) -> Option<V>;
|
||||
}
|
||||
|
||||
/// An implementation of a map with an arbitrary number of keys.
|
||||
///
|
||||
/// Details of implementation can be found at [`generator::StorageNMap`].
|
||||
pub trait StorageNMap<K: KeyGenerator, V: FullCodec> {
|
||||
/// 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<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8>;
|
||||
|
||||
/// Does the value (explicitly) exist in storage?
|
||||
fn contains_key<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> bool;
|
||||
|
||||
/// Load the value associated with the given key from the map.
|
||||
fn get<KArg: EncodeLikeTuple<K::KArg> + 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<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Result<V, ()>;
|
||||
|
||||
/// Swap the values of two keys.
|
||||
fn swap<KOther, KArg1, KArg2>(key1: KArg1, key2: KArg2)
|
||||
where
|
||||
KOther: KeyGenerator,
|
||||
KArg1: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
KArg2: EncodeLikeTuple<KOther::KArg> + TupleToEncodedIter;
|
||||
|
||||
/// Store a value to be associated with the given key from the map.
|
||||
fn insert<KArg, VArg>(key: KArg, val: VArg)
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
VArg: EncodeLike<V>;
|
||||
|
||||
/// Remove the value under a key.
|
||||
fn remove<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg);
|
||||
|
||||
/// Remove all values under the partial prefix key.
|
||||
fn remove_prefix<KP>(partial_key: KP) where K: HasKeyPrefix<KP>;
|
||||
|
||||
/// Iterate over values that share the partial prefix key.
|
||||
fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<V> where K: HasKeyPrefix<KP>;
|
||||
|
||||
/// Mutate the value under a key.
|
||||
fn mutate<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Self::Query) -> R;
|
||||
|
||||
/// Mutate the item, only if an `Ok` value is returned.
|
||||
fn try_mutate<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Self::Query) -> Result<R, E>;
|
||||
|
||||
/// Mutate the value under a key.
|
||||
///
|
||||
/// Deletes the item if mutated to a `None`.
|
||||
fn mutate_exists<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<V>) -> R;
|
||||
|
||||
/// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`.
|
||||
fn try_mutate_exists<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<V>) -> Result<R, E>;
|
||||
|
||||
/// Take the value under a key.
|
||||
fn take<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> 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<Item, EncodeLikeItem, KArg>(key: KArg, item: EncodeLikeItem)
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
V: StorageAppend<Item>;
|
||||
|
||||
/// 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<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Option<usize>
|
||||
where
|
||||
V: StorageDecodeLength,
|
||||
{
|
||||
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<KArg>(key: KArg, hash_fns: K::HArg) -> Option<V>
|
||||
where
|
||||
KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
@@ -806,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;
|
||||
@@ -818,6 +973,33 @@ mod private {
|
||||
impl<T, S> Sealed for BoundedVec<T, S> {}
|
||||
impl<K, V, S> Sealed for bounded_btree_map::BoundedBTreeMap<K, V, S> {}
|
||||
impl<T, S> Sealed for bounded_btree_set::BoundedBTreeSet<T, S> {}
|
||||
|
||||
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<T: Encode> StorageAppend<T> for Vec<T> {}
|
||||
|
||||
+957
@@ -0,0 +1,957 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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};
|
||||
use codec::{Encode, EncodeLike, FullCodec};
|
||||
use paste::paste;
|
||||
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<Hasher, KeyType>(core::marker::PhantomData<(Hasher, KeyType)>);
|
||||
|
||||
/// A trait that contains the current key as an associated type.
|
||||
pub trait KeyGenerator {
|
||||
type Key: EncodeLike<Self::Key>;
|
||||
type KArg: Encode;
|
||||
type HashFn: FnOnce(&[u8]) -> Vec<u8>;
|
||||
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<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8>;
|
||||
/// 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<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
|
||||
key: &KArg,
|
||||
hash_fns: Self::HArg,
|
||||
) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// 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<u8>;
|
||||
}
|
||||
|
||||
impl<H: StorageHasher, K: FullCodec> KeyGenerator for Key<H, K> {
|
||||
type Key = K;
|
||||
type KArg = (K,);
|
||||
type HashFn = Box<dyn FnOnce(&[u8]) -> Vec<u8>>;
|
||||
type HArg = (Self::HashFn,);
|
||||
|
||||
const HASHER_METADATA: &'static [frame_metadata::StorageHasher] = &[H::METADATA];
|
||||
|
||||
fn final_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
|
||||
H::hash(
|
||||
&key.to_encoded_iter()
|
||||
.next()
|
||||
.expect("should have at least one element!"),
|
||||
)
|
||||
.as_ref()
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
fn migrate_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
|
||||
key: &KArg,
|
||||
hash_fns: Self::HArg,
|
||||
) -> Vec<u8> {
|
||||
(hash_fns.0)(
|
||||
&key.to_encoded_iter()
|
||||
.next()
|
||||
.expect("should have at least one element!"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: StorageHasher, K: FullCodec> KeyGeneratorInner for Key<H, K> {
|
||||
type Hasher = H;
|
||||
|
||||
fn final_hash(encoded: &[u8]) -> Vec<u8> {
|
||||
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<dyn FnOnce(&[u8]) -> Vec<u8>>;
|
||||
|
||||
const HASHER_METADATA: &'static [frame_metadata::StorageHasher] = &[
|
||||
for_tuples!( #(Tuple::Hasher::METADATA),* )
|
||||
];
|
||||
|
||||
fn final_key<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
|
||||
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<KArg: EncodeLikeTuple<Self::KArg> + TupleToEncodedIter>(
|
||||
key: &KArg,
|
||||
hash_fns: Self::HArg,
|
||||
) -> Vec<u8> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<T>: crate::storage::private::Sealed {}
|
||||
|
||||
macro_rules! impl_encode_like_tuples {
|
||||
($($elem:ident),+) => {
|
||||
paste! {
|
||||
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>],)+) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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<Vec<u8>>;
|
||||
}
|
||||
|
||||
#[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<Vec<u8>> {
|
||||
[for_tuples!( #(self.Tuple.encode()),* )]
|
||||
.to_vec()
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TupleToEncodedIter> TupleToEncodedIter for &T {
|
||||
fn to_encoded_iter(&self) -> sp_std::vec::IntoIter<Vec<u8>> {
|
||||
(*self).to_encoded_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that indicates the hashers for the keys generated are all reversible.
|
||||
pub trait ReversibleKeyGenerator: KeyGenerator {
|
||||
type ReversibleHasher;
|
||||
fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error>;
|
||||
}
|
||||
|
||||
impl<H: ReversibleStorageHasher, K: FullCodec> ReversibleKeyGenerator for Key<H, K> {
|
||||
type ReversibleHasher = H;
|
||||
|
||||
fn decode_final_key(key_material: &[u8]) -> Result<(Self::Key, &[u8]), codec::Error> {
|
||||
let mut current_key_material = Self::ReversibleHasher::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 ReversibleHasher = ( #(Tuple::ReversibleHasher),* ); );
|
||||
|
||||
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<P>: KeyGenerator {
|
||||
type Suffix;
|
||||
|
||||
fn partial_key(prefix: P) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// Trait indicating whether a ReversibleKeyGenerator has the prefix P.
|
||||
pub trait HasReversibleKeyPrefix<P>: ReversibleKeyGenerator + HasKeyPrefix<P> {
|
||||
fn decode_partial_key(key_material: &[u8]) -> Result<Self::Suffix, codec::Error>;
|
||||
}
|
||||
|
||||
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<u8> {
|
||||
<($(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<Self::Suffix, codec::Error> {
|
||||
<($(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<u8> {
|
||||
<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<Self::Suffix, codec::Error> {
|
||||
<($(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<u8> {
|
||||
<($(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<Self::Suffix, codec::Error> {
|
||||
<Key<[<$suffix $suffix>], $suffix>>::decode_final_key(key_material).map(|k| k.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<A: FullCodec, B: FullCodec, X: StorageHasher, Y: StorageHasher> HasKeyPrefix<(A,)>
|
||||
for (Key<X, A>, Key<Y, B>)
|
||||
{
|
||||
type Suffix = B;
|
||||
|
||||
fn partial_key(prefix: (A,)) -> Vec<u8> {
|
||||
<Key<X, A>>::final_key(prefix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: FullCodec, B: FullCodec, X: ReversibleStorageHasher, Y: ReversibleStorageHasher>
|
||||
HasReversibleKeyPrefix<(A,)> for (Key<X, A>, Key<Y, B>)
|
||||
{
|
||||
fn decode_partial_key(key_material: &[u8]) -> Result<B, codec::Error> {
|
||||
<Key<Y, B>>::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)
|
||||
);
|
||||
@@ -21,13 +21,20 @@
|
||||
use codec::FullCodec;
|
||||
use frame_metadata::{DefaultByte, StorageEntryModifier};
|
||||
|
||||
mod value;
|
||||
mod map;
|
||||
mod double_map;
|
||||
mod key;
|
||||
mod map;
|
||||
mod nmap;
|
||||
mod value;
|
||||
|
||||
pub use value::{StorageValue, StorageValueMetadata};
|
||||
pub use map::{StorageMap, StorageMapMetadata};
|
||||
pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata};
|
||||
pub use key::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator,
|
||||
ReversibleKeyGenerator, TupleToEncodedIter,
|
||||
};
|
||||
pub use map::{StorageMap, StorageMapMetadata};
|
||||
pub use nmap::{StorageNMap, StorageNMapMetadata};
|
||||
pub use value::{StorageValue, StorageValueMetadata};
|
||||
|
||||
/// Trait implementing how the storage optional value is converted into the queried type.
|
||||
///
|
||||
@@ -104,5 +111,5 @@ impl<Value: FullCodec, OnEmpty: crate::traits::Get<Value>> DefaultByte
|
||||
OnEmpty::get().encode()
|
||||
}
|
||||
}
|
||||
unsafe impl <Value, OnEmpty: crate::traits::Get<Value>> Send for OnEmptyGetter<Value, OnEmpty> {}
|
||||
unsafe impl <Value, OnEmpty: crate::traits::Get<Value>> Sync for OnEmptyGetter<Value, OnEmpty> {}
|
||||
unsafe impl<Value, OnEmpty: crate::traits::Get<Value>> Send for OnEmptyGetter<Value, OnEmpty> {}
|
||||
unsafe impl<Value, OnEmpty: crate::traits::Get<Value>> Sync for OnEmptyGetter<Value, OnEmpty> {}
|
||||
|
||||
+995
@@ -0,0 +1,995 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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 crate::{
|
||||
storage::{
|
||||
types::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter,
|
||||
OptionQuery, QueryKindTrait, TupleToEncodedIter,
|
||||
},
|
||||
KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength,
|
||||
},
|
||||
traits::{GetDefault, StorageInstance},
|
||||
};
|
||||
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
|
||||
/// `(Key<Hasher1, key1>, Key<Hasher2, key2>, ..., Key<HasherN, 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<Prefix, Key, Value, QueryKind = OptionQuery, OnEmpty = GetDefault>(
|
||||
core::marker::PhantomData<(Prefix, Key, Value, QueryKind, OnEmpty)>,
|
||||
);
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> crate::storage::generator::StorageNMap<Key, Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + '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<Value>) -> Self::Query {
|
||||
QueryKind::from_optional_value_to_query(v)
|
||||
}
|
||||
fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
|
||||
QueryKind::from_query_to_optional_value(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> crate::storage::StoragePrefixedMap<Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
{
|
||||
fn module_prefix() -> &'static [u8] {
|
||||
<Self as crate::storage::generator::StorageNMap<Key, Value>>::module_prefix()
|
||||
}
|
||||
fn storage_prefix() -> &'static [u8] {
|
||||
<Self as crate::storage::generator::StorageNMap<Key, Value>>::storage_prefix()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
{
|
||||
/// Get the storage key used to fetch a value corresponding to a specific key.
|
||||
pub fn hashed_key_for<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::hashed_key_for(key)
|
||||
}
|
||||
|
||||
/// Does the value (explicitly) exist in storage?
|
||||
pub fn contains_key<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) -> bool {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::contains_key(key)
|
||||
}
|
||||
|
||||
/// Load the value associated with the given key from the map.
|
||||
pub fn get<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) -> QueryKind::Query {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::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<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(
|
||||
key: KArg,
|
||||
) -> Result<Value, ()> {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::try_get(key)
|
||||
}
|
||||
|
||||
/// Take a value from storage, removing it afterwards.
|
||||
pub fn take<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) -> QueryKind::Query {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::take(key)
|
||||
}
|
||||
|
||||
/// Swap the values of two key-pairs.
|
||||
pub fn swap<KOther, KArg1, KArg2>(key1: KArg1, key2: KArg2)
|
||||
where
|
||||
KOther: KeyGenerator,
|
||||
KArg1: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
KArg2: EncodeLikeTuple<KOther::KArg> + TupleToEncodedIter,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::swap::<KOther, _, _>(key1, key2)
|
||||
}
|
||||
|
||||
/// Store a value to be associated with the given keys from the map.
|
||||
pub fn insert<KArg, VArg>(key: KArg, val: VArg)
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
VArg: EncodeLike<Value>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::insert(key, val)
|
||||
}
|
||||
|
||||
/// Remove the value under the given keys.
|
||||
pub fn remove<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) {
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::remove(key)
|
||||
}
|
||||
|
||||
/// Remove all values under the first key.
|
||||
pub fn remove_prefix<KP>(partial_key: KP)
|
||||
where
|
||||
Key: HasKeyPrefix<KP>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::remove_prefix(partial_key)
|
||||
}
|
||||
|
||||
/// Iterate over values that share the first key.
|
||||
pub fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<Value>
|
||||
where
|
||||
Key: HasKeyPrefix<KP>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::iter_prefix_values(partial_key)
|
||||
}
|
||||
|
||||
/// Mutate the value under the given keys.
|
||||
pub fn mutate<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut QueryKind::Query) -> R,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::mutate(key, f)
|
||||
}
|
||||
|
||||
/// Mutate the value under the given keys when the closure returns `Ok`.
|
||||
pub fn try_mutate<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut QueryKind::Query) -> Result<R, E>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::try_mutate(key, f)
|
||||
}
|
||||
|
||||
/// Mutate the value under the given keys. Deletes the item if mutated to a `None`.
|
||||
pub fn mutate_exists<KArg, R, F>(key: KArg, f: F) -> R
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<Value>) -> R,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::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<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
F: FnOnce(&mut Option<Value>) -> Result<R, E>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::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<Item, EncodeLikeItem, KArg>(key: KArg, item: EncodeLikeItem)
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter,
|
||||
Item: Encode,
|
||||
EncodeLikeItem: EncodeLike<Item>,
|
||||
Value: StorageAppend<Item>,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::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<KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter>(key: KArg) -> Option<usize>
|
||||
where
|
||||
Value: StorageDecodeLength,
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::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<KArg>(key: KArg, hash_fns: Key::HArg) -> Option<Value>
|
||||
where
|
||||
KArg: EncodeLikeTuple<Key::KArg> + TupleToEncodedIter
|
||||
{
|
||||
<Self as crate::storage::StorageNMap<Key, Value>>::migrate_keys::<_>(key, hash_fns)
|
||||
}
|
||||
|
||||
/// Remove all value of the storage.
|
||||
pub fn remove_all() {
|
||||
<Self as crate::storage::StoragePrefixedMap<Value>>::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<Value> {
|
||||
<Self as crate::storage::StoragePrefixedMap<Value>>::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<OldValue: Decode, F: FnMut(OldValue) -> Option<Value>>(f: F) {
|
||||
<Self as crate::storage::StoragePrefixedMap<Value>>::translate_values(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::ReversibleKeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + '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: KP,
|
||||
) -> crate::storage::PrefixIterator<(<Key as HasKeyPrefix<KP>>::Suffix, Value)>
|
||||
where
|
||||
Key: HasReversibleKeyPrefix<KP>,
|
||||
{
|
||||
<Self as crate::storage::IterableStorageNMap<Key, Value>>::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: KP,
|
||||
) -> crate::storage::PrefixIterator<(<Key as HasKeyPrefix<KP>>::Suffix, Value)>
|
||||
where
|
||||
Key: HasReversibleKeyPrefix<KP>,
|
||||
{
|
||||
<Self as crate::storage::IterableStorageNMap<Key, Value>>::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.
|
||||
pub fn iter() -> crate::storage::PrefixIterator<(Key::Key, Value)> {
|
||||
<Self as crate::storage::IterableStorageNMap<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::Key, Value)> {
|
||||
<Self as crate::storage::IterableStorageNMap<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<O: Decode, F: FnMut(Key::Key, O) -> Option<Value>>(f: F) {
|
||||
<Self as crate::storage::IterableStorageNMap<Key, Value>>::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;
|
||||
const HASHERS: &'static [frame_metadata::StorageHasher];
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMapMetadata
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
{
|
||||
const MODIFIER: StorageEntryModifier = QueryKind::METADATA;
|
||||
const NAME: &'static str = Prefix::STORAGE_PREFIX;
|
||||
const DEFAULT: DefaultByteGetter = DefaultByteGetter(
|
||||
&OnEmptyGetter::<QueryKind::Query, OnEmpty>(core::marker::PhantomData),
|
||||
);
|
||||
const HASHERS: &'static [frame_metadata::StorageHasher] = Key::HASHER_METADATA;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
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"
|
||||
}
|
||||
const STORAGE_PREFIX: &'static str = "foo";
|
||||
}
|
||||
|
||||
struct ADefault;
|
||||
impl crate::traits::Get<u32> for ADefault {
|
||||
fn get() -> u32 {
|
||||
98
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_1_key() {
|
||||
type A = StorageNMap<Prefix, Key<Blake2_128Concat, u16>, u32, OptionQuery>;
|
||||
type AValueQueryWithAnOnEmpty =
|
||||
StorageNMap<Prefix, Key<Blake2_128Concat, u16>, u32, ValueQuery, ADefault>;
|
||||
type B = StorageNMap<Prefix, Key<Blake2_256, u16>, u32, ValueQuery>;
|
||||
type C = StorageNMap<Prefix, Key<Blake2_128Concat, u16>, u8, ValueQuery>;
|
||||
type WithLen = StorageNMap<Prefix, Key<Blake2_128Concat, u16>, Vec<u32>>;
|
||||
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let mut k: Vec<u8> = 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<Blake2_128Concat, u16>, _, _>((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,), (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();
|
||||
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<_>>(), vec![10, 10]);
|
||||
|
||||
C::insert((3,), 10);
|
||||
C::insert((4,), 10);
|
||||
A::translate_values::<u8, _>(|v| Some((v * 2).into()));
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 20), (3, 20)]);
|
||||
|
||||
A::insert((3,), 10);
|
||||
A::insert((4,), 10);
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), vec![(4, 10), (3, 10)]);
|
||||
assert_eq!(A::drain().collect::<Vec<_>>(), vec![(4, 10), (3, 10)]);
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), vec![]);
|
||||
|
||||
C::insert((3,), 10);
|
||||
C::insert((4,), 10);
|
||||
A::translate::<u8, _>(|k1, v| Some((k1 as u16 * v as u16).into()));
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), 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::<u32>::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<
|
||||
Prefix,
|
||||
(Key<Blake2_128Concat, u16>, Key<Twox64Concat, u8>),
|
||||
u32,
|
||||
OptionQuery,
|
||||
>;
|
||||
type AValueQueryWithAnOnEmpty = StorageNMap<
|
||||
Prefix,
|
||||
(Key<Blake2_128Concat, u16>, Key<Twox64Concat, u8>),
|
||||
u32,
|
||||
ValueQuery,
|
||||
ADefault,
|
||||
>;
|
||||
type B = StorageNMap<Prefix, (Key<Blake2_256, u16>, Key<Twox128, u8>), u32, ValueQuery>;
|
||||
type C = StorageNMap<
|
||||
Prefix,
|
||||
(Key<Blake2_128Concat, u16>, Key<Twox64Concat, u8>),
|
||||
u8,
|
||||
ValueQuery,
|
||||
>;
|
||||
type WithLen =
|
||||
StorageNMap<Prefix, (Key<Blake2_128Concat, u16>, Key<Twox64Concat, u8>), Vec<u32>>;
|
||||
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let mut k: Vec<u8> = 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<Blake2_128Concat, u16>, Key<Twox64Concat, u8>), _, _>((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),
|
||||
(
|
||||
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();
|
||||
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<_>>(), vec![10, 10]);
|
||||
|
||||
C::insert((3, 30), 10);
|
||||
C::insert((4, 40), 10);
|
||||
A::translate_values::<u8, _>(|v| Some((v * 2).into()));
|
||||
assert_eq!(
|
||||
A::iter().collect::<Vec<_>>(),
|
||||
vec![((4, 40), 20), ((3, 30), 20)]
|
||||
);
|
||||
|
||||
A::insert((3, 30), 10);
|
||||
A::insert((4, 40), 10);
|
||||
assert_eq!(
|
||||
A::iter().collect::<Vec<_>>(),
|
||||
vec![((4, 40), 10), ((3, 30), 10)]
|
||||
);
|
||||
assert_eq!(
|
||||
A::drain().collect::<Vec<_>>(),
|
||||
vec![((4, 40), 10), ((3, 30), 10)]
|
||||
);
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), vec![]);
|
||||
|
||||
C::insert((3, 30), 10);
|
||||
C::insert((4, 40), 10);
|
||||
A::translate::<u8, _>(|(k1, k2), v| Some((k1 * k2 as u16 * v as u16).into()));
|
||||
assert_eq!(
|
||||
A::iter().collect::<Vec<_>>(),
|
||||
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::<u32>::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<_>>(),
|
||||
vec![12, 11]
|
||||
);
|
||||
assert_eq!(
|
||||
A::iter_prefix_values((4,)).collect::<Vec<_>>(),
|
||||
vec![13, 14]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_3_keys() {
|
||||
type A = StorageNMap<
|
||||
Prefix,
|
||||
(
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Twox64Concat, u16>,
|
||||
),
|
||||
u32,
|
||||
OptionQuery,
|
||||
>;
|
||||
type AValueQueryWithAnOnEmpty = StorageNMap<
|
||||
Prefix,
|
||||
(
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Twox64Concat, u16>,
|
||||
),
|
||||
u32,
|
||||
ValueQuery,
|
||||
ADefault,
|
||||
>;
|
||||
type B = StorageNMap<
|
||||
Prefix,
|
||||
(
|
||||
Key<Blake2_256, u16>,
|
||||
Key<Blake2_256, u16>,
|
||||
Key<Twox128, u16>,
|
||||
),
|
||||
u32,
|
||||
ValueQuery,
|
||||
>;
|
||||
type C = StorageNMap<
|
||||
Prefix,
|
||||
(
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Twox64Concat, u16>,
|
||||
),
|
||||
u8,
|
||||
ValueQuery,
|
||||
>;
|
||||
type WithLen = StorageNMap<
|
||||
Prefix,
|
||||
(
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Twox64Concat, u16>,
|
||||
),
|
||||
Vec<u32>,
|
||||
>;
|
||||
|
||||
TestExternalities::default().execute_with(|| {
|
||||
let mut k: Vec<u8> = 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<Blake2_128Concat, u16>,
|
||||
Key<Blake2_128Concat, u16>,
|
||||
Key<Twox64Concat, u16>,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
>((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(
|
||||
(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();
|
||||
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<_>>(), vec![10, 10]);
|
||||
|
||||
C::insert((3, 30, 300), 10);
|
||||
C::insert((4, 40, 400), 10);
|
||||
A::translate_values::<u8, _>(|v| Some((v * 2).into()));
|
||||
assert_eq!(
|
||||
A::iter().collect::<Vec<_>>(),
|
||||
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<_>>(),
|
||||
vec![((4, 40, 400), 10), ((3, 30, 300), 10)]
|
||||
);
|
||||
assert_eq!(
|
||||
A::drain().collect::<Vec<_>>(),
|
||||
vec![((4, 40, 400), 10), ((3, 30, 300), 10)]
|
||||
);
|
||||
assert_eq!(A::iter().collect::<Vec<_>>(), vec![]);
|
||||
|
||||
C::insert((3, 30, 300), 10);
|
||||
C::insert((4, 40, 400), 10);
|
||||
A::translate::<u8, _>(|(k1, k2, k3), v| {
|
||||
Some((k1 * k2 as u16 * v as u16 / k3 as u16).into())
|
||||
});
|
||||
assert_eq!(
|
||||
A::iter().collect::<Vec<_>>(),
|
||||
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::<u32>::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,)).collect::<Vec<_>>(),
|
||||
vec![11, 12]
|
||||
);
|
||||
assert_eq!(
|
||||
A::iter_prefix_values((4,)).collect::<Vec<_>>(),
|
||||
vec![14, 13]
|
||||
);
|
||||
assert_eq!(
|
||||
A::iter_prefix_values((3, 30)).collect::<Vec<_>>(),
|
||||
vec![11, 12]
|
||||
);
|
||||
assert_eq!(
|
||||
A::iter_prefix_values((4, 40)).collect::<Vec<_>>(),
|
||||
vec![14, 13]
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user