Switch srml-session keys to decl_storage! (#3184)

* Switch `srml-session` keys to `decl_storage!`

* Expose `DEDUP_KEY_PREFIX` in constants

* Fix test

* Bump spec version
This commit is contained in:
Bastian Köcher
2019-07-24 10:40:04 +02:00
committed by Gavin Wood
parent c8dab27f35
commit 5d58d583e3
14 changed files with 365 additions and 201 deletions
+2 -2
View File
@@ -75,8 +75,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
// and set impl_version to equal spec_version. If only runtime // and set impl_version to equal spec_version. If only runtime
// implementation changes and behavior does not, then leave spec_version as // implementation changes and behavior does not, then leave spec_version as
// is and increment impl_version. // is and increment impl_version.
spec_version: 117, spec_version: 118,
impl_version: 117, impl_version: 118,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
+4 -4
View File
@@ -336,7 +336,7 @@ decl_module! {
<NextAssetId<T>>::put(next_id); <NextAssetId<T>>::put(next_id);
<TotalIssuance<T>>::insert(id, &options.initial_issuance); <TotalIssuance<T>>::insert(id, &options.initial_issuance);
<FreeBalance<T>>::insert(&id, &origin, options.initial_issuance); <FreeBalance<T>>::insert(&id, &origin, &options.initial_issuance);
<Permissions<T>>::insert(&id, permissions); <Permissions<T>>::insert(&id, permissions);
Self::deposit_event(RawEvent::Created(id, origin, options)); Self::deposit_event(RawEvent::Created(id, origin, options));
@@ -560,7 +560,7 @@ impl<T: Trait> Module<T> {
let permissions: PermissionVersions<T::AccountId> = options.permissions.clone().into(); let permissions: PermissionVersions<T::AccountId> = options.permissions.clone().into();
<TotalIssuance<T>>::insert(asset_id, &options.initial_issuance); <TotalIssuance<T>>::insert(asset_id, &options.initial_issuance);
<FreeBalance<T>>::insert(&asset_id, &account_id, options.initial_issuance); <FreeBalance<T>>::insert(&asset_id, &account_id, &options.initial_issuance);
<Permissions<T>>::insert(&asset_id, permissions); <Permissions<T>>::insert(&asset_id, permissions);
Self::deposit_event(RawEvent::Created(asset_id, account_id, options)); Self::deposit_event(RawEvent::Created(asset_id, account_id, options));
@@ -768,13 +768,13 @@ impl<T: Trait> Module<T> {
/// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that
/// the caller will do this. /// the caller will do this.
fn set_reserved_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) { fn set_reserved_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) {
<ReservedBalance<T>>::insert(asset_id, who, balance); <ReservedBalance<T>>::insert(asset_id, who, &balance);
} }
/// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that /// NOTE: LOW-LEVEL: This will not attempt to maintain total issuance. It is expected that
/// the caller will do this. /// the caller will do this.
fn set_free_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) { fn set_free_balance(asset_id: &T::AssetId, who: &T::AccountId, balance: T::Balance) {
<FreeBalance<T>>::insert(asset_id, who, balance); <FreeBalance<T>>::insert(asset_id, who, &balance);
} }
fn set_lock( fn set_lock(
+7 -7
View File
@@ -200,13 +200,13 @@ decl_module! {
ensure_none(origin)?; ensure_none(origin)?;
let current_session = <session::Module<T>>::current_index(); let current_session = <session::Module<T>>::current_index();
let exists = <ReceivedHeartbeats<T>>::exists(current_session, &heartbeat.authority_id); let exists = <ReceivedHeartbeats<T>>::exists(&current_session, &heartbeat.authority_id);
if !exists { if !exists {
let now = <system::Module<T>>::block_number(); let now = <system::Module<T>>::block_number();
Self::deposit_event(RawEvent::HeartbeatReceived(now, heartbeat.authority_id.clone())); Self::deposit_event(RawEvent::HeartbeatReceived(now, heartbeat.authority_id.clone()));
let network_state = heartbeat.network_state.encode(); let network_state = heartbeat.network_state.encode();
<ReceivedHeartbeats<T>>::insert(current_session, &heartbeat.authority_id, network_state); <ReceivedHeartbeats<T>>::insert(&current_session, &heartbeat.authority_id, &network_state);
} }
} }
@@ -301,13 +301,13 @@ impl<T: Trait> Module<T> {
Some(start) => { Some(start) => {
// iterate over every session // iterate over every session
for index in start..curr { for index in start..curr {
if <ReceivedHeartbeats<T>>::exists(index, authority_id) { if <ReceivedHeartbeats<T>>::exists(&index, authority_id) {
return true; return true;
} }
} }
false false
}, },
None => <ReceivedHeartbeats<T>>::exists(curr, authority_id), None => <ReceivedHeartbeats<T>>::exists(&curr, authority_id),
} }
} }
@@ -315,7 +315,7 @@ impl<T: Trait> Module<T> {
/// during the current session. Otherwise `false`. /// during the current session. Otherwise `false`.
pub fn is_online_in_current_session(authority_id: &T::AuthorityId) -> bool { pub fn is_online_in_current_session(authority_id: &T::AuthorityId) -> bool {
let current_session = <session::Module<T>>::current_index(); let current_session = <session::Module<T>>::current_index();
<ReceivedHeartbeats<T>>::exists(current_session, authority_id) <ReceivedHeartbeats<T>>::exists(&current_session, authority_id)
} }
/// Session has just changed. /// Session has just changed.
@@ -345,10 +345,10 @@ impl<T: Trait> Module<T> {
match LastNewEraStart::get() { match LastNewEraStart::get() {
Some(start) => { Some(start) => {
for index in start..curr { for index in start..curr {
<ReceivedHeartbeats<T>>::remove_prefix(index); <ReceivedHeartbeats<T>>::remove_prefix(&index);
} }
}, },
None => <ReceivedHeartbeats<T>>::remove_prefix(curr), None => <ReceivedHeartbeats<T>>::remove_prefix(&curr),
} }
} }
} }
+26 -30
View File
@@ -120,14 +120,12 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}}; use rstd::{prelude::*, marker::PhantomData, ops::{Sub, Rem}};
use parity_codec::{Decode, Encode}; use parity_codec::Decode;
use primitives::KeyTypeId; use primitives::KeyTypeId;
use primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey, Hash}; use primitives::traits::{Convert, Zero, Member, OpaqueKeys, TypedKey};
use srml_support::{ use srml_support::{
dispatch::Result, dispatch::Result, ConsensusEngineId, StorageValue, StorageDoubleMap, for_each_tuple,
storage, decl_module, decl_event, decl_storage,
ConsensusEngineId, StorageValue, for_each_tuple, decl_module,
decl_event, decl_storage,
}; };
use srml_support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor}, Parameter}; use srml_support::{ensure, traits::{OnFreeBalanceZero, Get, FindAuthor}, Parameter};
use system::{self, ensure_signed}; use system::{self, ensure_signed};
@@ -283,8 +281,7 @@ pub trait Trait: system::Trait {
type SelectInitialValidators: SelectInitialValidators<Self::ValidatorId>; type SelectInitialValidators: SelectInitialValidators<Self::ValidatorId>;
} }
const DEDUP_KEY_LEN: usize = 13; const DEDUP_KEY_PREFIX: &[u8] = b":session:keys";
const DEDUP_KEY_PREFIX: &[u8; DEDUP_KEY_LEN] = b":session:keys";
decl_storage! { decl_storage! {
trait Store for Module<T: Trait> as Session { trait Store for Module<T: Trait> as Session {
@@ -304,6 +301,17 @@ decl_storage! {
/// will be used to determine the validator's session keys. /// will be used to determine the validator's session keys.
QueuedKeys get(queued_keys): Vec<(T::ValidatorId, T::Keys)>; QueuedKeys get(queued_keys): Vec<(T::ValidatorId, T::Keys)>;
/// The next session keys for a validator.
///
/// The first key is always `DEDUP_KEY_PREFIX` to have all the data in the same branch of
/// the trie. Having all data in the same branch should prevent slowing down other queries.
NextKeys: double_map hasher(twox_64_concat) Vec<u8>, blake2_256(T::ValidatorId) => Option<T::Keys>;
/// The owner of a key. The second key is the `KeyTypeId` + the encoded key.
///
/// The first key is always `DEDUP_KEY_PREFIX` to have all the data in the same branch of
/// the trie. Having all data in the same branch should prevent slowing down other queries.
KeyOwner: double_map hasher(twox_64_concat) Vec<u8>, blake2_256((KeyTypeId, Vec<u8>)) => Option<T::ValidatorId>;
} }
add_extra_genesis { add_extra_genesis {
config(keys): Vec<(T::ValidatorId, T::Keys)>; config(keys): Vec<(T::ValidatorId, T::Keys)>;
@@ -354,6 +362,10 @@ decl_event!(
decl_module! { decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { pub struct Module<T: Trait> for enum Call where origin: T::Origin {
/// Used as first key for `NextKeys` and `KeyOwner` to put all the data into the same branch
/// of the trie.
const DEDUP_KEY_PREFIX: &[u8] = DEDUP_KEY_PREFIX;
fn deposit_event() = default; fn deposit_event() = default;
/// Sets the session key(s) of the function caller to `key`. /// Sets the session key(s) of the function caller to `key`.
@@ -494,47 +506,31 @@ impl<T: Trait> Module<T> {
} }
} }
// Child trie storage.
fn load_keys(v: &T::ValidatorId) -> Option<T::Keys> { fn load_keys(v: &T::ValidatorId) -> Option<T::Keys> {
storage::unhashed::get(&dedup_trie_key::<T, _>(v)) <NextKeys<T>>::get(DEDUP_KEY_PREFIX, v)
} }
fn take_keys(v: &T::ValidatorId) -> Option<T::Keys> { fn take_keys(v: &T::ValidatorId) -> Option<T::Keys> {
storage::unhashed::take(&dedup_trie_key::<T, _>(v)) <NextKeys<T>>::take(DEDUP_KEY_PREFIX, v)
} }
fn put_keys(v: &T::ValidatorId, keys: &T::Keys) { fn put_keys(v: &T::ValidatorId, keys: &T::Keys) {
storage::unhashed::put(&dedup_trie_key::<T, _>(v), keys) <NextKeys<T>>::insert(DEDUP_KEY_PREFIX, v, keys);
} }
fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option<T::ValidatorId> { fn key_owner(id: KeyTypeId, key_data: &[u8]) -> Option<T::ValidatorId> {
storage::unhashed::get(&dedup_trie_key::<T, _>(&(id, key_data))) <KeyOwner<T>>::get(DEDUP_KEY_PREFIX, &(id, key_data.to_vec()))
} }
fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) { fn put_key_owner(id: KeyTypeId, key_data: &[u8], v: &T::ValidatorId) {
storage::unhashed::put(&dedup_trie_key::<T, _>(&(id, key_data)), v); <KeyOwner<T>>::insert(DEDUP_KEY_PREFIX, &(id, key_data.to_vec()), v)
} }
fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) { fn clear_key_owner(id: KeyTypeId, key_data: &[u8]) {
storage::unhashed::kill(&dedup_trie_key::<T, _>(&(id, key_data))); <KeyOwner<T>>::remove(DEDUP_KEY_PREFIX, &(id, key_data.to_vec()));
} }
} }
fn dedup_trie_key<T: Trait, K: Encode>(key: &K) -> [u8; 32 + DEDUP_KEY_LEN] {
key.using_encoded(|s| {
// take at most 32 bytes from the hash of the value.
let hash = <T as system::Trait>::Hashing::hash(s);
let hash: &[u8] = hash.as_ref();
let len = rstd::cmp::min(hash.len(), 32);
let mut data = [0; 32 + DEDUP_KEY_LEN];
data[..DEDUP_KEY_LEN].copy_from_slice(DEDUP_KEY_PREFIX);
data[DEDUP_KEY_LEN..][..len].copy_from_slice(hash);
data
})
}
impl<T: Trait> OnFreeBalanceZero<T::ValidatorId> for Module<T> { impl<T: Trait> OnFreeBalanceZero<T::ValidatorId> for Module<T> {
fn on_free_balance_zero(who: &T::ValidatorId) { fn on_free_balance_zero(who: &T::ValidatorId) {
Self::prune_dead_keys(who); Self::prune_dead_keys(who);
+1 -1
View File
@@ -18,7 +18,7 @@
//! Proc macro of Support code for the runtime. //! Proc macro of Support code for the runtime.
// end::description[] // end::description[]
#![recursion_limit="256"] #![recursion_limit="512"]
extern crate proc_macro; extern crate proc_macro;
@@ -694,13 +694,18 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
let mutate_impl = if !is_option { let mutate_impl = if !is_option {
quote!{ quote!{
#as_double_map::insert(key1, key2, &val, storage) #as_double_map::insert(k1, k2, &val, storage)
} }
} else { } else {
quote!{ quote!{
match val { match val {
Some(ref val) => #as_double_map::insert(key1, key2, &val, storage), Some(ref val) => #as_double_map::insert::<KArg1, KArg2, #typ, S>(
None => #as_double_map::remove(key1, key2, storage), k1,
k2,
val,
storage,
),
None => #as_double_map::remove(k1, k2, storage),
} }
} }
}; };
@@ -751,7 +756,10 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
{ {
type Query = #value_type; type Query = #value_type;
fn prefix_for(k1: &#k1ty) -> Vec<u8> { fn prefix_for<KArg1>(k1: &KArg1) -> #scrate::rstd::vec::Vec<u8> where
KArg1: ?Sized + #scrate::codec::Encode,
#k1ty: #scrate::rstd::borrow::Borrow<KArg1>,
{
use #scrate::storage::hashed::generator::StorageHasher; use #scrate::storage::hashed::generator::StorageHasher;
let mut key = #as_double_map::prefix().to_vec(); let mut key = #as_double_map::prefix().to_vec();
@@ -763,7 +771,15 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#final_prefix #final_prefix
} }
fn key_for(k1: &#k1ty, k2: &#k2ty) -> Vec<u8> { fn key_for<KArg1, KArg2>(
k1: &KArg1,
k2: &KArg2,
) -> #scrate::rstd::vec::Vec<u8> where
#k1ty: #scrate::rstd::borrow::Borrow<KArg1>,
#k2ty: #scrate::rstd::borrow::Borrow<KArg2>,
KArg1: ?Sized + #scrate::codec::Encode,
KArg2: ?Sized + #scrate::codec::Encode,
{
use #scrate::storage::hashed::generator::StorageHasher; use #scrate::storage::hashed::generator::StorageHasher;
let mut key = #as_double_map::prefix_for(k1); let mut key = #as_double_map::prefix_for(k1);
@@ -771,25 +787,50 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
key key
} }
fn get<S: #scrate::UnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query { fn get<KArg1, KArg2, S: #scrate::UnhashedStorage>(
let key = #as_double_map::key_for(key1, key2); k1: &KArg1,
k2: &KArg2,
storage: &S,
) -> Self::Query where
#k1ty: #scrate::rstd::borrow::Borrow<KArg1>,
#k2ty: #scrate::rstd::borrow::Borrow<KArg2>,
KArg1: ?Sized + #scrate::codec::Encode,
KArg2: ?Sized + #scrate::codec::Encode,
{
let key = #as_double_map::key_for(k1, k2);
storage.get(&key).#option_simple_1(|| #fielddefault) storage.get(&key).#option_simple_1(|| #fielddefault)
} }
fn take<S: #scrate::UnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &mut S) -> Self::Query { fn take<KArg1, KArg2, S: #scrate::UnhashedStorage>(
let key = #as_double_map::key_for(key1, key2); k1: &KArg1,
k2: &KArg2,
storage: &mut S,
) -> Self::Query where
#k1ty: #scrate::rstd::borrow::Borrow<KArg1>,
#k2ty: #scrate::rstd::borrow::Borrow<KArg2>,
KArg1: ?Sized + #scrate::codec::Encode,
KArg2: ?Sized + #scrate::codec::Encode,
{
let key = #as_double_map::key_for(k1, k2);
storage.take(&key).#option_simple_1(|| #fielddefault) storage.take(&key).#option_simple_1(|| #fielddefault)
} }
fn mutate<R, F, S>(key1: &#k1ty, key2: &#k2ty, f: F, storage: &mut S) -> R fn mutate<KArg1, KArg2, R, F, S: #scrate::UnhashedStorage>(
where k1: &KArg1,
k2: &KArg2,
f: F,
storage: &mut S,
) -> R where
#k1ty: #scrate::rstd::borrow::Borrow<KArg1>,
#k2ty: #scrate::rstd::borrow::Borrow<KArg2>,
KArg1: ?Sized + #scrate::codec::Encode,
KArg2: ?Sized + #scrate::codec::Encode,
F: FnOnce(&mut Self::Query) -> R, F: FnOnce(&mut Self::Query) -> R,
S: #scrate::UnhashedStorage,
{ {
let mut val = #as_double_map::get(key1, key2, storage); let mut val = #as_double_map::get(k1, k2, storage);
let ret = f(&mut val); let ret = f(&mut val);
#mutate_impl ; #mutate_impl;
ret ret
} }
} }
@@ -905,15 +905,17 @@ fn impl_store_fns(
}; };
quote!{ quote!{
pub fn #get_fn<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #value_type pub fn #get_fn<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> #value_type
where where
KArg1: #scrate::rstd::borrow::Borrow<#key1_type>, #key1_type: #scrate::rstd::borrow::Borrow<KArg1>,
KArg2: #scrate::rstd::borrow::Borrow<#key2_type>, #key2_type: #scrate::rstd::borrow::Borrow<KArg2>,
KArg1: ?Sized + #scrate::codec::Encode,
KArg2: ?Sized + #scrate::codec::Encode,
{ {
< <
#name<#struct_trait #instance> as #name<#struct_trait #instance> as
#scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ> #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>
>::get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage) >::get(k1, k2, &#scrate::storage::RuntimeStorage)
} }
} }
} }
+2 -2
View File
@@ -34,8 +34,8 @@ use sr_std::borrow::Borrow;
/// ///
/// Hasher are implemented in derive_key* methods. /// Hasher are implemented in derive_key* methods.
pub trait StorageDoubleMapWithHasher { pub trait StorageDoubleMapWithHasher {
type Key1: Codec; type Key1: Encode;
type Key2: Codec; type Key2: Encode;
type Value: Codec + Default; type Value: Codec + Default;
const PREFIX: &'static [u8]; const PREFIX: &'static [u8];
+21 -21
View File
@@ -387,32 +387,32 @@ mod tests {
// get / insert / take // get / insert / take
let key1 = 17u32; let key1 = 17u32;
let key2 = 18u32; let key2 = 18u32;
assert_eq!(DoubleMap::get(key1, key2), 0u64); assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(key1, key2, 4u64); DoubleMap::insert(&key1, &key2, &4u64);
assert_eq!(DoubleMap::get(key1, key2), 4u64); assert_eq!(DoubleMap::get(&key1, &key2), 4u64);
assert_eq!(DoubleMap::take(key1, key2), 4u64); assert_eq!(DoubleMap::take(&key1, &key2), 4u64);
assert_eq!(DoubleMap::get(key1, key2), 0u64); assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
// mutate // mutate
DoubleMap::mutate(key1, key2, |val| { DoubleMap::mutate(&key1, &key2, |val| {
*val = 15; *val = 15;
}); });
assert_eq!(DoubleMap::get(key1, key2), 15u64); assert_eq!(DoubleMap::get(&key1, &key2), 15u64);
// remove // remove
DoubleMap::remove(key1, key2); DoubleMap::remove(&key1, &key2);
assert_eq!(DoubleMap::get(key1, key2), 0u64); assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
// remove prefix // remove prefix
DoubleMap::insert(key1, key2, 4u64); DoubleMap::insert(&key1, &key2, &4u64);
DoubleMap::insert(key1, key2+1, 4u64); DoubleMap::insert(&key1, &(key2 + 1), &4u64);
DoubleMap::insert(key1+1, key2, 4u64); DoubleMap::insert(&(key1 + 1), &key2, &4u64);
DoubleMap::insert(key1+1, key2+1, 4u64); DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64);
DoubleMap::remove_prefix(key1); DoubleMap::remove_prefix(&key1);
assert_eq!(DoubleMap::get(key1, key2), 0u64); assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
assert_eq!(DoubleMap::get(key1, key2+1), 0u64); assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64);
assert_eq!(DoubleMap::get(key1+1, key2), 4u64); assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64);
assert_eq!(DoubleMap::get(key1+1, key2+1), 4u64); assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64);
}); });
} }
@@ -425,9 +425,9 @@ mod tests {
let key1 = 17u32; let key1 = 17u32;
let key2 = 18u32; let key2 = 18u32;
DoubleMap::insert(key1, key2, vec![1]); DoubleMap::insert(&key1, &key2, &vec![1]);
DoubleMap::append(key1, key2, &[2, 3]).unwrap(); DoubleMap::append(&key1, &key2, &[2, 3]).unwrap();
assert_eq!(DoubleMap::get(key1, key2), vec![1, 2, 3]); assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2, 3]);
}); });
} }
+134 -69
View File
@@ -104,7 +104,7 @@ impl UnhashedStorage for RuntimeStorage {
} }
/// Put a value in under a key. /// Put a value in under a key.
fn put<T: Encode>(&mut self, key: &[u8], val: &T) { fn put<T: Encode + ?Sized>(&mut self, key: &[u8], val: &T) {
unhashed::put(key, val) unhashed::put(key, val)
} }
@@ -332,60 +332,83 @@ impl<K: Codec, V: Codec, U> EnumerableStorageMap<K, V> for U
/// is a hash of a `Key2`. /// is a hash of a `Key2`.
/// ///
/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. /// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie.
pub trait StorageDoubleMap<K1: Codec, K2: Codec, V: Codec> { pub trait StorageDoubleMap<K1: Encode, K2: Encode, V: Codec> {
/// The type that get/take returns. /// The type that get/take returns.
type Query; type Query;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8]; fn prefix() -> &'static [u8];
/// Get the storage key used to fetch a value corresponding to a specific key. fn key_for<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Vec<u8>
fn key_for<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Vec<u8>;
/// Get the storage prefix used to fetch keys corresponding to a specific key1.
fn prefix_for<KArg1: Borrow<K1>>(k1: KArg1) -> Vec<u8>;
/// true if the value is defined in storage.
fn exists<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> bool;
/// Load the value associated with the given key from the map.
fn get<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Self::Query;
/// Take the value under a key.
fn take<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Self::Query;
/// Store a value to be associated with the given key from the map.
fn insert<KArg1: Borrow<K1>, KArg2: Borrow<K2>, VArg: Borrow<V>>(k1: KArg1, k2: KArg2, val: VArg);
/// Remove the value under a key.
fn remove<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2);
/// Removes all entries that shares the `k1` as the first key.
fn remove_prefix<KArg1: Borrow<K1>>(k1: KArg1);
/// Mutate the value under a key.
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
where where
KArg1: Borrow<K1>, K1: Borrow<KArg1>,
KArg2: Borrow<K2>, K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
fn prefix_for<KArg1>(k1: &KArg1) -> Vec<u8> where KArg1: ?Sized + Encode, K1: Borrow<KArg1>;
fn exists<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> bool
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
fn get<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Self::Query
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
fn take<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Self::Query
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
fn insert<KArg1, KArg2, VArg>(k1: &KArg1, k2: &KArg2, val: &VArg)
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
V: Borrow<VArg>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
VArg: ?Sized + Encode;
fn remove<KArg1, KArg2>(k1: &KArg1, k2: &KArg2)
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
fn remove_prefix<KArg1>(k1: &KArg1) where KArg1: ?Sized + Encode, K1: Borrow<KArg1>;
fn mutate<KArg1, KArg2, R, F>(k1: &KArg1, k2: &KArg2, f: F) -> R
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
F: FnOnce(&mut Self::Query) -> R; F: FnOnce(&mut Self::Query) -> R;
/// Append the given items to the value under the key specified.
///
/// `V` is required to implement `codec::EncodeAppend<Item=I>`.
fn append<KArg1, KArg2, I>( fn append<KArg1, KArg2, I>(
k1: KArg1, k1: &KArg1,
k2: KArg2, k2: &KArg2,
items: &[I], items: &[I],
) -> Result<(), &'static str> ) -> Result<(), &'static str>
where where
KArg1: Borrow<K1>, K1: Borrow<KArg1>,
KArg2: Borrow<K2>, K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
I: codec::Encode, I: codec::Encode,
V: EncodeAppend<Item=I>; V: EncodeAppend<Item=I>;
} }
impl<K1: Codec, K2: Codec, V: Codec, U> StorageDoubleMap<K1, K2, V> for U impl<K1: Encode, K2: Encode, V: Codec, U> StorageDoubleMap<K1, K2, V> for U
where where
U: unhashed::generator::StorageDoubleMap<K1, K2, V> U: unhashed::generator::StorageDoubleMap<K1, K2, V>
{ {
@@ -395,59 +418,101 @@ where
<U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::prefix() <U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::prefix()
} }
fn key_for<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Vec<u8> { fn key_for<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Vec<u8>
<U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::key_for(k1.borrow(), k2.borrow()) where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
{
<U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::key_for(k1, k2)
} }
fn prefix_for<KArg1: Borrow<K1>>(k1: KArg1) -> Vec<u8> { fn prefix_for<KArg1>(k1: &KArg1) -> Vec<u8> where KArg1: ?Sized + Encode, K1: Borrow<KArg1> {
<U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::prefix_for(k1.borrow()) <U as unhashed::generator::StorageDoubleMap<K1, K2, V>>::prefix_for(k1)
} }
fn exists<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> bool { fn exists<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> bool
U::exists(k1.borrow(), k2.borrow(), &RuntimeStorage) where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
{
U::exists(k1, k2, &RuntimeStorage)
} }
fn get<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Self::Query { fn get<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Self::Query
U::get(k1.borrow(), k2.borrow(), &RuntimeStorage) where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
{
U::get(k1, k2, &RuntimeStorage)
} }
fn take<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) -> Self::Query { fn take<KArg1, KArg2>(k1: &KArg1, k2: &KArg2) -> Self::Query
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
{
U::take(k1.borrow(), k2.borrow(), &mut RuntimeStorage) U::take(k1.borrow(), k2.borrow(), &mut RuntimeStorage)
} }
fn insert<KArg1: Borrow<K1>, KArg2: Borrow<K2>, VArg: Borrow<V>>(k1: KArg1, k2: KArg2, val: VArg) { fn insert<KArg1, KArg2, VArg>(k1: &KArg1, k2: &KArg2, val: &VArg)
U::insert(k1.borrow(), k2.borrow(), val.borrow(), &mut RuntimeStorage)
}
fn remove<KArg1: Borrow<K1>, KArg2: Borrow<K2>>(k1: KArg1, k2: KArg2) {
U::remove(k1.borrow(), k2.borrow(), &mut RuntimeStorage)
}
fn remove_prefix<KArg1: Borrow<K1>>(k1: KArg1) {
U::remove_prefix(k1.borrow(), &mut RuntimeStorage)
}
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
where where
KArg1: Borrow<K1>, K1: Borrow<KArg1>,
KArg2: Borrow<K2>, K2: Borrow<KArg2>,
V: Borrow<VArg>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
VArg: ?Sized + Encode,
{
U::insert(k1, k2, val, &mut RuntimeStorage)
}
fn remove<KArg1, KArg2>(k1: &KArg1, k2: &KArg2)
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
{
U::remove(k1, k2, &mut RuntimeStorage)
}
fn remove_prefix<KArg1>(k1: &KArg1) where KArg1: ?Sized + Encode, K1: Borrow<KArg1> {
U::remove_prefix(k1, &mut RuntimeStorage)
}
fn mutate<KArg1, KArg2, R, F>(k1: &KArg1, k2: &KArg2, f: F) -> R
where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
F: FnOnce(&mut Self::Query) -> R F: FnOnce(&mut Self::Query) -> R
{ {
U::mutate(k1.borrow(), k2.borrow(), f, &mut RuntimeStorage) U::mutate(k1, k2, f, &mut RuntimeStorage)
} }
fn append<KArg1, KArg2, I>( fn append<KArg1, KArg2, I>(
k1: KArg1, k1: &KArg1,
k2: KArg2, k2: &KArg2,
items: &[I], items: &[I],
) -> Result<(), &'static str> ) -> Result<(), &'static str>
where where
KArg1: Borrow<K1>, K1: Borrow<KArg1>,
KArg2: Borrow<K2>, K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
I: codec::Encode, I: codec::Encode,
V: EncodeAppend<Item=I>, V: EncodeAppend<Item=I>,
{ {
U::append(k1.borrow(), k2.borrow(), items, &mut RuntimeStorage) U::append(k1, k2, items, &mut RuntimeStorage)
} }
} }
@@ -14,8 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::codec; use crate::codec::{self, Encode, EncodeAppend};
use crate::rstd::vec::Vec; use crate::rstd::{borrow::Borrow, vec::Vec};
/// Abstraction around storage with unhashed access. /// Abstraction around storage with unhashed access.
pub trait UnhashedStorage { pub trait UnhashedStorage {
@@ -38,7 +38,7 @@ pub trait UnhashedStorage {
} }
/// Put a value in under a key. /// Put a value in under a key.
fn put<T: codec::Encode>(&mut self, key: &[u8], val: &T); fn put<T: codec::Encode + ?Sized>(&mut self, key: &[u8], val: &T);
/// Remove the bytes of a key from storage. /// Remove the bytes of a key from storage.
fn kill(&mut self, key: &[u8]); fn kill(&mut self, key: &[u8]);
@@ -82,7 +82,7 @@ impl UnhashedStorage for sr_primitives::StorageOverlay {
.map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type.")) .map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type."))
} }
fn put<T: codec::Encode>(&mut self, key: &[u8], val: &T) { fn put<T: codec::Encode + ?Sized>(&mut self, key: &[u8], val: &T) {
self.insert(key.to_vec(), codec::Encode::encode(val)); self.insert(key.to_vec(), codec::Encode::encode(val));
} }
@@ -117,7 +117,7 @@ impl UnhashedStorage for sr_primitives::StorageOverlay {
/// is a hash of a `Key2`. /// is a hash of a `Key2`.
/// ///
/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. /// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie.
pub trait StorageDoubleMap<K1: codec::Codec, K2: codec::Codec, V: codec::Codec> { pub trait StorageDoubleMap<K1: codec::Encode, K2: codec::Encode, V: codec::Codec> {
/// The type that get/take returns. /// The type that get/take returns.
type Query; type Query;
@@ -125,50 +125,110 @@ pub trait StorageDoubleMap<K1: codec::Codec, K2: codec::Codec, V: codec::Codec>
fn prefix() -> &'static [u8]; fn prefix() -> &'static [u8];
/// Get the storage key used to fetch a value corresponding to a specific key. /// Get the storage key used to fetch a value corresponding to a specific key.
fn key_for(k1: &K1, k2: &K2) -> Vec<u8>; fn key_for<KArg1, KArg2>(
k1: &KArg1,
k2: &KArg2,
) -> Vec<u8> where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
/// Get the storage prefix used to fetch keys corresponding to a specific key1. /// Get the storage prefix used to fetch keys corresponding to a specific key1.
fn prefix_for(k1: &K1) -> Vec<u8>; fn prefix_for<KArg1>(k1: &KArg1) -> Vec<u8> where KArg1: ?Sized + Encode, K1: Borrow<KArg1>;
/// true if the value is defined in storage. /// true if the value is defined in storage.
fn exists<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &S) -> bool { fn exists<KArg1, KArg2, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
storage: &S,
) -> bool where K1: Borrow<KArg1>, K2: Borrow<KArg2>, KArg1: ?Sized + Encode, KArg2: ?Sized + Encode {
storage.exists(&Self::key_for(k1, k2)) storage.exists(&Self::key_for(k1, k2))
} }
/// Load the value associated with the given key from the map. /// Load the value associated with the given key from the map.
fn get<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &S) -> Self::Query; fn get<KArg1, KArg2, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
storage: &S,
) -> Self::Query where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
/// Take the value under a key. /// Take the value under a key.
fn take<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &mut S) -> Self::Query; fn take<KArg1, KArg2, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
storage: &mut S,
) -> Self::Query where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode;
/// Store a value to be associated with the given key from the map. /// Store a value to be associated with the given key from the map.
fn insert<S: UnhashedStorage>(k1: &K1, k2: &K2, val: &V, storage: &mut S) { fn insert<KArg1, KArg2, VArg, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
val: &VArg,
storage: &mut S,
) where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
V: Borrow<VArg>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
VArg: ?Sized + Encode,
{
storage.put(&Self::key_for(k1, k2), val); storage.put(&Self::key_for(k1, k2), val);
} }
/// Remove the value under a key. /// Remove the value under a key.
fn remove<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &mut S) { fn remove<KArg1, KArg2, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
storage: &mut S,
) where K1: Borrow<KArg1>, K2: Borrow<KArg2>, KArg1: ?Sized + Encode, KArg2: ?Sized + Encode {
storage.kill(&Self::key_for(k1, k2)); storage.kill(&Self::key_for(k1, k2));
} }
/// Removes all entries that shares the `k1` as the first key. /// Removes all entries that shares the `k1` as the first key.
fn remove_prefix<S: UnhashedStorage>(k1: &K1, storage: &mut S) { fn remove_prefix<KArg1, S: UnhashedStorage>(
k1: &KArg1,
storage: &mut S,
) where KArg1: ?Sized + Encode, K1: Borrow<KArg1> {
storage.kill_prefix(&Self::prefix_for(k1)); storage.kill_prefix(&Self::prefix_for(k1));
} }
/// Mutate the value under a key. /// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: UnhashedStorage>(k1: &K1, k2: &K2, f: F, storage: &mut S) -> R; fn mutate<KArg1, KArg2, R, F, S: UnhashedStorage>(
k1: &KArg1,
k2: &KArg2,
f: F,
storage: &mut S,
) -> R where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
F: FnOnce(&mut Self::Query) -> R;
/// Append the given items to the value under the key specified. /// Append the given items to the value under the key specified.
fn append<I, S: UnhashedStorage>( fn append<KArg1, KArg2, I, S: UnhashedStorage>(
k1: &K1, k1: &KArg1,
k2: &K2, k2: &KArg2,
items: &[I], items: &[I],
storage: &mut S, storage: &mut S,
) -> Result<(), &'static str> ) -> Result<(), &'static str>
where where
K1: Borrow<KArg1>,
K2: Borrow<KArg2>,
KArg1: ?Sized + Encode,
KArg2: ?Sized + Encode,
I: codec::Encode, I: codec::Encode,
V: codec::EncodeAppend<Item=I>, V: EncodeAppend<Item=I>,
{ {
let key = Self::key_for(k1, k2); let key = Self::key_for(k1, k2);
let new_val = <V as codec::EncodeAppend>::append( let new_val = <V as codec::EncodeAppend>::append(
@@ -51,7 +51,7 @@ pub fn get_or_else<T: Decode + Sized, F: FnOnce() -> T>(key: &[u8], default_valu
} }
/// Put `value` in storage under `key`. /// Put `value` in storage under `key`.
pub fn put<T: Encode>(key: &[u8], value: &T) { pub fn put<T: Encode + ?Sized>(key: &[u8], value: &T) {
value.using_encoded(|slice| runtime_io::set_storage(key, slice)); value.using_encoded(|slice| runtime_io::set_storage(key, slice));
} }
+10 -10
View File
@@ -29,7 +29,7 @@ srml_support::decl_module! {
} }
srml_support::decl_storage!{ srml_support::decl_storage!{
trait Store for Module<T: Trait> as Module { trait Store for Module<T: Trait> as FinalKeys {
pub Value config(value): u32; pub Value config(value): u32;
pub Map: map u32 => u32; pub Map: map u32 => u32;
@@ -60,37 +60,37 @@ fn new_test_ext() -> runtime_io::TestExternalities<Blake2Hasher> {
fn final_keys() { fn final_keys() {
with_externalities(&mut new_test_ext(), || { with_externalities(&mut new_test_ext(), || {
Value::put(1); Value::put(1);
assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(b"Module Value")), Some(1u32)); assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(b"FinalKeys Value")), Some(1u32));
Map::insert(1, 2); Map::insert(1, 2);
let mut k = b"Module Map".to_vec(); let mut k = b"FinalKeys Map".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
assert_eq!(unhashed::get::<u32>(&runtime_io::blake2_256(&k)), Some(2u32)); assert_eq!(unhashed::get::<u32>(&runtime_io::blake2_256(&k)), Some(2u32));
Map2::insert(1, 2); Map2::insert(1, 2);
let mut k = b"Module Map2".to_vec(); let mut k = b"FinalKeys Map2".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(&k)), Some(2u32)); assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(&k)), Some(2u32));
LinkedMap::insert(1, 2); LinkedMap::insert(1, 2);
let mut k = b"Module LinkedMap".to_vec(); let mut k = b"FinalKeys LinkedMap".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
assert_eq!(unhashed::get::<u32>(&runtime_io::blake2_256(&k)), Some(2u32)); assert_eq!(unhashed::get::<u32>(&runtime_io::blake2_256(&k)), Some(2u32));
LinkedMap2::insert(1, 2); LinkedMap2::insert(1, 2);
let mut k = b"Module LinkedMap2".to_vec(); let mut k = b"FinalKeys LinkedMap2".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(&k)), Some(2u32)); assert_eq!(unhashed::get::<u32>(&runtime_io::twox_128(&k)), Some(2u32));
DoubleMap::insert(1, 2, 3); DoubleMap::insert(&1, &2, &3);
let mut k = b"Module DoubleMap".to_vec(); let mut k = b"FinalKeys DoubleMap".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
let mut k = runtime_io::blake2_256(&k).to_vec(); let mut k = runtime_io::blake2_256(&k).to_vec();
k.extend(&runtime_io::blake2_256(&2u32.encode())); k.extend(&runtime_io::blake2_256(&2u32.encode()));
assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); assert_eq!(unhashed::get::<u32>(&k), Some(3u32));
DoubleMap2::insert(1, 2, 3); DoubleMap2::insert(&1, &2, &3);
let mut k = b"Module DoubleMap2".to_vec(); let mut k = b"FinalKeys DoubleMap2".to_vec();
k.extend(1u32.encode()); k.extend(1u32.encode());
let mut k = runtime_io::twox_128(&k).to_vec(); let mut k = runtime_io::twox_128(&k).to_vec();
k.extend(&runtime_io::blake2_128(&2u32.encode())); k.extend(&runtime_io::blake2_128(&2u32.encode()));
+18 -18
View File
@@ -335,14 +335,14 @@ fn storage_instance_independance() {
module2::LinkedMap::<module2::Instance1>::key_for(1).to_vec(), module2::LinkedMap::<module2::Instance1>::key_for(1).to_vec(),
module2::LinkedMap::<module2::Instance2>::key_for(1).to_vec(), module2::LinkedMap::<module2::Instance2>::key_for(1).to_vec(),
module2::LinkedMap::<module2::Instance3>::key_for(1).to_vec(), module2::LinkedMap::<module2::Instance3>::key_for(1).to_vec(),
module2::DoubleMap::<module2::DefaultInstance>::prefix_for(1), module2::DoubleMap::<module2::DefaultInstance>::prefix_for(&1),
module2::DoubleMap::<module2::Instance1>::prefix_for(1).to_vec(), module2::DoubleMap::<module2::Instance1>::prefix_for(&1).to_vec(),
module2::DoubleMap::<module2::Instance2>::prefix_for(1).to_vec(), module2::DoubleMap::<module2::Instance2>::prefix_for(&1).to_vec(),
module2::DoubleMap::<module2::Instance3>::prefix_for(1).to_vec(), module2::DoubleMap::<module2::Instance3>::prefix_for(&1).to_vec(),
module2::DoubleMap::<module2::DefaultInstance>::key_for(1, 1), module2::DoubleMap::<module2::DefaultInstance>::key_for(&1, &1),
module2::DoubleMap::<module2::Instance1>::key_for(1, 1).to_vec(), module2::DoubleMap::<module2::Instance1>::key_for(&1, &1).to_vec(),
module2::DoubleMap::<module2::Instance2>::key_for(1, 1).to_vec(), module2::DoubleMap::<module2::Instance2>::key_for(&1, &1).to_vec(),
module2::DoubleMap::<module2::Instance3>::key_for(1, 1).to_vec(), module2::DoubleMap::<module2::Instance3>::key_for(&1, &1).to_vec(),
].iter() { ].iter() {
assert!(map.insert(key, ()).is_none()) assert!(map.insert(key, ()).is_none())
} }
@@ -396,15 +396,15 @@ fn storage_with_instance_basic_operation() {
let key1 = 1; let key1 = 1;
let key2 = 1; let key2 = 1;
assert_eq!(DoubleMap::exists(0, 0), true); assert_eq!(DoubleMap::exists(&0, &0), true);
assert_eq!(DoubleMap::exists(key1, key2), false); assert_eq!(DoubleMap::exists(&key1, &key2), false);
DoubleMap::insert(key1, key2, 1); DoubleMap::insert(&key1, &key2, &1);
assert_eq!(DoubleMap::get(key1, key2), 1); assert_eq!(DoubleMap::get(&key1, &key2), 1);
assert_eq!(DoubleMap::take(key1, key2), 1); assert_eq!(DoubleMap::take(&key1, &key2), 1);
assert_eq!(DoubleMap::get(key1, key2), 0); assert_eq!(DoubleMap::get(&key1, &key2), 0);
DoubleMap::mutate(key1, key2, |a| *a=2); DoubleMap::mutate(&key1, &key2, |a| *a=2);
assert_eq!(DoubleMap::get(key1, key2), 2); assert_eq!(DoubleMap::get(&key1, &key2), 2);
DoubleMap::remove(key1, key2); DoubleMap::remove(&key1, &key2);
assert_eq!(DoubleMap::get(key1, key2), 0); assert_eq!(DoubleMap::get(&key1, &key2), 0);
}); });
} }