mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 11:38:01 +00:00
Allow to specify some max number of values for storages in pallet macro. (#8735)
* implement max_values + storages info * some formatting + doc * rename StoragesInfo -> PalletStorageInfo * merge both StorageInfoTrait and PalletStorageInfo I think it is more future proof. In the future some storage could make use of multiple prefix. Like one to store how much value has been inserted, etc... * Update frame/support/procedural/src/storage/parse.rs Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Update frame/support/procedural/src/storage/storage_struct.rs Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * Fix max_size using hasher information hasher now expose `max_len` which allows to computes their maximum len. For hasher without concatenation, it is the size of the hash part, for hasher with concatenation, it is the size of the hash part + max encoded len of the key. * fix tests * fix ui tests Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
59f34ab8bc
commit
9bf62ef65d
@@ -21,14 +21,15 @@
|
||||
use codec::{Decode, Encode, EncodeLike, FullCodec};
|
||||
use crate::{
|
||||
storage::{
|
||||
StorageAppend, StorageDecodeLength,
|
||||
StorageAppend, StorageDecodeLength, StoragePrefixedMap,
|
||||
bounded_vec::BoundedVec,
|
||||
types::{OptionQuery, QueryKindTrait, OnEmptyGetter},
|
||||
},
|
||||
traits::{GetDefault, StorageInstance, Get},
|
||||
traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo},
|
||||
};
|
||||
use frame_metadata::{DefaultByteGetter, StorageEntryModifier};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// A type that allow to store values for `(key1, key2)` couple. Similar to `StorageMap` but allow
|
||||
/// to iterate and remove value associated to first key.
|
||||
@@ -47,14 +48,24 @@ use sp_std::vec::Vec;
|
||||
/// such as `blake2_128_concat` must be used for Hasher1 (resp. Hasher2). Otherwise, other values
|
||||
/// in storage can be compromised.
|
||||
pub struct StorageDoubleMap<
|
||||
Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind=OptionQuery, OnEmpty=GetDefault
|
||||
Prefix,
|
||||
Hasher1,
|
||||
Key1,
|
||||
Hasher2,
|
||||
Key2,
|
||||
Value,
|
||||
QueryKind=OptionQuery,
|
||||
OnEmpty=GetDefault,
|
||||
MaxValues=GetDefault,
|
||||
>(
|
||||
core::marker::PhantomData<(Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty)>
|
||||
core::marker::PhantomData<
|
||||
(Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues)
|
||||
>
|
||||
);
|
||||
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::storage::generator::StorageDoubleMap<Key1, Key2, Value> for
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
@@ -63,7 +74,8 @@ where
|
||||
Key2: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
type Query = QueryKind::Query;
|
||||
type Hasher1 = Hasher1;
|
||||
@@ -82,9 +94,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
crate::storage::StoragePrefixedMap<Value> for
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StoragePrefixedMap<Value> for
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
@@ -93,7 +105,8 @@ where
|
||||
Key2: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn module_prefix() -> &'static [u8] {
|
||||
<Self as crate::storage::generator::StorageDoubleMap<Key1, Key2, Value>>::module_prefix()
|
||||
@@ -103,7 +116,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, QueryKind, OnEmpty, VecValue, VecBound>
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, QueryKind, OnEmpty, MaxValues, VecValue, VecBound>
|
||||
StorageDoubleMap<
|
||||
Prefix,
|
||||
Hasher1,
|
||||
@@ -113,6 +126,7 @@ impl<Prefix, Hasher1, Key1, Hasher2, Key2, QueryKind, OnEmpty, VecValue, VecBoun
|
||||
BoundedVec<VecValue, VecBound>,
|
||||
QueryKind,
|
||||
OnEmpty,
|
||||
MaxValues,
|
||||
> where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
@@ -120,7 +134,8 @@ impl<Prefix, Hasher1, Key1, Hasher2, Key2, QueryKind, OnEmpty, VecValue, VecBoun
|
||||
Key1: FullCodec,
|
||||
Key2: FullCodec,
|
||||
QueryKind: QueryKindTrait<BoundedVec<VecValue, VecBound>, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
VecValue: FullCodec,
|
||||
VecBound: Get<u32>,
|
||||
{
|
||||
@@ -147,8 +162,8 @@ impl<Prefix, Hasher1, Key1, Hasher2, Key2, QueryKind, OnEmpty, VecValue, VecBoun
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
@@ -157,7 +172,8 @@ where
|
||||
Key2: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// Get the storage key used to fetch a value corresponding to a specific key.
|
||||
pub fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
|
||||
@@ -376,8 +392,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
|
||||
@@ -386,7 +402,8 @@ where
|
||||
Key2: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// Enumerate all elements in the map with first key `k1` in no particular order.
|
||||
///
|
||||
@@ -440,8 +457,10 @@ pub trait StorageDoubleMapMetadata {
|
||||
const HASHER2: frame_metadata::StorageHasher;
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty> StorageDoubleMapMetadata
|
||||
for StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty> where
|
||||
impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageDoubleMapMetadata for
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
Hasher2: crate::hash::StorageHasher,
|
||||
@@ -449,7 +468,8 @@ impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty> StorageDou
|
||||
Key2: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
const MODIFIER: StorageEntryModifier = QueryKind::METADATA;
|
||||
const HASHER1: frame_metadata::StorageHasher = Hasher1::METADATA;
|
||||
@@ -459,6 +479,36 @@ impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty> StorageDou
|
||||
DefaultByteGetter(&OnEmptyGetter::<QueryKind::Query, OnEmpty>(core::marker::PhantomData));
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher1, Hasher2, Key1, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::traits::StorageInfoTrait for
|
||||
StorageDoubleMap<Prefix, Hasher1, Key1, Hasher2, Key2, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher1: crate::hash::StorageHasher,
|
||||
Hasher2: crate::hash::StorageHasher,
|
||||
Key1: FullCodec + MaxEncodedLen,
|
||||
Key2: FullCodec + MaxEncodedLen,
|
||||
Value: FullCodec + MaxEncodedLen,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn storage_info() -> Vec<StorageInfo> {
|
||||
vec![
|
||||
StorageInfo {
|
||||
prefix: Self::final_prefix(),
|
||||
max_values: MaxValues::get(),
|
||||
max_size: Some(
|
||||
Hasher1::max_len::<Key1>()
|
||||
.saturating_add(Hasher2::max_len::<Key2>())
|
||||
.saturating_add(Value::max_encoded_len())
|
||||
.saturated_into(),
|
||||
),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
//! Storage key type.
|
||||
|
||||
use crate::hash::{ReversibleStorageHasher, StorageHasher};
|
||||
use crate::{hash::{ReversibleStorageHasher, StorageHasher}, traits::MaxEncodedLen};
|
||||
use codec::{Encode, EncodeLike, FullCodec};
|
||||
use paste::paste;
|
||||
use sp_std::prelude::*;
|
||||
@@ -53,6 +53,11 @@ pub trait KeyGenerator {
|
||||
) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// The maximum length used by the key in storage.
|
||||
pub trait KeyGeneratorMaxEncodedLen: KeyGenerator {
|
||||
fn key_max_encoded_len() -> usize;
|
||||
}
|
||||
|
||||
/// A trait containing methods that are only implemented on the Key struct instead of the entire tuple.
|
||||
pub trait KeyGeneratorInner: KeyGenerator {
|
||||
type Hasher: StorageHasher;
|
||||
@@ -91,6 +96,12 @@ impl<H: StorageHasher, K: FullCodec> KeyGenerator for Key<H, K> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: StorageHasher, K: FullCodec + MaxEncodedLen> KeyGeneratorMaxEncodedLen for Key<H, K> {
|
||||
fn key_max_encoded_len() -> usize {
|
||||
H::max_len::<K>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: StorageHasher, K: FullCodec> KeyGeneratorInner for Key<H, K> {
|
||||
type Hasher = H;
|
||||
|
||||
@@ -139,6 +150,20 @@ impl KeyGenerator for Tuple {
|
||||
}
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(2, 18)]
|
||||
#[tuple_types_custom_trait_bound(KeyGeneratorInner + KeyGeneratorMaxEncodedLen)]
|
||||
impl KeyGeneratorMaxEncodedLen for Tuple {
|
||||
fn key_max_encoded_len() -> usize {
|
||||
let mut len = 0usize;
|
||||
for_tuples!(
|
||||
#(
|
||||
len = len.saturating_add(Tuple::key_max_encoded_len());
|
||||
)*
|
||||
);
|
||||
len
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker trait to indicate that each element in the tuple encodes like the corresponding element
|
||||
/// in another tuple.
|
||||
///
|
||||
|
||||
@@ -21,13 +21,14 @@
|
||||
use codec::{FullCodec, Decode, EncodeLike, Encode};
|
||||
use crate::{
|
||||
storage::{
|
||||
StorageAppend, StorageDecodeLength,
|
||||
StorageAppend, StorageDecodeLength, StoragePrefixedMap,
|
||||
bounded_vec::BoundedVec,
|
||||
types::{OptionQuery, QueryKindTrait, OnEmptyGetter},
|
||||
},
|
||||
traits::{GetDefault, StorageInstance, Get},
|
||||
traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo},
|
||||
};
|
||||
use frame_metadata::{DefaultByteGetter, StorageEntryModifier};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// A type that allow to store value for given key. Allowing to insert/remove/iterate on values.
|
||||
@@ -43,20 +44,23 @@ use sp_std::prelude::*;
|
||||
///
|
||||
/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
|
||||
/// `blake2_128_concat` must be used. Otherwise, other values in storage can be compromised.
|
||||
pub struct StorageMap<Prefix, Hasher, Key, Value, QueryKind=OptionQuery, OnEmpty=GetDefault>(
|
||||
core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty)>
|
||||
pub struct StorageMap<
|
||||
Prefix, Hasher, Key, Value, QueryKind=OptionQuery, OnEmpty=GetDefault, MaxValues=GetDefault,
|
||||
>(
|
||||
core::marker::PhantomData<(Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues)>
|
||||
);
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::storage::generator::StorageMap<Key, Value>
|
||||
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
type Query = QueryKind::Query;
|
||||
type Hasher = Hasher;
|
||||
@@ -74,15 +78,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> crate::storage::StoragePrefixedMap<Value> for
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StoragePrefixedMap<Value> for
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn module_prefix() -> &'static [u8] {
|
||||
<Self as crate::storage::generator::StorageMap<Key, Value>>::module_prefix()
|
||||
@@ -92,14 +98,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, QueryKind, OnEmpty, VecValue, VecBound>
|
||||
StorageMap<Prefix, Hasher, Key, BoundedVec<VecValue, VecBound>, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher, Key, QueryKind, OnEmpty, MaxValues, VecValue, VecBound>
|
||||
StorageMap<Prefix, Hasher, Key, BoundedVec<VecValue, VecBound>, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec,
|
||||
QueryKind: QueryKindTrait<BoundedVec<VecValue, VecBound>, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
VecValue: FullCodec,
|
||||
VecBound: Get<u32>,
|
||||
{
|
||||
@@ -120,15 +127,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// Get the storage key used to fetch a value corresponding to a specific key.
|
||||
pub fn hashed_key_for<KeyArg: EncodeLike<Key>>(key: KeyArg) -> Vec<u8> {
|
||||
@@ -283,15 +291,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher + crate::ReversibleStorageHasher,
|
||||
Key: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// Enumerate all elements in the map in no particular order.
|
||||
///
|
||||
@@ -327,14 +336,15 @@ pub trait StorageMapMetadata {
|
||||
const HASHER: frame_metadata::StorageHasher;
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> StorageMapMetadata
|
||||
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> where
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues> StorageMapMetadata
|
||||
for StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues> where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
const MODIFIER: StorageEntryModifier = QueryKind::METADATA;
|
||||
const HASHER: frame_metadata::StorageHasher = Hasher::METADATA;
|
||||
@@ -343,6 +353,33 @@ impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty> StorageMapMetadata
|
||||
DefaultByteGetter(&OnEmptyGetter::<QueryKind::Query, OnEmpty>(core::marker::PhantomData));
|
||||
}
|
||||
|
||||
impl<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::traits::StorageInfoTrait for
|
||||
StorageMap<Prefix, Hasher, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Hasher: crate::hash::StorageHasher,
|
||||
Key: FullCodec + MaxEncodedLen,
|
||||
Value: FullCodec + MaxEncodedLen,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn storage_info() -> Vec<StorageInfo> {
|
||||
vec![
|
||||
StorageInfo {
|
||||
prefix: Self::final_prefix(),
|
||||
max_values: MaxValues::get(),
|
||||
max_size: Some(
|
||||
Hasher::max_len::<Key>()
|
||||
.saturating_add(Value::max_encoded_len())
|
||||
.saturated_into(),
|
||||
),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -30,7 +30,7 @@ mod value;
|
||||
pub use double_map::{StorageDoubleMap, StorageDoubleMapMetadata};
|
||||
pub use key::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, Key, KeyGenerator,
|
||||
ReversibleKeyGenerator, TupleToEncodedIter,
|
||||
ReversibleKeyGenerator, TupleToEncodedIter, KeyGeneratorMaxEncodedLen,
|
||||
};
|
||||
pub use map::{StorageMap, StorageMapMetadata};
|
||||
pub use nmap::{StorageNMap, StorageNMapMetadata};
|
||||
|
||||
@@ -24,12 +24,13 @@ use crate::{
|
||||
EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, OnEmptyGetter,
|
||||
OptionQuery, QueryKindTrait, TupleToEncodedIter,
|
||||
},
|
||||
KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength,
|
||||
KeyGenerator, PrefixIterator, StorageAppend, StorageDecodeLength, StoragePrefixedMap,
|
||||
},
|
||||
traits::{GetDefault, StorageInstance},
|
||||
traits::{Get, GetDefault, StorageInstance, StorageInfo, MaxEncodedLen},
|
||||
};
|
||||
use codec::{Decode, Encode, EncodeLike, FullCodec};
|
||||
use frame_metadata::{DefaultByteGetter, StorageEntryModifier};
|
||||
use sp_runtime::SaturatedConversion;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// A type that allow to store values for an arbitrary number of keys in the form of
|
||||
@@ -50,18 +51,22 @@ use sp_std::prelude::*;
|
||||
/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher`
|
||||
/// such as `blake2_128_concat` must be used 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)>,
|
||||
pub struct StorageNMap<
|
||||
Prefix, Key, Value, QueryKind = OptionQuery, OnEmpty = GetDefault, MaxValues=GetDefault,
|
||||
>(
|
||||
core::marker::PhantomData<(Prefix, Key, Value, QueryKind, OnEmpty, MaxValues)>,
|
||||
);
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> crate::storage::generator::StorageNMap<Key, Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::storage::generator::StorageNMap<Key, Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
type Query = QueryKind::Query;
|
||||
fn module_prefix() -> &'static [u8] {
|
||||
@@ -78,14 +83,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> crate::storage::StoragePrefixedMap<Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::storage::StoragePrefixedMap<Value>
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn module_prefix() -> &'static [u8] {
|
||||
<Self as crate::storage::generator::StorageNMap<Key, Value>>::module_prefix()
|
||||
@@ -95,13 +102,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// 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> {
|
||||
@@ -286,13 +295,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::ReversibleKeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
/// Enumerate all elements in the map with prefix key `kp` in no particular order.
|
||||
///
|
||||
@@ -355,14 +366,15 @@ pub trait StorageNMapMetadata {
|
||||
const HASHERS: &'static [frame_metadata::StorageHasher];
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty> StorageNMapMetadata
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty>
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues> StorageNMapMetadata
|
||||
for StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator,
|
||||
Value: FullCodec,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
const MODIFIER: StorageEntryModifier = QueryKind::METADATA;
|
||||
const NAME: &'static str = Prefix::STORAGE_PREFIX;
|
||||
@@ -372,6 +384,32 @@ where
|
||||
const HASHERS: &'static [frame_metadata::StorageHasher] = Key::HASHER_METADATA;
|
||||
}
|
||||
|
||||
impl<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
crate::traits::StorageInfoTrait for
|
||||
StorageNMap<Prefix, Key, Value, QueryKind, OnEmpty, MaxValues>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Key: super::key::KeyGenerator + super::key::KeyGeneratorMaxEncodedLen,
|
||||
Value: FullCodec + MaxEncodedLen,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: Get<QueryKind::Query> + 'static,
|
||||
MaxValues: Get<Option<u32>>,
|
||||
{
|
||||
fn storage_info() -> Vec<StorageInfo> {
|
||||
vec![
|
||||
StorageInfo {
|
||||
prefix: Self::final_prefix(),
|
||||
max_values: MaxValues::get(),
|
||||
max_size: Some(
|
||||
Key::key_max_encoded_len()
|
||||
.saturating_add(Value::max_encoded_len())
|
||||
.saturated_into(),
|
||||
),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
@@ -24,9 +24,11 @@ use crate::{
|
||||
bounded_vec::BoundedVec,
|
||||
types::{OptionQuery, QueryKindTrait, OnEmptyGetter},
|
||||
},
|
||||
traits::{GetDefault, StorageInstance, Get},
|
||||
traits::{GetDefault, StorageInstance, Get, MaxEncodedLen, StorageInfo},
|
||||
};
|
||||
use frame_metadata::{DefaultByteGetter, StorageEntryModifier};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
use sp_std::prelude::*;
|
||||
|
||||
/// A type that allow to store a value.
|
||||
///
|
||||
@@ -212,6 +214,29 @@ impl<Prefix, Value, QueryKind, OnEmpty> StorageValueMetadata
|
||||
DefaultByteGetter(&OnEmptyGetter::<QueryKind::Query, OnEmpty>(core::marker::PhantomData));
|
||||
}
|
||||
|
||||
impl<Prefix, Value, QueryKind, OnEmpty>
|
||||
crate::traits::StorageInfoTrait for
|
||||
StorageValue<Prefix, Value, QueryKind, OnEmpty>
|
||||
where
|
||||
Prefix: StorageInstance,
|
||||
Value: FullCodec + MaxEncodedLen,
|
||||
QueryKind: QueryKindTrait<Value, OnEmpty>,
|
||||
OnEmpty: crate::traits::Get<QueryKind::Query> + 'static
|
||||
{
|
||||
fn storage_info() -> Vec<StorageInfo> {
|
||||
vec![
|
||||
StorageInfo {
|
||||
prefix: Self::hashed_key(),
|
||||
max_values: Some(1),
|
||||
max_size: Some(
|
||||
Value::max_encoded_len()
|
||||
.saturated_into(),
|
||||
),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user