diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index eba744f62a..27b94df8b3 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -42,9 +42,7 @@ mod tests { use codec::{Encode, Decode, Joiner}; use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; - use primitives::{ - twox_128, blake2_256, Blake2Hasher, NeverNativeValue, NativeOrEncoded, map - }; + use primitives::{Blake2Hasher, NeverNativeValue, NativeOrEncoded, map}; use sr_primitives::traits::{Header as HeaderT, Hash as HashT, Convert}; use sr_primitives::{ApplyOutcome, ApplyError, ApplyResult}; use sr_primitives::weights::{WeightMultiplier, GetDispatchInfo}; @@ -122,16 +120,16 @@ mod tests { #[test] fn panic_execution_with_foreign_code_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { 69_u128.encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { 69_u128.encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { 0_u128.encode() }, - blake2_256(&>::key_for(0)).to_vec() => { + >::hashed_key_for(0) => { vec![0u8; 32] } ], map![])); @@ -158,16 +156,16 @@ mod tests { #[test] fn bad_extrinsic_with_native_equivalent_code_gives_error() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { 69_u128.encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { 69_u128.encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { 0_u128.encode() }, - blake2_256(&>::key_for(0)).to_vec() => { + >::hashed_key_for(0) => { vec![0u8; 32] } ], map![])); @@ -194,14 +192,14 @@ mod tests { #[test] fn successful_execution_with_native_equivalent_code_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + >::hashed_key().to_vec() => vec![0u8; 16], + >::hashed_key_for(0) => vec![0u8; 32] ], map![])); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -230,14 +228,14 @@ mod tests { #[test] fn successful_execution_with_foreign_code_gives_ok() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + >::hashed_key().to_vec() => vec![0u8; 16], + >::hashed_key_for(0) => vec![0u8; 32] ], map![])); let r = executor().call::<_, NeverNativeValue, fn() -> _>( @@ -749,14 +747,14 @@ mod tests { #[test] fn panic_execution_gives_error() { let mut t = TestExternalities::::new_with_code(BLOATY_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { 0_u128.encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { 0_u128.encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + >::hashed_key().to_vec() => vec![0u8; 16], + >::hashed_key_for(0) => vec![0u8; 32] ], map![])); let r = WasmExecutor::new() @@ -771,14 +769,14 @@ mod tests { #[test] fn successful_execution_gives_ok() { let mut t = TestExternalities::::new_with_code(COMPACT_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { (111 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + >::hashed_key().to_vec() => vec![0u8; 16], + >::hashed_key_for(0) => vec![0u8; 32] ], map![])); let r = WasmExecutor::new() @@ -928,17 +926,17 @@ mod tests { // - 1 milldot based on current polkadot runtime. // (this baed on assigning 0.1 CENT to the cheapest tx with `weight = 100`) let mut t = TestExternalities::::new_with_code(COMPACT_CODE, (map![ - blake2_256(&>::key_for(alice())).to_vec() => { + >::hashed_key_for(alice()) => { (100 * DOLLARS).encode() }, - blake2_256(&>::key_for(bob())).to_vec() => { + >::hashed_key_for(bob()) => { (10 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => { + >::hashed_key().to_vec() => { (110 * DOLLARS).encode() }, - twox_128(>::key()).to_vec() => vec![0u8; 16], - blake2_256(&>::key_for(0)).to_vec() => vec![0u8; 32] + >::hashed_key().to_vec() => vec![0u8; 16], + >::hashed_key_for(0) => vec![0u8; 32] ], map![])); let tip = 1_000_000; diff --git a/substrate/srml/aura/src/lib.rs b/substrate/srml/aura/src/lib.rs index 4df832912a..f3ce6a9e09 100644 --- a/substrate/srml/aura/src/lib.rs +++ b/substrate/srml/aura/src/lib.rs @@ -155,15 +155,7 @@ decl_storage! { } add_extra_genesis { config(authorities): Vec; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - runtime_io::with_storage( - storage, - || Module::::initialize_authorities(&config.authorities), - ); - }) + build(|config| Module::::initialize_authorities(&config.authorities)) } } diff --git a/substrate/srml/authority-discovery/src/lib.rs b/substrate/srml/authority-discovery/src/lib.rs index ffcb6672c8..106f0cfa36 100644 --- a/substrate/srml/authority-discovery/src/lib.rs +++ b/substrate/srml/authority-discovery/src/lib.rs @@ -44,15 +44,7 @@ decl_storage! { } add_extra_genesis { config(keys): Vec>; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig, - | { - sr_io::with_storage( - storage, - || Module::::initialize_keys(&config.keys), - ); - }) + build(|config| Module::::initialize_keys(&config.keys)) } } diff --git a/substrate/srml/babe/src/lib.rs b/substrate/srml/babe/src/lib.rs index 0f439d489e..e21f083eb6 100644 --- a/substrate/srml/babe/src/lib.rs +++ b/substrate/srml/babe/src/lib.rs @@ -187,15 +187,7 @@ decl_storage! { } add_extra_genesis { config(authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - runtime_io::with_storage( - storage, - || Module::::initialize_authorities(&config.authorities), - ); - }) + build(|config| Module::::initialize_authorities(&config.authorities)) } } diff --git a/substrate/srml/collective/src/lib.rs b/substrate/srml/collective/src/lib.rs index ea616beb4b..03f5362021 100644 --- a/substrate/srml/collective/src/lib.rs +++ b/substrate/srml/collective/src/lib.rs @@ -99,15 +99,7 @@ decl_storage! { add_extra_genesis { config(phantom): rstd::marker::PhantomData; config(members): Vec; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &Self, - | { - runtime_io::with_storage( - storage, - || Module::::initialize_members(&config.members), - ); - }) + build(|config| Module::::initialize_members(&config.members)) } } diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs index 244d653662..f267763217 100644 --- a/substrate/srml/democracy/src/lib.rs +++ b/substrate/srml/democracy/src/lib.rs @@ -24,8 +24,8 @@ use sr_primitives::traits::{Zero, Bounded, CheckedMul, CheckedDiv, EnsureOrigin, use sr_primitives::weights::SimpleDispatchInfo; use codec::{Encode, Decode, Input, Output, Error}; use srml_support::{ - decl_module, decl_storage, decl_event, ensure, AppendableStorageMap, StorageValue, StorageMap, - Parameter, Dispatchable, EnumerableStorageMap, + decl_module, decl_storage, decl_event, ensure, StorageValue, StorageMap, StorageLinkedMap, + Parameter, Dispatchable, traits::{ Currency, ReservableCurrency, LockableCurrency, WithdrawReason, LockIdentifier, Get, OnFreeBalanceZero diff --git a/substrate/srml/elections/src/lib.rs b/substrate/srml/elections/src/lib.rs index 63a4509acc..c9aec6df4c 100644 --- a/substrate/srml/elections/src/lib.rs +++ b/substrate/srml/elections/src/lib.rs @@ -28,7 +28,7 @@ use sr_primitives::traits::{Zero, One, StaticLookup, Bounded, Saturating}; use sr_primitives::weights::SimpleDispatchInfo; use runtime_io::print; use srml_support::{ - StorageValue, StorageMap, AppendableStorageMap, DecodeLengthStorageMap, + StorageValue, StorageMap, dispatch::Result, decl_storage, decl_event, ensure, decl_module, traits::{ Currency, ExistenceRequirement, Get, LockableCurrency, LockIdentifier, diff --git a/substrate/srml/generic-asset/src/lib.rs b/substrate/srml/generic-asset/src/lib.rs index abd6e1302f..1f4c395d8d 100644 --- a/substrate/srml/generic-asset/src/lib.rs +++ b/substrate/srml/generic-asset/src/lib.rs @@ -478,15 +478,10 @@ decl_storage! { config(initial_balance): T::Balance; config(endowed_accounts): Vec; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig| { + build(|config: &GenesisConfig| { config.assets.iter().for_each(|asset_id| { config.endowed_accounts.iter().for_each(|account_id| { - storage.0.insert( - >::key_for(asset_id, account_id), - ::encode(&config.initial_balance) - ); + >::insert(asset_id, account_id, &config.initial_balance); }); }); }); diff --git a/substrate/srml/grandpa/src/lib.rs b/substrate/srml/grandpa/src/lib.rs index 5fc354eab9..f5c025b174 100644 --- a/substrate/srml/grandpa/src/lib.rs +++ b/substrate/srml/grandpa/src/lib.rs @@ -162,15 +162,7 @@ decl_storage! { } add_extra_genesis { config(authorities): Vec<(AuthorityId, AuthorityWeight)>; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - runtime_io::with_storage( - storage, - || Module::::initialize_authorities(&config.authorities), - ); - }) + build(|config| Module::::initialize_authorities(&config.authorities)) } } diff --git a/substrate/srml/im-online/src/lib.rs b/substrate/srml/im-online/src/lib.rs index fe604ca788..307c7169d1 100644 --- a/substrate/srml/im-online/src/lib.rs +++ b/substrate/srml/im-online/src/lib.rs @@ -223,15 +223,7 @@ decl_storage! { } add_extra_genesis { config(keys): Vec; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - sr_io::with_storage( - storage, - || Module::::initialize_keys(&config.keys), - ); - }) + build(|config| Module::::initialize_keys(&config.keys)) } } diff --git a/substrate/srml/membership/src/lib.rs b/substrate/srml/membership/src/lib.rs index aed8b598f7..842d4090b1 100644 --- a/substrate/srml/membership/src/lib.rs +++ b/substrate/srml/membership/src/lib.rs @@ -62,16 +62,11 @@ decl_storage! { add_extra_genesis { config(members): Vec; config(phantom): sr_std::marker::PhantomData; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &Self, - | { - sr_io::with_storage(storage, || { - let mut members = config.members.clone(); - members.sort(); - T::MembershipInitialized::initialize_members(&members); - >::put(members); - }); + build(|config: &Self| { + let mut members = config.members.clone(); + members.sort(); + T::MembershipInitialized::initialize_members(&members); + >::put(members); }) } } diff --git a/substrate/srml/scored-pool/src/lib.rs b/substrate/srml/scored-pool/src/lib.rs index f2f5d426d9..f3ea075653 100644 --- a/substrate/srml/scored-pool/src/lib.rs +++ b/substrate/srml/scored-pool/src/lib.rs @@ -172,32 +172,27 @@ decl_storage! { add_extra_genesis { config(members): Vec; config(phantom): sr_std::marker::PhantomData; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &Self, - | { - sr_io::with_storage(storage, || { - let mut pool = config.pool.clone(); + build(|config| { + let mut pool = config.pool.clone(); - // reserve balance for each candidate in the pool. - // panicking here is ok, since this just happens one time, pre-genesis. - pool - .iter() - .for_each(|(who, _)| { - T::Currency::reserve(&who, T::CandidateDeposit::get()) - .expect("balance too low to create candidacy"); - >::insert(who, true); - }); + // reserve balance for each candidate in the pool. + // panicking here is ok, since this just happens one time, pre-genesis. + pool + .iter() + .for_each(|(who, _)| { + T::Currency::reserve(&who, T::CandidateDeposit::get()) + .expect("balance too low to create candidacy"); + >::insert(who, true); + }); - /// Sorts the `Pool` by score in a descending order. Entities which - /// have a score of `None` are sorted to the beginning of the vec. - pool.sort_by_key(|(_, maybe_score)| - Reverse(maybe_score.unwrap_or_default()) - ); + /// Sorts the `Pool` by score in a descending order. Entities which + /// have a score of `None` are sorted to the beginning of the vec. + pool.sort_by_key(|(_, maybe_score)| + Reverse(maybe_score.unwrap_or_default()) + ); - >::put(&pool); - >::refresh_members(pool, ChangeReceiver::MembershipInitialized); - }); + >::put(&pool); + >::refresh_members(pool, ChangeReceiver::MembershipInitialized); }) } } diff --git a/substrate/srml/session/src/lib.rs b/substrate/srml/session/src/lib.rs index c474962c65..58a60a9875 100644 --- a/substrate/srml/session/src/lib.rs +++ b/substrate/srml/session/src/lib.rs @@ -381,41 +381,36 @@ decl_storage! { } add_extra_genesis { config(keys): Vec<(T::ValidatorId, T::Keys)>; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - runtime_io::with_storage(storage, || { - for (who, keys) in config.keys.iter().cloned() { - assert!( - >::load_keys(&who).is_none(), - "genesis config contained duplicate validator {:?}", who, - ); + build(|config: &GenesisConfig| { + for (who, keys) in config.keys.iter().cloned() { + assert!( + >::load_keys(&who).is_none(), + "genesis config contained duplicate validator {:?}", who, + ); - >::do_set_keys(&who, keys) - .expect("genesis config must not contain duplicates; qed"); - } + >::do_set_keys(&who, keys) + .expect("genesis config must not contain duplicates; qed"); + } - let initial_validators = T::SelectInitialValidators::select_initial_validators() - .unwrap_or_else(|| config.keys.iter().map(|(ref v, _)| v.clone()).collect()); + let initial_validators = T::SelectInitialValidators::select_initial_validators() + .unwrap_or_else(|| config.keys.iter().map(|(ref v, _)| v.clone()).collect()); - assert!(!initial_validators.is_empty(), "Empty validator set in genesis block!"); + assert!(!initial_validators.is_empty(), "Empty validator set in genesis block!"); - let queued_keys: Vec<_> = initial_validators - .iter() - .cloned() - .map(|v| ( - v.clone(), - >::load_keys(&v).unwrap_or_default(), - )) - .collect(); + let queued_keys: Vec<_> = initial_validators + .iter() + .cloned() + .map(|v| ( + v.clone(), + >::load_keys(&v).unwrap_or_default(), + )) + .collect(); - // Tell everyone about the genesis session keys - T::SessionHandler::on_genesis_session::(&queued_keys); + // Tell everyone about the genesis session keys + T::SessionHandler::on_genesis_session::(&queued_keys); - >::put(initial_validators); - >::put(queued_keys); - }); + >::put(initial_validators); + >::put(queued_keys); }); } } diff --git a/substrate/srml/staking/src/lib.rs b/substrate/srml/staking/src/lib.rs index e7824d36e0..8b268a8272 100644 --- a/substrate/srml/staking/src/lib.rs +++ b/substrate/srml/staking/src/lib.rs @@ -259,12 +259,10 @@ pub mod inflation; #[cfg(all(feature = "bench", test))] mod benches; -#[cfg(feature = "std")] -use runtime_io::with_storage; use rstd::{prelude::*, result}; use codec::{HasCompact, Encode, Decode}; use srml_support::{ - StorageValue, StorageMap, EnumerableStorageMap, decl_module, decl_event, + StorageValue, StorageMap, StorageLinkedMap, decl_module, decl_event, decl_storage, ensure, traits::{ Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, WithdrawReasons, WithdrawReason, OnUnbalanced, Imbalance, Get, Time @@ -619,37 +617,33 @@ decl_storage! { add_extra_genesis { config(stakers): Vec<(T::AccountId, T::AccountId, BalanceOf, StakerStatus)>; - build(| - storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig - | { - with_storage(storage, || { - for &(ref stash, ref controller, balance, ref status) in &config.stakers { - assert!( - T::Currency::free_balance(&stash) >= balance, - "Stash does not have enough balance to bond." - ); - let _ = >::bond( - T::Origin::from(Some(stash.clone()).into()), - T::Lookup::unlookup(controller.clone()), - balance, - RewardDestination::Staked - ); - let _ = match status { - StakerStatus::Validator => { - >::validate( - T::Origin::from(Some(controller.clone()).into()), - Default::default() - ) - }, StakerStatus::Nominator(votes) => { - >::nominate( - T::Origin::from(Some(controller.clone()).into()), - votes.iter().map(|l| {T::Lookup::unlookup(l.clone())}).collect() - ) - }, _ => Ok(()) - }; - } - }); + build(|config: &GenesisConfig| { + for &(ref stash, ref controller, balance, ref status) in &config.stakers { + assert!( + T::Currency::free_balance(&stash) >= balance, + "Stash does not have enough balance to bond." + ); + let _ = >::bond( + T::Origin::from(Some(stash.clone()).into()), + T::Lookup::unlookup(controller.clone()), + balance, + RewardDestination::Staked, + ); + let _ = match status { + StakerStatus::Validator => { + >::validate( + T::Origin::from(Some(controller.clone()).into()), + Default::default(), + ) + }, + StakerStatus::Nominator(votes) => { + >::nominate( + T::Origin::from(Some(controller.clone()).into()), + votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(), + ) + }, _ => Ok(()) + }; + } }); } } diff --git a/substrate/srml/staking/src/mock.rs b/substrate/srml/staking/src/mock.rs index 2f2e81196c..b7948d12fe 100644 --- a/substrate/srml/staking/src/mock.rs +++ b/substrate/srml/staking/src/mock.rs @@ -23,7 +23,7 @@ use sr_primitives::testing::{Header, UintAuthorityId}; use sr_staking_primitives::SessionIndex; use primitives::{H256, Blake2Hasher}; use runtime_io; -use srml_support::{assert_ok, impl_outer_origin, parameter_types, EnumerableStorageMap}; +use srml_support::{assert_ok, impl_outer_origin, parameter_types, StorageLinkedMap}; use srml_support::traits::{Currency, Get, FindAuthor}; use crate::{ EraIndex, GenesisConfig, Module, Trait, StakerStatus, ValidatorPrefs, RewardDestination, diff --git a/substrate/srml/staking/src/tests.rs b/substrate/srml/staking/src/tests.rs index 6e0eaf3b50..bc6b92e2dc 100644 --- a/substrate/srml/staking/src/tests.rs +++ b/substrate/srml/staking/src/tests.rs @@ -20,7 +20,7 @@ use super::*; use runtime_io::with_externalities; use sr_primitives::traits::OnInitialize; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; -use srml_support::{assert_ok, assert_noop, assert_eq_uvec, EnumerableStorageMap}; +use srml_support::{assert_ok, assert_noop, assert_eq_uvec, StorageLinkedMap}; use mock::*; use srml_support::traits::{Currency, ReservableCurrency}; diff --git a/substrate/srml/support/procedural/src/lib.rs b/substrate/srml/support/procedural/src/lib.rs index 674b90458f..91e0aa2d4d 100644 --- a/substrate/srml/support/procedural/src/lib.rs +++ b/substrate/srml/support/procedural/src/lib.rs @@ -47,10 +47,15 @@ use proc_macro::TokenStream; /// /// Basic storage consists of a name and a type; supported types are: /// -/// * Value: `Foo: type`: Implements the [`StorageValue`](../srml_support/storage/trait.StorageValue.html) trait. +/// * Value: `Foo: type`: Implements the +/// [`StorageValue`](../srml_support/storage/trait.StorageValue.html) trait using the +/// [`StorageValue generator`](../srml_support/storage/generator/trait.StorageValue.html). +/// /// * Map: `Foo: map hasher($hash) type => type`: Implements the -/// [`StorageMap`](../srml_support/storage/trait.StorageMap.html) trait -/// with `$hash` representing a choice of hashing algorithms available in the +/// [`StorageMap`](../srml_support/storage/trait.StorageMap.html) trait using the +/// [`StorageMap generator`](../srml_support/storage/generator/trait.StorageMap.html). +/// +/// `$hash` representing a choice of hashing algorithms available in the /// [`Hashable`](../srml_support/trait.Hashable.html) trait. /// /// `hasher($hash)` is optional and its default is `blake2_256`. @@ -60,12 +65,25 @@ use proc_macro::TokenStream; /// 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 can be compromised. /// -/// * Linked map: `Foo: linked_map hasher($hash) type => type`: Same as `Map` but also implements -/// the [`EnumerableStorageMap`](../srml_support/storage/trait.EnumerableStorageMap.html) trait. +/// * Linked map: `Foo: linked_map hasher($hash) type => type`: Implements the +/// [`StorageLinkedMap`](../srml_support/storage/trait.StorageLinkedMap.html) trait using the +/// [`StorageLinkedMap generator`](../srml_support/storage/generator/trait.StorageLinkedMap.html). /// -/// * Double map: `Foo: double_map hasher($hash) u32, $hash2(u32) => u32`: Implements the -/// [`StorageDoubleMap`](../srml_support/storage/trait.StorageDoubleMap.html) trait with -/// `$hash` and `$hash2` representing choices of hashing algorithms available in the +/// `$hash` representing a choice of hashing algorithms available in the +/// [`Hashable`](../srml_support/trait.Hashable.html) trait. +/// +/// `hasher($hash)` is optional and its default is `blake2_256`. +/// +/// /!\ Be careful with each key in the map that is inserted in the trie +/// `$hash(module_name ++ " " ++ storage_name ++ encoding(key))`. +/// 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 can be compromised. +/// +/// * Double map: `Foo: double_map hasher($hash1) u32, $hash2(u32) => u32`: Implements the +/// [`StorageDoubleMap`](../srml_support/storage/trait.StorageDoubleMap.html) trait using the +/// [`StorageDoubleMap generator`](../srml_support/storage/generator/trait.StorageDoubleMap.html). +/// +/// `$hash1` and `$hash2` representing choices of hashing algorithms available in the /// [`Hashable`](../srml_support/trait.Hashable.html) trait. /// /// `hasher($hash)` is optional and its default is `blake2_256`. @@ -126,7 +144,7 @@ use proc_macro::TokenStream; /// config(genesis_field): GenesisFieldType; /// config(genesis_field2): GenesisFieldType; /// ... -/// build(|_: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, _: &GenesisConfig| { +/// build(|_: &Self| { /// // Modification of storage /// }) /// } diff --git a/substrate/srml/support/procedural/src/storage/impls.rs b/substrate/srml/support/procedural/src/storage/impls.rs index d67bc5a116..a5b91eda78 100644 --- a/substrate/srml/support/procedural/src/storage/impls.rs +++ b/substrate/srml/support/procedural/src/storage/impls.rs @@ -21,13 +21,23 @@ use proc_macro2::TokenStream as TokenStream2; use syn::Ident; use quote::quote; -pub fn option_unwrap(is_option: bool) -> TokenStream2 { +fn from_optional_value_to_query(is_option: bool, fielddefault: TokenStream2) -> TokenStream2 { if !is_option { // raw type case - quote!( unwrap_or_else ) + quote!( v.unwrap_or_else(|| #fielddefault ) ) } else { // Option<> type case - quote!( or_else ) + quote!( v.or_else(|| #fielddefault ) ) + } +} + +fn from_query_to_optional_value(is_option: bool) -> TokenStream2 { + if !is_option { + // raw type case + quote!( Some(v) ) + } else { + // Option<> type case + quote!( v ) } } @@ -43,8 +53,6 @@ pub(crate) struct Impls<'a, I: Iterator> { pub instance_opts: &'a InstanceOpts, pub type_infos: DeclStorageTypeInfos<'a>, pub fielddefault: TokenStream2, - pub default_delegator_ident: syn::Ident, - pub default_delegator_return: TokenStream2, pub prefix: String, pub cratename: &'a syn::Ident, pub name: &'a syn::Ident, @@ -62,8 +70,6 @@ impl<'a, I: Iterator> Impls<'a, I> { instance_opts, type_infos, fielddefault, - default_delegator_ident, - default_delegator_return, prefix, name, attrs, @@ -71,20 +77,9 @@ impl<'a, I: Iterator> Impls<'a, I> { .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - let option_simple_1 = option_unwrap(is_option); - let mutate_impl = if !is_option { - quote!{ - >::put(&val, storage) - } - } else { - quote!{ - match val { - Some(ref val) => >::put(&val, storage), - None => >::kill(storage), - } - } - }; + let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); + let from_query_to_optional_value = from_query_to_optional_value(is_option); let InstanceOpts { equal_default_instance, @@ -120,56 +115,26 @@ impl<'a, I: Iterator> Impls<'a, I> { // generator for value quote! { - #visibility struct #default_delegator_ident<#struct_trait>( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - impl<#impl_trait> #scrate::traits::StorageDefault<#typ> - for #default_delegator_ident<#trait_and_instance> #where_clause - { - fn default() -> Option<#typ> { - #default_delegator_return - } - } - #( #[ #attrs ] )* #visibility struct #name<#struct_trait>( #scrate::rstd::marker::PhantomData<(#trait_and_instance)> ) #where_clause; - impl<#impl_trait> #scrate::storage::hashed::generator::StorageValue<#typ> + impl<#impl_trait> #scrate::storage::generator::StorageValue<#typ> for #name<#trait_and_instance> #where_clause { type Query = #value_type; - type Default = #default_delegator_ident<#trait_and_instance>; - /// Get the storage key. - fn key() -> &'static [u8] { + fn unhashed_key() -> &'static [u8] { #final_prefix } - /// Load the value from the provided storage instance. - fn get>(storage: &S) -> Self::Query { - storage.get(>::key()) - .#option_simple_1(|| #fielddefault) + fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { + #from_optional_value_to_query } - /// Take a value from storage, removing it afterwards. - fn take>(storage: &mut S) -> Self::Query { - storage.take(>::key()) - .#option_simple_1(|| #fielddefault) - } - - /// Mutate the value under a key. - fn mutate(f: F, storage: &mut S) -> R - where - F: FnOnce(&mut Self::Query) -> R, - S: #scrate::HashedStorage<#scrate::Twox128>, - { - let mut val = >::get(storage); - - let ret = f(&mut val); - #mutate_impl ; - ret + fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { + #from_query_to_optional_value } } } @@ -184,8 +149,6 @@ impl<'a, I: Iterator> Impls<'a, I> { instance_opts, type_infos, fielddefault, - default_delegator_ident, - default_delegator_return, prefix, name, attrs, @@ -193,22 +156,9 @@ impl<'a, I: Iterator> Impls<'a, I> { .. } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - let option_simple_1 = option_unwrap(is_option); - let as_map = quote!{ > }; - - let mutate_impl = if !is_option { - quote!{ - #as_map::insert(key, &val, storage) - } - } else { - quote!{ - match val { - Some(ref val) => #as_map::insert(key, &val, storage), - None => #as_map::remove(key, storage), - } - } - }; + let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); + let from_query_to_optional_value = from_query_to_optional_value(is_option); let InstanceOpts { equal_default_instance, @@ -248,74 +198,29 @@ impl<'a, I: Iterator> Impls<'a, I> { // generator for map quote!{ - #visibility struct #default_delegator_ident<#struct_trait>( - #scrate::rstd::marker::PhantomData<(#trait_and_instance)> - ) #where_clause; - impl<#impl_trait> #scrate::traits::StorageDefault<#typ> - for #default_delegator_ident<#trait_and_instance> #where_clause - { - fn default() -> Option<#typ> { - #default_delegator_return - } - } - #( #[ #attrs ] )* #visibility struct #name<#struct_trait>( #scrate::rstd::marker::PhantomData<(#trait_and_instance)> ) #where_clause; - impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ> + impl<#impl_trait> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#trait_and_instance> #where_clause { type Query = #value_type; type Hasher = #scrate::#hasher; - type Default = #default_delegator_ident<#trait_and_instance>; - /// Get the prefix key in storage. fn prefix() -> &'static [u8] { #final_prefix } - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec { - let mut key = #as_map::prefix().to_vec(); - #scrate::codec::Encode::encode_to(x, &mut key); - key + fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { + #from_optional_value_to_query } - /// Load the value associated with the given key from the map. - fn get>(key: &#kty, storage: &S) -> Self::Query { - let key = #as_map::key_for(key); - storage.get(&key[..]).#option_simple_1(|| #fielddefault) - } - - /// Take the value, reading and removing it. - fn take>(key: &#kty, storage: &mut S) -> Self::Query { - let key = #as_map::key_for(key); - storage.take(&key[..]).#option_simple_1(|| #fielddefault) - } - - /// Mutate the value under a key - fn mutate(key: &#kty, f: F, storage: &mut S) -> R - where - F: FnOnce(&mut Self::Query) -> R, - S: #scrate::HashedStorage<#scrate::#hasher>, - { - let mut val = #as_map::get(key, storage); - - let ret = f(&mut val); - #mutate_impl ; - ret + fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { + #from_query_to_optional_value } } - - impl<#impl_trait> #scrate::storage::hashed::generator::AppendableStorageMap<#kty, #typ> - for #name<#trait_and_instance> #where_clause - {} - - impl<#impl_trait> #scrate::storage::hashed::generator::DecodeLengthStorageMap<#kty, #typ> - for #name<#trait_and_instance> #where_clause - {} } } @@ -328,8 +233,6 @@ impl<'a, I: Iterator> Impls<'a, I> { instance_opts, type_infos, fielddefault, - default_delegator_ident, - default_delegator_return, prefix, name, attrs, @@ -365,421 +268,58 @@ impl<'a, I: Iterator> Impls<'a, I> { }; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - let option_simple_1 = option_unwrap(is_option); - let name_lowercase = name.to_string().to_lowercase(); - let inner_module = Ident::new( - &format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span() - ); - let linkage = Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span()); - let phantom_data = quote! { #scrate::rstd::marker::PhantomData }; - let as_map = quote!{ > }; - let put_or_insert = quote! { - match linkage { - Some(linkage) => storage.put(key_for, &(val, linkage)), - None => #as_map::insert(key, &val, storage), - } - }; - let mutate_impl = if !type_infos.is_option { - put_or_insert - } else { - quote! { - match val { - Some(ref val) => #put_or_insert, - None => #as_map::remove(key, storage), - } - } - }; - let mutate_map = if type_infos.is_option { - quote! { .map(|(data, linkage)| (Some(data), Some(linkage))) } - } else { - quote! { .map(|(data, linkage)| (data, Some(linkage))) } - }; + let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); + let from_query_to_optional_value = from_query_to_optional_value(is_option); let trait_required = ext::type_contains_ident(value_type, traitinstance) || ext::type_contains_ident(kty, traitinstance); - let (struct_trait, impl_trait, trait_and_instance) = if trait_required { + let (struct_trait, impl_trait, trait_and_instance, where_clause) = if trait_required { ( quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance), quote!(#traitinstance: #traittype, #instance #bound_instantiable), quote!(#traitinstance, #instance), + where_clause.clone(), ) } else { ( quote!(#instance #bound_instantiable #equal_default_instance), quote!(#instance #bound_instantiable), quote!(#instance), - ) - }; - - let (where_clause, trait_where_clause) = if trait_required { - ( - where_clause.clone(), - where_clause.clone().map(|mut wc| { - wc.predicates.push(syn::parse_quote!(#traitinstance: 'static)); - wc - }).or_else(|| syn::parse_quote!(where #traitinstance: 'static)), - ) - } else { - ( - None, None, ) }; // generator for linked map - let helpers = quote! { - /// Linkage data of an element (it's successor and predecessor) - #[derive(#scrate::codec::Encode, #scrate::codec::Decode)] - pub(crate) struct #linkage { - /// Previous element key in storage (None for the first element) - pub previous: Option, - /// Next element key in storage (None for the last element) - pub next: Option, - } - - mod #inner_module { - use super::*; - - /// Re-exported version of linkage to overcome proc-macro derivation issue. - pub(crate) use super::#linkage as Linkage; - - impl Default for Linkage { - fn default() -> Self { - Self { - previous: None, - next: None, - } - } - } - - /// A key-value pair iterator for enumerable map. - pub(crate) struct Enumerator<'a, S, K, V> { - pub storage: &'a S, - pub next: Option, - pub _data: #phantom_data, - } - - impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #impl_trait> Iterator - for Enumerator<'a, S, #kty, (#typ, #trait_and_instance)> #where_clause - { - type Item = (#kty, #typ); - - fn next(&mut self) -> Option { - let next = self.next.take()?; - let key_for = - as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>>::key_for(&next); - - let (val, linkage): (#typ, Linkage<#kty>) = self.storage.get(&*key_for) - .expect("previous/next only contain existing entires; we enumerate using next; entry exists; qed"); - self.next = linkage.next; - Some((next, val)) - } - } - - pub(crate) trait Utils<#struct_trait> { - /// Update linkage when this element is removed. - /// - /// Takes care of updating previous and next elements points - /// as well as updates head if the element is first or last. - fn remove_linkage>(linkage: Linkage<#kty>, storage: &mut S); - - /// Read the contained data and it's linkage. - fn read_with_linkage(storage: &S, key: &[u8]) -> Option<(#typ, Linkage<#kty>)> - where - S: #scrate::HashedStorage<#scrate::#hasher>; - - /// Generate linkage for newly inserted element. - /// - /// Takes care of updating head and previous head's pointer. - fn new_head_linkage>( - storage: &mut S, - key: &#kty, - ) -> Linkage<#kty>; - - /// Read current head pointer. - fn read_head>(storage: &S) -> Option<#kty>; - - /// Overwrite current head pointer. - /// - /// If `None` is given head is removed from storage. - fn write_head>(storage: &mut S, head: Option<&#kty>); - } - } - }; - - let structure = quote! { - #( #[ #attrs ] )* - #visibility struct #name<#struct_trait>(#phantom_data<(#trait_and_instance)>); - - impl<#impl_trait> self::#inner_module::Utils<#trait_and_instance> - for #name<#trait_and_instance> #where_clause - { - fn remove_linkage>( - linkage: self::#inner_module::Linkage<#kty>, - storage: &mut S, - ) { - use self::#inner_module::Utils; - - let next_key = linkage.next.as_ref().map(|x| #as_map::key_for(x)); - let prev_key = linkage.previous.as_ref().map(|x| #as_map::key_for(x)); - - if let Some(prev_key) = prev_key { - // Retrieve previous element and update `next` - let mut res = Self::read_with_linkage(storage, &*prev_key) - .expect("Linkage is updated in case entry is removed; it always points to existing keys; qed"); - res.1.next = linkage.next; - storage.put(&*prev_key, &res); - } else { - // we were first so let's update the head - Self::write_head(storage, linkage.next.as_ref()); - } - - if let Some(next_key) = next_key { - // Update previous of next element - let mut res = Self::read_with_linkage(storage, &*next_key) - .expect("Linkage is updated in case entry is removed; it always points to existing keys; qed"); - res.1.previous = linkage.previous; - storage.put(&*next_key, &res); - } - } - - fn read_with_linkage>( - storage: &S, - key: &[u8], - ) -> Option<(#typ, self::#inner_module::Linkage<#kty>)> { - storage.get(key) - } - - fn new_head_linkage>( - storage: &mut S, - key: &#kty, - ) -> self::#inner_module::Linkage<#kty> { - use self::#inner_module::Utils; - - if let Some(head) = Self::read_head(storage) { - // update previous head predecessor - { - let head_key = #as_map::key_for(&head); - let (data, linkage) = Self::read_with_linkage(storage, &*head_key).expect(r#" - head is set when first element is inserted and unset when last element is removed; - if head is Some then it points to existing key; qed - "#); - storage.put(&*head_key, &(data, self::#inner_module::Linkage { - next: linkage.next.as_ref(), - previous: Some(key), - })); - } - // update to current head - Self::write_head(storage, Some(key)); - // return linkage with pointer to previous head - let mut linkage = self::#inner_module::Linkage::default(); - linkage.next = Some(head); - linkage - } else { - // we are first - update the head and produce empty linkage - Self::write_head(storage, Some(key)); - self::#inner_module::Linkage::default() - } - } - - fn read_head>(storage: &S) -> Option<#kty> { - storage.get(#final_head_key) - } - - fn write_head>(storage: &mut S, head: Option<&#kty>) { - match head { - Some(head) => storage.put(#final_head_key, head), - None => storage.kill(#final_head_key), - } - } - } - }; - quote! { - #helpers - - #structure - - #visibility struct #default_delegator_ident<#struct_trait>( + #( #[ #attrs ] )* + #visibility struct #name<#struct_trait>( #scrate::rstd::marker::PhantomData<(#trait_and_instance)> ) #where_clause; - impl<#impl_trait> #scrate::traits::StorageDefault<#typ> - for #default_delegator_ident<#trait_and_instance> #where_clause - { - fn default() -> Option<#typ> { - #default_delegator_return - } - } - impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ> + impl<#impl_trait> #scrate::storage::generator::StorageLinkedMap<#kty, #typ> for #name<#trait_and_instance> #where_clause { type Query = #value_type; type Hasher = #scrate::#hasher; - type Default = #default_delegator_ident<#trait_and_instance>; - /// Get the prefix key in storage. fn prefix() -> &'static [u8] { #final_prefix } - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(key: &#kty) -> #scrate::rstd::vec::Vec { - let mut key_for = #as_map::prefix().to_vec(); - #scrate::codec::Encode::encode_to(&key, &mut key_for); - key_for + fn final_head_key() -> &'static [u8] { + #final_head_key } - /// Load the value associated with the given key from the map. - fn get>(key: &#kty, storage: &S) -> Self::Query { - storage.get(&*#as_map::key_for(key)).#option_simple_1(|| #fielddefault) + fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { + #from_optional_value_to_query } - /// Take the value, reading and removing it. - fn take>(key: &#kty, storage: &mut S) -> Self::Query { - use self::#inner_module::Utils; - - let res: Option<(#typ, self::#inner_module::Linkage<#kty>)> = storage.take(&*#as_map::key_for(key)); - - res.map(|(d, l)| { - Self::remove_linkage(l, storage); - d - }).#option_simple_1(|| #fielddefault) - } - - /// Remove the value under a key. - fn remove>(key: &#kty, storage: &mut S) { - #as_map::take(key, storage); - } - - /// Store a value to be associated with the given key from the map. - fn insert>( - key: &#kty, - val: &#typ, - storage: &mut S, - ) { - use self::#inner_module::Utils; - - let key_for = &*#as_map::key_for(key); - let linkage = match Self::read_with_linkage(storage, key_for) { - // overwrite but reuse existing linkage - Some((_data, linkage)) => linkage, - // create new linkage - None => Self::new_head_linkage(storage, key), - }; - - storage.put(key_for, &(val, linkage)) - } - - /// Store a value under this key into the provided storage instance; this can take any reference - /// type that derefs to `T` (and has `Encode` implemented). - /// Store a value under this key into the provided storage instance. - fn insert_ref(key: &#kty, val: &Arg, storage: &mut S) - where - #typ: AsRef, - Arg: ?Sized + #scrate::codec::Encode, - S: #scrate::HashedStorage<#scrate::#hasher> - { - use self::#inner_module::Utils; - - let key_for = &*#as_map::key_for(key); - let linkage = match Self::read_with_linkage(storage, key_for) { - // overwrite but reuse existing linkage - Some((_data, linkage)) => linkage, - // create new linkage - None => Self::new_head_linkage(storage, key), - }; - - storage.put(key_for, &(val, linkage)) - } - - /// Mutate the value under a key - fn mutate(key: &#kty, f: F, storage: &mut S) -> R - where - F: FnOnce(&mut Self::Query) -> R, - S: #scrate::HashedStorage<#scrate::#hasher>, - { - use self::#inner_module::Utils; - - let key_for = &*#as_map::key_for(key); - let (mut val, linkage) = Self::read_with_linkage(storage, key_for) - #mutate_map - .unwrap_or_else(|| (#fielddefault, None)); - - let ret = f(&mut val); - #mutate_impl; - ret - } - - // Swap must be overriden not to break links. - fn swap>( - key1: &#kty, - key2: &#kty, - storage: &mut S, - ) { - use self::#inner_module::Utils; - - let final_key1 = &*#as_map::key_for(key1); - let final_key2 = &*#as_map::key_for(key2); - let full_value_1 = Self::read_with_linkage(storage, final_key1); - let full_value_2 = Self::read_with_linkage(storage, final_key2); - - match (full_value_1, full_value_2) { - // Just keep linkage in order and only swap values. - (Some((value1, linkage1)), Some((value2, linkage2))) => { - storage.put(final_key1, &(value2, linkage1)); - storage.put(final_key2, &(value1, linkage2)); - } - // Remove key and insert the new one. - (Some((value, linkage)), None) => { - #as_map::remove(key1, storage); - let linkage = Self::new_head_linkage(storage, key2); - storage.put(final_key2, &(value, linkage)); - } - // Remove key and insert the new one. - (None, Some((value, linkage))) => { - #as_map::remove(key2, storage); - let linkage = Self::new_head_linkage(storage, key1); - storage.put(final_key1, &(value, linkage)); - } - // No-op. - (None, None) => (), - } + fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { + #from_query_to_optional_value } } - - impl<#impl_trait> #scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ> - for #name<#trait_and_instance> #trait_where_clause - { - fn head>(storage: &S) -> Option<#kty> { - use self::#inner_module::Utils; - - Self::read_head(storage) - } - - fn enumerate<'a, S>( - storage: &'a S - ) -> #scrate::rstd::boxed::Box + 'a> - where - S: #scrate::HashedStorage<#scrate::#hasher>, - #kty: 'a, - #typ: 'a, - { - use self::#inner_module::{Utils, Enumerator}; - - #scrate::rstd::boxed::Box::new(Enumerator { - next: Self::read_head(storage), - storage, - _data: #phantom_data::<(#typ, #trait_and_instance)>::default(), - }) - } - } - - impl<#impl_trait> #scrate::storage::hashed::generator::DecodeLengthStorageMap<#kty, #typ> - for #name<#trait_and_instance> #where_clause - {} } } @@ -806,29 +346,9 @@ impl<'a, I: Iterator> Impls<'a, I> { } = self; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; - let option_simple_1 = option_unwrap(is_option); - let as_double_map = quote!{ - > - }; - - let mutate_impl = if !is_option { - quote!{ - #as_double_map::insert(k1, k2, &val, storage) - } - } else { - quote!{ - match val { - Some(ref val) => #as_double_map::insert::( - k1, - k2, - val, - storage, - ), - None => #as_double_map::remove(k1, k2, storage), - } - } - }; + let from_optional_value_to_query = from_optional_value_to_query(is_option, fielddefault); + let from_query_to_optional_value = from_query_to_optional_value(is_option); let InstanceOpts { equal_default_instance, @@ -868,90 +388,29 @@ impl<'a, I: Iterator> Impls<'a, I> { // generator for double map quote!{ #( #[ #attrs ] )* - #visibility struct #name<#struct_trait> - (#scrate::rstd::marker::PhantomData<(#trait_and_instance)>); + #visibility struct #name<#struct_trait> ( + #scrate::rstd::marker::PhantomData<(#trait_and_instance)> + ) #where_clause; - impl<#impl_trait> #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> + impl<#impl_trait> #scrate::storage::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#trait_and_instance> #where_clause { type Query = #value_type; - fn prefix_for(k1: &KArg1) -> #scrate::rstd::vec::Vec where - KArg1: ?Sized + #scrate::codec::Encode, - #k1ty: #scrate::rstd::borrow::Borrow, - { - use #scrate::storage::hashed::generator::StorageHasher; + type Hasher1 = #scrate::#hasher; - let mut key = #as_double_map::prefix().to_vec(); - #scrate::codec::Encode::encode_to(k1, &mut key); - #scrate::#hasher::hash(&key[..]).to_vec() - } + type Hasher2 = #scrate::#k2_hasher; - fn prefix() -> &'static [u8] { + fn key1_prefix() -> &'static [u8] { #final_prefix } - fn key_for( - k1: &KArg1, - k2: &KArg2, - ) -> #scrate::rstd::vec::Vec where - #k1ty: #scrate::rstd::borrow::Borrow, - #k2ty: #scrate::rstd::borrow::Borrow, - KArg1: ?Sized + #scrate::codec::Encode, - KArg2: ?Sized + #scrate::codec::Encode, - { - use #scrate::storage::hashed::generator::StorageHasher; - - let mut key = #as_double_map::prefix_for(k1); - #scrate::codec::Encode::using_encoded(k2, |e| key.extend(&#scrate::#k2_hasher::hash(e))); - key + fn from_optional_value_to_query(v: Option<#typ>) -> Self::Query { + #from_optional_value_to_query } - fn get( - k1: &KArg1, - k2: &KArg2, - storage: &S, - ) -> Self::Query where - #k1ty: #scrate::rstd::borrow::Borrow, - #k2ty: #scrate::rstd::borrow::Borrow, - 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) - } - - fn take( - k1: &KArg1, - k2: &KArg2, - storage: &mut S, - ) -> Self::Query where - #k1ty: #scrate::rstd::borrow::Borrow, - #k2ty: #scrate::rstd::borrow::Borrow, - 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) - } - - fn mutate( - k1: &KArg1, - k2: &KArg2, - f: F, - storage: &mut S, - ) -> R where - #k1ty: #scrate::rstd::borrow::Borrow, - #k2ty: #scrate::rstd::borrow::Borrow, - KArg1: ?Sized + #scrate::codec::Encode, - KArg2: ?Sized + #scrate::codec::Encode, - F: FnOnce(&mut Self::Query) -> R, - { - let mut val = #as_double_map::get(k1, k2, storage); - - let ret = f(&mut val); - #mutate_impl; - ret + fn from_query_to_optional_value(v: Self::Query) -> Option<#typ> { + #from_query_to_optional_value } } } diff --git a/substrate/srml/support/procedural/src/storage/transformation.rs b/substrate/srml/support/procedural/src/storage/transformation.rs index 039bf8c8f6..cb2c7e6ca9 100644 --- a/substrate/srml/support/procedural/src/storage/transformation.rs +++ b/substrate/srml/support/procedural/src/storage/transformation.rs @@ -330,11 +330,11 @@ fn decl_store_extra_genesis( let v = (#builder)(&self); < #name<#struct_trait #instance> as - #scrate::storage::hashed::generator::StorageValue<#typ> - >::put(&v, storage); + #scrate::storage::StorageValue<#typ> + >::put(&v); }} }, - DeclStorageTypeInfosKind::Map { key_type, .. } => { + DeclStorageTypeInfosKind::Map { key_type, is_linked, .. } => { let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) || ext::type_contains_ident(key_type, traitinstance) { @@ -344,13 +344,19 @@ fn decl_store_extra_genesis( quote!() }; + let map = if is_linked { + quote! { StorageLinkedMap } + } else { + quote! { StorageMap } + }; + quote!{{ let data = (#builder)(&self); data.into_iter().for_each(|(k, v)| { < #name<#struct_trait #instance> as - #scrate::storage::hashed::generator::StorageMap<#key_type, #typ> - >::insert(&k, &v, storage); + #scrate::storage::#map<#key_type, #typ> + >::insert(&k, &v); }); }} }, @@ -370,8 +376,8 @@ fn decl_store_extra_genesis( data.into_iter().for_each(|(k1, k2, v)| { < #name<#struct_trait #instance> as - #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ> - >::insert(&k1, &k2, &v, storage); + #scrate::storage::StorageDoubleMap<#key1_type, #key2_type, #typ> + >::insert(&k1, &k2, &v); }); }} }, @@ -380,7 +386,7 @@ fn decl_store_extra_genesis( } let mut has_scall = false; - let mut scall = quote!{ ( |_, _| {} ) }; + let mut scall = quote!{ let scall: fn(&Self) = |_| {}; scall }; let mut genesis_extrafields = TokenStream2::new(); let mut genesis_extrafields_default = TokenStream2::new(); @@ -418,14 +424,7 @@ fn decl_store_extra_genesis( assimilate_require_generic |= ext::expr_contains_ident(&expr.content, traitinstance); let content = &expr.content; scall = quote_spanned! { expr.span() => - let scall: fn( - &mut ( - #scrate::sr_primitives::StorageOverlay, - #scrate::sr_primitives::ChildrenStorageOverlay - ), - &Self - ) = #content; - scall + let scall: fn(&Self) = #content; scall }; has_scall = true; }, @@ -558,13 +557,13 @@ fn decl_store_extra_genesis( #scrate::sr_primitives::ChildrenStorageOverlay, ), ) -> std::result::Result<(), String> #fn_where_clause { - let storage = &mut tuple_storage.0; + #scrate::with_storage(tuple_storage, || { + #builders - #builders + #scall(&self); - #scall(tuple_storage, &self); - - Ok(()) + Ok(()) + }) } } @@ -771,17 +770,6 @@ fn decl_storage_items( // Propagate doc attributes. let attrs = attrs.inner.iter().filter_map(|a| a.parse_meta().ok()).filter(|m| m.name() == "doc"); - // create default value delegator - let default_delegator_ident = Ident::new( - &format!("{}{}", name.to_string(), "DefaultDelegator"), - proc_macro2::Span::call_site(), - ); - let default_delegator_return = if !type_infos.is_option { - quote! { Some(#fielddefault) } - } else { - quote! { #fielddefault } - }; - let i = impls::Impls { scrate, visibility, @@ -791,8 +779,6 @@ fn decl_storage_items( instance_opts, type_infos, fielddefault, - default_delegator_ident, - default_delegator_return, prefix: build_prefix(cratename, name), name, attrs, @@ -903,14 +889,14 @@ fn impl_store_fns( quote!{ #( #[ #attrs ] )* pub fn #get_fn() -> #value_type { - <#name<#struct_trait #instance> as - #scrate::storage::hashed::generator::StorageValue<#typ>> :: get( - &#scrate::storage::RuntimeStorage - ) + < + #name<#struct_trait #instance> as + #scrate::storage::StorageValue<#typ> + >::get() } } }, - DeclStorageTypeInfosKind::Map { key_type, .. } => { + DeclStorageTypeInfosKind::Map { key_type, is_linked, .. } => { let struct_trait = if ext::type_contains_ident(&type_infos.value_type, traitinstance) || ext::type_contains_ident(key_type, traitinstance) { @@ -919,13 +905,19 @@ fn impl_store_fns( quote!() }; + let map = if is_linked { + quote! { StorageLinkedMap } + } else { + quote! { StorageMap } + }; + quote!{ #( #[ #attrs ] )* pub fn #get_fn>(key: K) -> #value_type { < #name<#struct_trait #instance> as - #scrate::storage::hashed::generator::StorageMap<#key_type, #typ> - >::get(key.borrow(), &#scrate::storage::RuntimeStorage) + #scrate::storage::#map<#key_type, #typ> + >::get(key.borrow()) } } } @@ -949,8 +941,8 @@ fn impl_store_fns( { < #name<#struct_trait #instance> as - #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ> - >::get(k1, k2, &#scrate::storage::RuntimeStorage) + #scrate::storage::StorageDoubleMap<#key1_type, #key2_type, #typ> + >::get(k1, k2) } } } diff --git a/substrate/srml/support/src/hashable.rs b/substrate/srml/support/src/hashable.rs index b3ee2b3612..f0918cc358 100644 --- a/substrate/srml/support/src/hashable.rs +++ b/substrate/srml/support/src/hashable.rs @@ -18,7 +18,7 @@ use crate::codec::Codec; use runtime_io::{blake2_128, blake2_256, twox_128, twox_256}; -use crate::storage::hashed::generator::StorageHasher; +use crate::storage::hashed::StorageHasher; use crate::Twox64Concat; use crate::rstd::prelude::Vec; diff --git a/substrate/srml/support/src/lib.rs b/substrate/srml/support/src/lib.rs index 9ebd848fca..6795603ade 100644 --- a/substrate/srml/support/src/lib.rs +++ b/substrate/srml/support/src/lib.rs @@ -35,11 +35,11 @@ pub use codec; pub use once_cell; #[doc(hidden)] pub use paste; +#[cfg(feature = "std")] +#[doc(hidden)] +pub use runtime_io::with_storage; -pub use self::storage::hashed::generator::{ - HashedStorage, Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat -}; -pub use self::storage::unhashed::generator::UnhashedStorage; +pub use self::storage::hashed::{Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat}; #[macro_use] pub mod dispatch; @@ -61,10 +61,7 @@ pub mod unsigned; mod double_map; pub mod traits; -pub use self::storage::{ - StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap, AppendableStorageMap, - DecodeLengthStorageMap, -}; +pub use self::storage::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap}; pub use self::hashable::Hashable; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::double_map::StorageDoubleMapWithHasher; diff --git a/substrate/srml/support/src/metadata.rs b/substrate/srml/support/src/metadata.rs index 4bc1f906da..7ae5f7d193 100644 --- a/substrate/srml/support/src/metadata.rs +++ b/substrate/srml/support/src/metadata.rs @@ -324,7 +324,7 @@ mod tests { StorageMethod : Option; } add_extra_genesis { - build(|_, _| {}); + build(|_| {}); } } } diff --git a/substrate/srml/support/src/storage/child.rs b/substrate/srml/support/src/storage/child.rs index e69de29bb2..6000dd2f17 100644 --- a/substrate/srml/support/src/storage/child.rs +++ b/substrate/srml/support/src/storage/child.rs @@ -0,0 +1,106 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Operation on runtime child storages. +//! +//! This module is a currently only a variant of unhashed with additional `storage_key`. +//! Note that `storage_key` must be unique and strong (strong in the sense of being long enough to +//! avoid collision from a resistant hash function (which unique implies)). +// NOTE: could replace unhashed by having only one kind of storage (root being null storage key (storage_key can become Option<&[u8]>). + +use super::{Codec, Encode, Decode, Vec}; + +/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. +pub fn get(storage_key: &[u8], key: &[u8]) -> Option { + runtime_io::child_storage(storage_key, key).map(|v| { + Decode::decode(&mut &v[..]).expect("storage is not null, therefore must be a valid type") + }) +} + +/// Return the value of the item in storage under `key`, or the type's default if there is no +/// explicit entry. +pub fn get_or_default(storage_key: &[u8], key: &[u8]) -> T { + get(storage_key, key).unwrap_or_else(Default::default) +} + +/// Return the value of the item in storage under `key`, or `default_value` if there is no +/// explicit entry. +pub fn get_or(storage_key: &[u8], key: &[u8], default_value: T) -> T { + get(storage_key, key).unwrap_or(default_value) +} + +/// Return the value of the item in storage under `key`, or `default_value()` if there is no +/// explicit entry. +pub fn get_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + get(storage_key, key).unwrap_or_else(default_value) +} + +/// Put `value` in storage under `key`. +pub fn put(storage_key: &[u8], key: &[u8], value: &T) { + value.using_encoded(|slice| runtime_io::set_child_storage(storage_key, key, slice)); +} + +/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. +pub fn take(storage_key: &[u8], key: &[u8]) -> Option { + let r = get(storage_key, key); + if r.is_some() { + kill(storage_key, key); + } + r +} + +/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, +/// the default for its type. +pub fn take_or_default(storage_key: &[u8], key: &[u8]) -> T { + take(storage_key, key).unwrap_or_else(Default::default) +} + +/// Return the value of the item in storage under `key`, or `default_value` if there is no +/// explicit entry. Ensure there is no explicit entry on return. +pub fn take_or(storage_key: &[u8],key: &[u8], default_value: T) -> T { + take(storage_key, key).unwrap_or(default_value) +} + +/// Return the value of the item in storage under `key`, or `default_value()` if there is no +/// explicit entry. Ensure there is no explicit entry on return. +pub fn take_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { + take(storage_key, key).unwrap_or_else(default_value) +} + +/// Check to see if `key` has an explicit entry in storage. +pub fn exists(storage_key: &[u8], key: &[u8]) -> bool { + runtime_io::read_child_storage(storage_key, key, &mut [0;0][..], 0).is_some() +} + +/// Remove all `storage_key` key/values +pub fn kill_storage(storage_key: &[u8]) { + runtime_io::kill_child_storage(storage_key) +} + +/// Ensure `key` has no explicit entry in storage. +pub fn kill(storage_key: &[u8], key: &[u8]) { + runtime_io::clear_child_storage(storage_key, key); +} + +/// Get a Vec of bytes from storage. +pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option> { + runtime_io::child_storage(storage_key, key) +} + +/// Put a raw byte slice into storage. +pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) { + runtime_io::set_child_storage(storage_key, key, value) +} diff --git a/substrate/srml/support/src/storage/generator/double_map.rs b/substrate/srml/support/src/storage/generator/double_map.rs new file mode 100644 index 0000000000..a1898c3b88 --- /dev/null +++ b/substrate/srml/support/src/storage/generator/double_map.rs @@ -0,0 +1,194 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use sr_std::prelude::*; +use codec::{Codec, Encode, EncodeAppend}; +use crate::{storage::{self, unhashed, hashed::StorageHasher}, rstd::borrow::Borrow}; + +/// Generator for `StorageDoubleMap` used by `decl_storage`. +/// +/// # Mapping of keys to a storage path +/// +/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. +/// The first part is a hash of a concatenation of the `key1_prefix` and `Key1`. And the second part +/// is a hash of a `Key2`. +/// +/// Thus value for (key1, key2) is stored at `Hasher1(key1_prefix ++ key1) ++ Hasher2(key2)`. +/// +/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the +/// trie. +pub trait StorageDoubleMap { + /// The type that get/take returns. + type Query; + + /// Hasher for the first key. + type Hasher1: StorageHasher; + + /// Hasher for the second key. + type Hasher2: StorageHasher; + + /// Get the prefix for first key. + fn key1_prefix() -> &'static [u8]; + + /// Convert an optional value retrieved from storage to the type queried. + fn from_optional_value_to_query(v: Option) -> Self::Query; + + /// Convert a query to an optional value into storage. + fn from_query_to_optional_value(v: Self::Query) -> Option; + + /// Generate the first part of the key used in top storage. + fn storage_double_map_final_key1(k1: &KArg1) -> ::Output + where + KArg1: ?Sized + Encode, + K1: Borrow, + { + let mut final_key1 = Self::key1_prefix().to_vec(); + k1.encode_to(&mut final_key1); + Self::Hasher1::hash(&final_key1) + } + + /// Generate the full key used in top storage. + fn storage_double_map_final_key(k1: &KArg1, k2: &KArg2) -> Vec + where + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + K1: Borrow, + K2: Borrow, + { + let mut final_key = Self::storage_double_map_final_key1(k1).as_ref().to_vec(); + final_key.extend_from_slice(k2.using_encoded(Self::Hasher2::hash).as_ref()); + final_key + } +} + +impl storage::StorageDoubleMap for G +where + K1: Encode, + K2: Encode, + V: Codec, + G: StorageDoubleMap, +{ + type Query = G::Query; + + fn exists(k1: &KArg1, k2: &KArg2) -> bool + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + { + unhashed::exists(&Self::storage_double_map_final_key(k1, k2)) + } + + fn get(k1: &KArg1, k2: &KArg2) -> Self::Query + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + { + G::from_optional_value_to_query(unhashed::get(&Self::storage_double_map_final_key(k1, k2))) + } + + fn take(k1: &KArg1, k2: &KArg2) -> Self::Query + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + { + let final_key = Self::storage_double_map_final_key(k1, k2); + + let value = unhashed::take(&final_key); + G::from_optional_value_to_query(value) + } + + fn insert(k1: &KArg1, k2: &KArg2, val: &VArg) + where + K1: Borrow, + K2: Borrow, + V: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + VArg: ?Sized + Encode, + { + unhashed::put(&Self::storage_double_map_final_key(k1, k2), &val.borrow()) + } + + fn remove(k1: &KArg1, k2: &KArg2) + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + { + unhashed::kill(&Self::storage_double_map_final_key(k1, k2)) + } + + fn remove_prefix(k1: &KArg1) where KArg1: ?Sized + Encode, K1: Borrow { + unhashed::kill_prefix(Self::storage_double_map_final_key1(k1).as_ref()) + } + + fn mutate(k1: &KArg1, k2: &KArg2, f: F) -> R + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + F: FnOnce(&mut Self::Query) -> R, + { + let mut val = G::get(k1, k2); + + let ret = f(&mut val); + match G::from_query_to_optional_value(val) { + Some(ref val) => G::insert(k1, k2, val), + None => G::remove(k1, k2), + } + ret + } + + fn append( + k1: &KArg1, + k2: &KArg2, + items: &[I], + ) -> Result<(), &'static str> + where + K1: Borrow, + K2: Borrow, + KArg1: ?Sized + Encode, + KArg2: ?Sized + Encode, + I: codec::Encode, + V: EncodeAppend, + { + let final_key = Self::storage_double_map_final_key(k1, k2); + + let encoded_value = unhashed::get_raw(&final_key) + .unwrap_or_else(|| { + match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) { + Some(value) => value.encode(), + None => vec![], + } + }); + + let new_val = V::append( + encoded_value, + items, + ).map_err(|_| "Could not append given item")?; + unhashed::put_raw(&final_key, &new_val); + + Ok(()) + } +} diff --git a/substrate/srml/support/src/storage/generator/linked_map.rs b/substrate/srml/support/src/storage/generator/linked_map.rs new file mode 100644 index 0000000000..b087cf42f5 --- /dev/null +++ b/substrate/srml/support/src/storage/generator/linked_map.rs @@ -0,0 +1,327 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use codec::{Codec, Encode, Decode}; +use crate::{storage::{self, unhashed, hashed::StorageHasher}, traits::Len}; +use sr_std::{ + borrow::Borrow, + marker::PhantomData, +}; + +/// Generator for `StorageLinkedMap` used by `decl_storage`. +/// +/// For each key value is stored at `Hasher(prefix ++ key)` along with a linkage used for +/// enumeration. +pub trait StorageLinkedMap { + /// The type that get/take returns. + type Query; + + /// Hasher used to insert into storage. + type Hasher: StorageHasher; + + /// Prefix used to prepend each key. + fn prefix() -> &'static [u8]; + + /// Key used to store linked map head. + fn final_head_key() -> &'static [u8]; + + /// Convert an optionnal value retrieved from storage to the type queried. + fn from_optional_value_to_query(v: Option) -> Self::Query; + + /// Convert a query to an optionnal value into storage. + fn from_query_to_optional_value(v: Self::Query) -> Option; + + /// Generate the full key used in top storage. + fn storage_linked_map_final_key(key: KeyArg) -> ::Output + where + KeyArg: Borrow, + { + let mut final_key = Self::prefix().to_vec(); + key.borrow().encode_to(&mut final_key); + Self::Hasher::hash(&final_key) + } +} + +/// Linkage data of an element (it's successor and predecessor) +#[derive(Encode, Decode)] +pub struct Linkage { + /// Previous element key in storage (None for the first element) + pub previous: Option, + /// Next element key in storage (None for the last element) + pub next: Option, +} + +impl Default for Linkage { + fn default() -> Self { + Self { + previous: None, + next: None, + } + } +} + +/// A key-value pair iterator for enumerable map. +pub struct Enumerator> { + next: Option, + _phantom: PhantomData<(G, V)>, +} + +impl> Iterator for Enumerator { + type Item = (K, V); + + fn next(&mut self) -> Option { + let next = self.next.take()?; + let (val, linkage): (V, Linkage) = { + let next_full_key = G::storage_linked_map_final_key(&next); + unhashed::get(next_full_key.as_ref()) + .expect("previous/next only contain existing entires; + we enumerate using next; entry exists; qed") + }; + + self.next = linkage.next; + Some((next, val)) + } +} + +/// Update linkage when this element is removed. +/// +/// Takes care of updating previous and next elements points +/// as well as updates head if the element is first or last. +fn remove_linkage>(linkage: Linkage) { + let next_key = linkage.next.as_ref() + .map(G::storage_linked_map_final_key) + .map(|x| x.as_ref().to_vec()); + let prev_key = linkage.previous.as_ref() + .map(G::storage_linked_map_final_key) + .map(|x| x.as_ref().to_vec()); + + if let Some(prev_key) = prev_key { + // Retrieve previous element and update `next` + let mut res = read_with_linkage::<_, _, G>(prev_key.as_ref()) + .expect("Linkage is updated in case entry is removed; + it always points to existing keys; qed"); + res.1.next = linkage.next; + unhashed::put(prev_key.as_ref(), &res); + } else { + // we were first so let's update the head + write_head::<_, _, G>(linkage.next.as_ref()); + } + if let Some(next_key) = next_key { + // Update previous of next element + let mut res = read_with_linkage::<_, _, G>(next_key.as_ref()) + .expect("Linkage is updated in case entry is removed; + it always points to existing keys; qed"); + res.1.previous = linkage.previous; + unhashed::put(next_key.as_ref(), &res); + } +} + +/// Read the contained data and it's linkage. +fn read_with_linkage(key: &[u8]) -> Option<(V, Linkage)> +where + K: Codec, + V: Codec, + G: StorageLinkedMap +{ + unhashed::get(key) +} + +/// Generate linkage for newly inserted element. +/// +/// Takes care of updating head and previous head's pointer. +fn new_head_linkage(key: &K) -> Linkage +where + K: Codec, + V: Codec, + G: StorageLinkedMap +{ + if let Some(head) = read_head::<_, _, G>() { + // update previous head predecessor + { + let head_key = G::storage_linked_map_final_key(&head); + let (data, linkage) = read_with_linkage::<_, _, G>(head_key.as_ref()) + .expect("head is set when first element is inserted + and unset when last element is removed; + if head is Some then it points to existing key; qed"); + unhashed::put(head_key.as_ref(), &(data, Linkage { + next: linkage.next.as_ref(), + previous: Some(key), + })); + } + // update to current head + write_head::<_, _, G>(Some(key)); + // return linkage with pointer to previous head + let mut linkage = Linkage::default(); + linkage.next = Some(head); + linkage + } else { + // we are first - update the head and produce empty linkage + write_head::<_, _, G>(Some(key)); + Linkage::default() + } +} + +/// Read current head pointer. +fn read_head() -> Option +where + K: Codec, + V: Codec, + G: StorageLinkedMap +{ + unhashed::get(G::final_head_key()) +} + +/// Overwrite current head pointer. +/// +/// If `None` is given head is removed from storage. +fn write_head(head: Option<&K>) +where + K: Codec, + V: Codec, + G: StorageLinkedMap +{ + match head { + Some(head) => unhashed::put(G::final_head_key(), head), + None => unhashed::kill(G::final_head_key()), + } +} + +impl> storage::StorageLinkedMap for G { + type Query = G::Query; + + type Enumerator = Enumerator; + + fn exists>(key: KeyArg) -> bool { + unhashed::exists(Self::storage_linked_map_final_key(key).as_ref()) + } + + fn get>(key: KeyArg) -> Self::Query { + let val = unhashed::get(Self::storage_linked_map_final_key(key).as_ref()); + G::from_optional_value_to_query(val) + } + + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2) { + let final_key1 = Self::storage_linked_map_final_key(key1.borrow()); + let final_key2 = Self::storage_linked_map_final_key(key2.borrow()); + let full_value_1 = read_with_linkage::<_, _, G>(final_key1.as_ref()); + let full_value_2 = read_with_linkage::<_, _, G>(final_key2.as_ref()); + + match (full_value_1, full_value_2) { + // Just keep linkage in order and only swap values. + (Some((value1, linkage1)), Some((value2, linkage2))) => { + unhashed::put(final_key1.as_ref(), &(value2, linkage1)); + unhashed::put(final_key2.as_ref(), &(value1, linkage2)); + } + // Remove key and insert the new one. + (Some((value, _linkage)), None) => { + Self::remove(key1); + let linkage = new_head_linkage::<_, _, G>(key2.borrow()); + unhashed::put(final_key2.as_ref(), &(value, linkage)); + } + // Remove key and insert the new one. + (None, Some((value, _linkage))) => { + Self::remove(key2); + let linkage = new_head_linkage::<_, _, G>(key1.borrow()); + unhashed::put(final_key1.as_ref(), &(value, linkage)); + } + // No-op. + (None, None) => (), + } + } + + fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg) { + let final_key = Self::storage_linked_map_final_key(key.borrow()); + let linkage = match read_with_linkage::<_, _, G>(final_key.as_ref()) { + // overwrite but reuse existing linkage + Some((_data, linkage)) => linkage, + // create new linkage + None => new_head_linkage::<_, _, G>(key.borrow()), + }; + unhashed::put(final_key.as_ref(), &(val.borrow(), linkage)) + } + + fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) + where + V: AsRef + { + let final_key = Self::storage_linked_map_final_key(key.borrow()); + let linkage = match read_with_linkage::<_, _, G>(final_key.as_ref()) { + // overwrite but reuse existing linkage + Some((_data, linkage)) => linkage, + // create new linkage + None => new_head_linkage::<_, _, G>(key.borrow()), + }; + unhashed::put(final_key.as_ref(), &(&val, &linkage)) + } + + fn remove>(key: KeyArg) { + G::take(key); + } + + fn mutate, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R { + let final_key = Self::storage_linked_map_final_key(key.borrow()); + + let (mut val, _linkage) = read_with_linkage::<_, _, G>(final_key.as_ref()) + .map(|(data, linkage)| (G::from_optional_value_to_query(Some(data)), Some(linkage))) + .unwrap_or_else(|| (G::from_optional_value_to_query(None), None)); + + let ret = f(&mut val); + match G::from_query_to_optional_value(val) { + Some(ref val) => G::insert(key.borrow(), val), + None => G::remove(key.borrow()), + } + ret + } + + fn take>(key: KeyArg) -> Self::Query { + let final_key = Self::storage_linked_map_final_key(key); + + let full_value: Option<(V, Linkage)> = unhashed::take(final_key.as_ref()); + + let value = full_value.map(|(data, linkage)| { + remove_linkage::<_, _, G>(linkage); + data + }); + + G::from_optional_value_to_query(value) + } + + fn enumerate() -> Self::Enumerator { + Enumerator::<_, _, G> { + next: read_head::<_, _, G>(), + _phantom: Default::default(), + } + } + + fn head() -> Option { + read_head::<_, _, G>() + } + + fn decode_len>(key: KeyArg) -> Result + where V: codec::DecodeLength + Len + { + let key = Self::storage_linked_map_final_key(key); + if let Some(v) = unhashed::get_raw(key.as_ref()) { + ::len(&v).map_err(|e| e.what()) + } else { + let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None)) + .map(|v| v.len()) + .unwrap_or(0); + + Ok(len) + } + } +} diff --git a/substrate/srml/support/src/storage/generator/map.rs b/substrate/srml/support/src/storage/generator/map.rs new file mode 100644 index 0000000000..1d660da3b4 --- /dev/null +++ b/substrate/srml/support/src/storage/generator/map.rs @@ -0,0 +1,167 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[cfg(not(feature = "std"))] +use sr_std::prelude::*; +use sr_std::borrow::Borrow; +use codec::{Codec, Encode}; +use crate::{storage::{self, unhashed, hashed::StorageHasher}, traits::Len}; + +/// Generator for `StorageMap` used by `decl_storage`. +/// +/// For each key value is stored at `Hasher(prefix ++ key)`. +pub trait StorageMap { + /// The type that get/take returns. + type Query; + + /// Hasher used to insert into storage. + type Hasher: StorageHasher; + + /// Prefix used to prepend each key. + fn prefix() -> &'static [u8]; + + /// Convert an optional value retrieved from storage to the type queried. + fn from_optional_value_to_query(v: Option) -> Self::Query; + + /// Convert a query to an optional value into storage. + fn from_query_to_optional_value(v: Self::Query) -> Option; + + /// Generate the full key used in top storage. + fn storage_map_final_key(key: KeyArg) -> ::Output + where + KeyArg: Borrow, + { + let mut final_key = Self::prefix().to_vec(); + key.borrow().encode_to(&mut final_key); + Self::Hasher::hash(&final_key) + } +} + +impl> storage::StorageMap for G { + type Query = G::Query; + + fn hashed_key_for>(key: KeyArg) -> Vec { + Self::storage_map_final_key(key).as_ref().to_vec() + } + + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2) { + let k1 = Self::storage_map_final_key(key1); + let k2 = Self::storage_map_final_key(key2); + + let v1 = unhashed::get_raw(k1.as_ref()); + if let Some(val) = unhashed::get_raw(k2.as_ref()) { + unhashed::put_raw(k1.as_ref(), &val); + } else { + unhashed::kill(k1.as_ref()) + } + if let Some(val) = v1 { + unhashed::put_raw(k2.as_ref(), &val); + } else { + unhashed::kill(k2.as_ref()) + } + } + + fn exists>(key: KeyArg) -> bool { + unhashed::exists(Self::storage_map_final_key(key).as_ref()) + } + + fn get>(key: KeyArg) -> Self::Query { + G::from_optional_value_to_query(unhashed::get(Self::storage_map_final_key(key).as_ref())) + } + + fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg) { + unhashed::put(Self::storage_map_final_key(key).as_ref(), &val.borrow()) + } + + fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) + where V: AsRef + { + val.using_encoded(|b| unhashed::put_raw(Self::storage_map_final_key(key).as_ref(), b)) + } + + fn remove>(key: KeyArg) { + unhashed::kill(Self::storage_map_final_key(key).as_ref()) + } + + fn mutate, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R { + let mut val = G::get(key.borrow()); + + let ret = f(&mut val); + match G::from_query_to_optional_value(val) { + Some(ref val) => G::insert(key, val), + None => G::remove(key), + } + ret + } + + fn take>(key: KeyArg) -> Self::Query { + let key = Self::storage_map_final_key(key); + let value = unhashed::take(key.as_ref()); + G::from_optional_value_to_query(value) + } + + fn append<'a, I, R, KeyArg>(key: KeyArg, items: R) -> Result<(), &'static str> + where + KeyArg: Borrow, + I: 'a + codec::Encode, + V: codec::EncodeAppend, + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + { + let key = Self::storage_map_final_key(key); + let encoded_value = unhashed::get_raw(key.as_ref()) + .unwrap_or_else(|| { + match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) { + Some(value) => value.encode(), + None => vec![], + } + }); + + let new_val = V::append( + encoded_value, + items, + ).map_err(|_| "Could not append given item")?; + unhashed::put_raw(key.as_ref(), &new_val); + Ok(()) + } + + fn append_or_insert<'a, I, R, KeyArg>(key: KeyArg, items: R) + where + KeyArg: Borrow, + I: 'a + codec::Encode + Clone, + V: codec::EncodeAppend + crate::rstd::iter::FromIterator, + R: IntoIterator + Clone, + R::IntoIter: ExactSizeIterator, + { + Self::append(key.borrow(), items.clone()) + .unwrap_or_else(|_| Self::insert(key, &items.into_iter().cloned().collect())); + } + + fn decode_len>(key: KeyArg) -> Result + where V: codec::DecodeLength + Len + { + let key = Self::storage_map_final_key(key); + if let Some(v) = unhashed::get_raw(key.as_ref()) { + ::len(&v).map_err(|e| e.what()) + } else { + let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None)) + .map(|v| v.len()) + .unwrap_or(0); + + Ok(len) + } + } +} diff --git a/substrate/srml/support/src/storage/generator/mod.rs b/substrate/srml/support/src/storage/generator/mod.rs new file mode 100644 index 0000000000..a53ce7a831 --- /dev/null +++ b/substrate/srml/support/src/storage/generator/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Generators are a set of trait on which storage traits are implemented. +//! +//! (i.e. implementing the generator for StorageValue on a type will automatically derive the +//! implementation of StorageValue for this type). +//! +//! They are used by `decl_storage`. + +mod linked_map; +mod map; +mod double_map; +mod value; + +pub use linked_map::{StorageLinkedMap, Enumerator}; +pub use map::StorageMap; +pub use double_map::StorageDoubleMap; +pub use value::StorageValue; diff --git a/substrate/srml/support/src/storage/generator/value.rs b/substrate/srml/support/src/storage/generator/value.rs new file mode 100644 index 0000000000..32b4a195c8 --- /dev/null +++ b/substrate/srml/support/src/storage/generator/value.rs @@ -0,0 +1,156 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[cfg(not(feature = "std"))] +use sr_std::prelude::*; +use sr_std::{borrow::Borrow, iter::FromIterator}; +use codec::{Codec, Encode}; +use crate::{storage::{self, unhashed, hashed::{Twox128, StorageHasher}}, traits::Len}; + +/// Generator for `StorageValue` used by `decl_storage`. +/// +/// Value is stored at `Twox128(unhashed_key)`. +pub trait StorageValue { + /// The type that get/take returns. + type Query; + + /// Unhashed key used in storage + fn unhashed_key() -> &'static [u8]; + + /// Convert an optional value retrieved from storage to the type queried. + fn from_optional_value_to_query(v: Option) -> Self::Query; + + /// Convert a query to an optional value into storage. + fn from_query_to_optional_value(v: Self::Query) -> Option; + + /// Generate the full key used in top storage. + fn storage_value_final_key() -> [u8; 16] { + Twox128::hash(Self::unhashed_key()) + } +} + +impl> storage::StorageValue for G { + type Query = G::Query; + + fn hashed_key() -> [u8; 16] { + Self::storage_value_final_key() + } + + fn exists() -> bool { + unhashed::exists(&Self::storage_value_final_key()) + } + + fn get() -> Self::Query { + let value = unhashed::get(&Self::storage_value_final_key()); + G::from_optional_value_to_query(value) + } + + fn put>(val: Arg) { + unhashed::put(&Self::storage_value_final_key(), val.borrow()) + } + + fn put_ref(val: &Arg) where T: AsRef { + val.using_encoded(|b| unhashed::put_raw(&Self::storage_value_final_key(), b)) + } + + fn kill() { + unhashed::kill(&Self::storage_value_final_key()) + } + + fn mutate R>(f: F) -> R { + let mut val = G::get(); + + let ret = f(&mut val); + match G::from_query_to_optional_value(val) { + Some(ref val) => G::put(val), + None => G::kill(), + } + ret + } + + fn take() -> G::Query { + let key = Self::storage_value_final_key(); + let value = unhashed::get(&key); + if value.is_some() { + unhashed::kill(&key) + } + G::from_optional_value_to_query(value) + } + + /// Append the given items to the value in the storage. + /// + /// `T` is required to implement `codec::EncodeAppend`. + fn append<'a, I, R>(items: R) -> Result<(), &'static str> + where + I: 'a + codec::Encode, + T: codec::EncodeAppend, + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + { + let key = Self::storage_value_final_key(); + let encoded_value = unhashed::get_raw(&key) + .unwrap_or_else(|| { + match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) { + Some(value) => value.encode(), + None => vec![], + } + }); + + let new_val = T::append( + encoded_value, + items, + ).map_err(|_| "Could not append given item")?; + unhashed::put_raw(&key, &new_val); + Ok(()) + } + + /// Safely append the given items to the value in the storage. If a codec error occurs, then the + /// old (presumably corrupt) value is replaced with the given `items`. + /// + /// `T` is required to implement `codec::EncodeAppend`. + fn append_or_put<'a, I, R>(items: R) + where + I: 'a + codec::Encode + Clone, + T: codec::EncodeAppend + FromIterator, + R: IntoIterator + Clone, + R::IntoIter: ExactSizeIterator, + { + Self::append(items.clone()) + .unwrap_or_else(|_| Self::put(&items.into_iter().cloned().collect())); + } + + /// Read the length of the value in a fast way, without decoding the entire value. + /// + /// `T` is required to implement `Codec::DecodeLength`. + /// + /// Note that `0` is returned as the default value if no encoded value exists at the given key. + /// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()` + /// function for this purpose. + fn decode_len() -> Result where T: codec::DecodeLength, T: Len { + let key = Self::storage_value_final_key(); + + // attempt to get the length directly. + if let Some(k) = unhashed::get_raw(&key) { + ::len(&k).map_err(|e| e.what()) + } else { + let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None)) + .map(|v| v.len()) + .unwrap_or(0); + + Ok(len) + } + } +} diff --git a/substrate/srml/support/src/storage/hashed/mod.rs b/substrate/srml/support/src/storage/hashed.rs similarity index 85% rename from substrate/srml/support/src/storage/hashed/mod.rs rename to substrate/srml/support/src/storage/hashed.rs index 5ca718df8c..c125cc3479 100644 --- a/substrate/srml/support/src/storage/hashed/mod.rs +++ b/substrate/srml/support/src/storage/hashed.rs @@ -16,12 +16,72 @@ //! Operation on runtime storage using hashed keys. -pub mod generator; use super::unhashed; use crate::rstd::prelude::*; use crate::rstd::borrow::Borrow; -use runtime_io::{self, twox_128}; use crate::codec::{Codec, Encode, Decode, KeyedVec}; +use runtime_io::{self, twox_64, twox_128, blake2_128, twox_256, blake2_256}; + +/// Hasher to use to hash keys to insert to storage. +pub trait StorageHasher: 'static { + type Output: AsRef<[u8]>; + fn hash(x: &[u8]) -> Self::Output; +} + +/// Hash storage keys with `concat(twox64(key), key)` +pub struct Twox64Concat; +impl StorageHasher for Twox64Concat { + type Output = Vec; + fn hash(x: &[u8]) -> Vec { + twox_64(x) + .into_iter() + .chain(x.into_iter()) + .cloned() + .collect::>() + } +} + +#[test] +fn test_twox_64_concat() { + let r = Twox64Concat::hash(b"foo"); + assert_eq!(r.split_at(8), (&twox_128(b"foo")[..8], &b"foo"[..])) +} + +/// Hash storage keys with blake2 128 +pub struct Blake2_128; +impl StorageHasher for Blake2_128 { + type Output = [u8; 16]; + fn hash(x: &[u8]) -> [u8; 16] { + blake2_128(x) + } +} + +/// Hash storage keys with blake2 256 +pub struct Blake2_256; +impl StorageHasher for Blake2_256 { + type Output = [u8; 32]; + fn hash(x: &[u8]) -> [u8; 32] { + blake2_256(x) + } +} + +/// Hash storage keys with twox 128 +pub struct Twox128; +impl StorageHasher for Twox128 { + type Output = [u8; 16]; + fn hash(x: &[u8]) -> [u8; 16] { + twox_128(x) + } +} + +/// Hash storage keys with twox 256 +pub struct Twox256; +impl StorageHasher for Twox256 { + type Output = [u8; 32]; + fn hash(x: &[u8]) -> [u8; 32] { + twox_256(x) + } +} /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(hash: &HashFn, key: &[u8]) -> Option diff --git a/substrate/srml/support/src/storage/hashed/generator.rs b/substrate/srml/support/src/storage/hashed/generator.rs deleted file mode 100644 index 27b459e3ff..0000000000 --- a/substrate/srml/support/src/storage/hashed/generator.rs +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Abstract storage to use on HashedStorage trait. Please refer to the -//! [top level docs](../../index.html) for more detailed documentation about storage traits and functions. - -use crate::codec::{self, Encode}; -use crate::rstd::{prelude::{Vec, Box}, iter::FromIterator}; -#[cfg(feature = "std")] -use crate::storage::unhashed::generator::UnhashedStorage; -use crate::traits::{StorageDefault, Len}; -use runtime_io::{twox_64, twox_128, blake2_128, twox_256, blake2_256}; - -pub trait StorageHasher: 'static { - type Output: AsRef<[u8]>; - fn hash(x: &[u8]) -> Self::Output; -} - -/// Hash storage keys with `concat(twox64(key), key)` -pub struct Twox64Concat; -impl StorageHasher for Twox64Concat { - type Output = Vec; - fn hash(x: &[u8]) -> Vec { - twox_64(x) - .into_iter() - .chain(x.into_iter()) - .cloned() - .collect::>() - } -} - -#[test] -fn test_twox_64_concat() { - let r = Twox64Concat::hash(b"foo"); - assert_eq!(r.split_at(8), (&twox_128(b"foo")[..8], &b"foo"[..])) -} - -/// Hash storage keys with blake2 128 -pub struct Blake2_128; -impl StorageHasher for Blake2_128 { - type Output = [u8; 16]; - fn hash(x: &[u8]) -> [u8; 16] { - blake2_128(x) - } -} - -/// Hash storage keys with blake2 256 -pub struct Blake2_256; -impl StorageHasher for Blake2_256 { - type Output = [u8; 32]; - fn hash(x: &[u8]) -> [u8; 32] { - blake2_256(x) - } -} - -/// Hash storage keys with twox 128 -pub struct Twox128; -impl StorageHasher for Twox128 { - type Output = [u8; 16]; - fn hash(x: &[u8]) -> [u8; 16] { - twox_128(x) - } -} - -/// Hash storage keys with twox 256 -pub struct Twox256; -impl StorageHasher for Twox256 { - type Output = [u8; 32]; - fn hash(x: &[u8]) -> [u8; 32] { - twox_256(x) - } -} - -/// Abstraction around storage. -pub trait HashedStorage { - /// true if the key exists in storage. - fn exists(&self, key: &[u8]) -> bool; - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn get(&self, key: &[u8]) -> Option; - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if - /// it's not there. - fn require(&self, key: &[u8]) -> T { - self.get(key).expect("Required values must be in storage") - } - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. The type's - /// default is returned if it's not there. - fn get_or_default(&self, key: &[u8]) -> T { - self.get(key).unwrap_or_default() - } - - /// Put a value in under a key. - fn put(&mut self, key: &[u8], val: &T); - - /// Remove the bytes of a key from storage. - fn kill(&mut self, key: &[u8]); - - /// Take a value from storage, deleting it after reading. - fn take(&mut self, key: &[u8]) -> Option { - let value = self.get(key); - self.kill(key); - value - } - - /// Take a value from storage, deleting it after reading. - fn take_or_panic(&mut self, key: &[u8]) -> T { - self.take(key).expect("Required values must be in storage") - } - - /// Take a value from storage, deleting it after reading. - fn take_or_default(&mut self, key: &[u8]) -> T { - self.take(key).unwrap_or_default() - } - - /// Get a Vec of bytes from storage. - fn get_raw(&self, key: &[u8]) -> Option>; - - /// Put a raw byte slice into storage. - fn put_raw(&mut self, key: &[u8], value: &[u8]); -} - -// We use a construct like this during when genesis storage is being built. -#[cfg(feature = "std")] -impl HashedStorage for sr_primitives::StorageOverlay { - fn exists(&self, key: &[u8]) -> bool { - UnhashedStorage::exists(self, &H::hash(key).as_ref()) - } - - fn get(&self, key: &[u8]) -> Option { - UnhashedStorage::get(self, &H::hash(key).as_ref()) - } - - fn put(&mut self, key: &[u8], val: &T) { - UnhashedStorage::put(self, &H::hash(key).as_ref(), val) - } - - fn kill(&mut self, key: &[u8]) { - UnhashedStorage::kill(self, &H::hash(key).as_ref()) - } - - fn get_raw(&self, key: &[u8]) -> Option> { - UnhashedStorage::get_raw(self, &H::hash(key).as_ref()) - } - - fn put_raw(&mut self, key: &[u8], value: &[u8]) { - UnhashedStorage::put_raw(self, &H::hash(key).as_ref(), value) - } -} - -/// A strongly-typed value kept in storage. -pub trait StorageValue { - /// The type that get/take returns. - type Query; - /// Something that can provide the default value of this storage type. - type Default: StorageDefault; - - - /// Get the storage key. - fn key() -> &'static [u8]; - - /// true if the value is defined in storage. - fn exists>(storage: &S) -> bool { - storage.exists(Self::key()) - } - - /// Load the value from the provided storage instance. - fn get>(storage: &S) -> Self::Query; - - /// Take a value from storage, removing it afterwards. - fn take>(storage: &mut S) -> Self::Query; - - /// Store a value under this key into the provided storage instance. - fn put>(val: &T, storage: &mut S) { - storage.put(Self::key(), val) - } - - /// Store a value under this key into the provided storage instance; this can take any reference - /// type that derefs to `T` (and has `Encode` implemented). - /// Store a value under this key into the provided storage instance. - fn put_ref>(val: &Arg, storage: &mut S) where T: AsRef { - val.using_encoded(|b| storage.put_raw(Self::key(), b)) - } - - /// Mutate this value - fn mutate R, S: HashedStorage>(f: F, storage: &mut S) -> R; - - /// Clear the storage value. - fn kill>(storage: &mut S) { - storage.kill(Self::key()) - } - - /// Append the given items to the value in the storage. - /// - /// `T` is required to implement `codec::EncodeAppend`. - fn append<'a, S, I, R>( - items: R, - storage: &mut S, - ) -> Result<(), &'static str> where - S: HashedStorage, - I: 'a + codec::Encode, - T: codec::EncodeAppend, - R: IntoIterator, - R::IntoIter: ExactSizeIterator, - { - let new_val = ::append( - // if the key exists, directly append to it. - storage.get_raw(Self::key()).unwrap_or_else(|| { - // otherwise, try and read a proper __provided__ default. - Self::Default::default().map(|v| v.encode()) - // or just use the Rust's `default()` value. - .unwrap_or_default() - }), - items, - ).map_err(|_| "Could not append given item")?; - storage.put_raw(Self::key(), &new_val); - Ok(()) - } - - /// Safely append the given items to the value in the storage. If a codec error occurs, then the - /// old (presumably corrupt) value is replaced with the given `items`. - /// - /// `T` is required to implement `codec::EncodeAppend`. - fn append_or_put<'a, S, I, R>( - items: R, - storage: &mut S, - ) where - S: HashedStorage, - I: 'a + codec::Encode + Clone, - T: codec::EncodeAppend + FromIterator, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - Self::append(items.clone(), storage) - .unwrap_or_else(|_| Self::put(&items.into_iter().cloned().collect(), storage)); - } - - /// Read the length of the value in a fast way, without decoding the entire value. - /// - /// `T` is required to implement `Codec::DecodeLength`. - /// - /// Note that `0` is returned as the default value if no encoded value exists at the given key. - /// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()` - /// function for this purpose. - fn decode_len>(storage: &mut S) -> Result - where T: codec::DecodeLength, T: Len - { - // attempt to get the length directly. - if let Some(k) = storage.get_raw(Self::key()) { - ::len(&k).map_err(|e| e.what()) - } else { - Ok(Self::Default::default().map(|v| v.len()).unwrap_or(0)) - } - } -} - -/// A strongly-typed map in storage. -pub trait StorageMap { - /// The type that get/take returns. - type Query; - /// Hasher type - type Hasher: StorageHasher; - /// Something that can provide the default value of this storage type. - type Default: StorageDefault; - - /// Get the prefix key in storage. - fn prefix() -> &'static [u8]; - - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &K) -> Vec; - - /// true if the value is defined in storage. - fn exists>(key: &K, storage: &S) -> bool { - storage.exists(&Self::key_for(key)[..]) - } - - /// Load the value associated with the given key from the map. - fn get>(key: &K, storage: &S) -> Self::Query; - - /// Take the value under a key. - fn take>(key: &K, storage: &mut S) -> Self::Query; - - /// Swap the values of two keys. - fn swap>(key1: &K, key2: &K, storage: &mut S) { - let k1 = Self::key_for(key1); - let k2 = Self::key_for(key2); - let v1 = storage.get_raw(&k1[..]); - if let Some(val) = storage.get_raw(&k2[..]) { - storage.put_raw(&k1[..], &val[..]); - } else { - storage.kill(&k1[..]) - } - if let Some(val) = v1 { - storage.put_raw(&k2[..], &val[..]); - } else { - storage.kill(&k2[..]) - } - } - - /// Store a value to be associated with the given key from the map. - fn insert>(key: &K, val: &V, storage: &mut S) { - storage.put(&Self::key_for(key)[..], val); - } - - /// Store a value under this key into the provided storage instance; this can take any reference - /// type that derefs to `T` (and has `Encode` implemented). - /// Store a value under this key into the provided storage instance. - fn insert_ref>( - key: &K, - val: &Arg, - storage: &mut S - ) where V: AsRef { - val.using_encoded(|b| storage.put_raw(&Self::key_for(key)[..], b)) - } - - /// Remove the value under a key. - fn remove>(key: &K, storage: &mut S) { - storage.kill(&Self::key_for(key)[..]); - } - - /// Mutate the value under a key. - fn mutate R, S: HashedStorage>(key: &K, f: F, storage: &mut S) -> R; -} - -/// A `StorageMap` with enumerable entries. -pub trait EnumerableStorageMap: StorageMap { - /// Return current head element. - fn head>(storage: &S) -> Option; - - /// Enumerate all elements in the map. - fn enumerate<'a, S: HashedStorage>( - storage: &'a S - ) -> Box + 'a> where K: 'a, V: 'a; -} - -/// A `StorageMap` with appendable entries. -pub trait AppendableStorageMap: StorageMap { - /// Append the given items to the value in the storage. - /// - /// `V` is required to implement `codec::EncodeAppend`. - fn append<'a, S, I, R>( - key : &K, - items: R, - storage: &mut S, - ) -> Result<(), &'static str> where - S: HashedStorage, - I: 'a + codec::Encode, - V: codec::EncodeAppend, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - let k = Self::key_for(key); - let new_val = ::append( - storage.get_raw(&k[..]).unwrap_or_else(|| { - // otherwise, try and read a proper __provided__ default. - Self::Default::default().map(|v| v.encode()) - // or just use the default value. - .unwrap_or_default() - }), - items, - ).map_err(|_| "Could not append given item")?; - storage.put_raw(&k[..], &new_val); - Ok(()) - } - - /// Safely append the given items to the value in the storage. If a codec error occurs, then the - /// old (presumably corrupt) value is replaced with the given `items`. - /// - /// `T` is required to implement `codec::EncodeAppend`. - fn append_or_insert<'a, S, I, R>( - key : &K, - items: R, - storage: &mut S, - ) where - S: HashedStorage, - I: 'a + codec::Encode + Clone, - V: codec::EncodeAppend + crate::rstd::iter::FromIterator, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - Self::append(key, items.clone(), storage) - .unwrap_or_else(|_| Self::insert(key, &items.into_iter().cloned().collect(), storage)); - } -} - -/// A storage map with a decodable length. -pub trait DecodeLengthStorageMap: StorageMap { - /// Read the length of the value in a fast way, without decoding the entire value. - /// - /// `T` is required to implement `Codec::DecodeLength`. - /// - /// Note that `0` is returned as the default value if no encoded value exists at the given key. - /// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()` - /// function for this purpose. - fn decode_len>(key: &K, storage: &mut S) -> Result - where V: codec::DecodeLength, V: Len - { - let k = Self::key_for(key); - if let Some(v) = storage.get_raw(&k[..]) { - ::len(&v).map_err(|e| e.what()) - } else { - Ok(Self::Default::default().map(|v| v.len()).unwrap_or(0)) - } - } -} diff --git a/substrate/srml/support/src/storage/mod.rs b/substrate/srml/support/src/storage/mod.rs index aa3faee878..1524cd234a 100644 --- a/substrate/srml/support/src/storage/mod.rs +++ b/substrate/srml/support/src/storage/mod.rs @@ -19,100 +19,22 @@ use crate::rstd::prelude::*; use crate::rstd::{borrow::Borrow, iter::FromIterator}; use codec::{Codec, Encode, Decode, KeyedVec, EncodeAppend}; -use hashed::generator::{HashedStorage, StorageHasher}; -use unhashed::generator::UnhashedStorage; -use crate::traits::{StorageDefault, Len}; +use crate::traits::Len; #[macro_use] pub mod storage_items; pub mod unhashed; pub mod hashed; - -/// The underlying runtime storage. -pub struct RuntimeStorage; - -impl HashedStorage for RuntimeStorage { - fn exists(&self, key: &[u8]) -> bool { - hashed::exists(&H::hash, key) - } - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn get(&self, key: &[u8]) -> Option { - hashed::get(&H::hash, key) - } - - /// Put a value in under a key. - fn put(&mut self, key: &[u8], val: &T) { - hashed::put(&H::hash, key, val) - } - - /// Remove the bytes of a key from storage. - fn kill(&mut self, key: &[u8]) { - hashed::kill(&H::hash, key) - } - - /// Take a value from storage, deleting it after reading. - fn take(&mut self, key: &[u8]) -> Option { - hashed::take(&H::hash, key) - } - - fn get_raw(&self, key: &[u8]) -> Option> { - hashed::get_raw(&H::hash, key) - } - - fn put_raw(&mut self, key: &[u8], value: &[u8]) { - hashed::put_raw(&H::hash, key, value) - } -} - -impl UnhashedStorage for RuntimeStorage { - fn exists(&self, key: &[u8]) -> bool { - unhashed::exists(key) - } - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn get(&self, key: &[u8]) -> Option { - unhashed::get(key) - } - - /// Put a value in under a key. - fn put(&mut self, key: &[u8], val: &T) { - unhashed::put(key, val) - } - - /// Remove the bytes of a key from storage. - fn kill(&mut self, key: &[u8]) { - unhashed::kill(key) - } - - /// Remove the bytes of a key from storage. - fn kill_prefix(&mut self, prefix: &[u8]) { - unhashed::kill_prefix(prefix) - } - - /// Take a value from storage, deleting it after reading. - fn take(&mut self, key: &[u8]) -> Option { - unhashed::take(key) - } - - fn get_raw(&self, key: &[u8]) -> Option> { - unhashed::get_raw(key) - } - - fn put_raw(&mut self, key: &[u8], value: &[u8]) { - unhashed::put_raw(key, value) - } -} +pub mod child; +pub mod generator; /// A trait for working with macro-generated storage values under the substrate storage API. pub trait StorageValue { /// The type that get/take return. type Query; - /// Something that can provide the default value of this storage type. - type Default: StorageDefault; /// Get the storage key. - fn key() -> &'static [u8]; + fn hashed_key() -> [u8; 16]; /// Does the value (explicitly) exist in storage? fn exists() -> bool; @@ -166,72 +88,16 @@ pub trait StorageValue { /// /// `T` is required to implement `Codec::DecodeLength`. fn decode_len() -> Result - where T: codec::DecodeLength, T: Len; -} - -impl StorageValue for U where U: hashed::generator::StorageValue { - type Query = U::Query; - type Default = U::Default; - - fn key() -> &'static [u8] { - >::key() - } - fn exists() -> bool { - U::exists(&RuntimeStorage) - } - fn get() -> Self::Query { - U::get(&RuntimeStorage) - } - fn put>(val: Arg) { - U::put(val.borrow(), &mut RuntimeStorage) - } - fn put_ref(val: &Arg) where T: AsRef { - U::put_ref(val, &mut RuntimeStorage) - } - fn mutate R>(f: F) -> R { - U::mutate(f, &mut RuntimeStorage) - } - fn kill() { - U::kill(&mut RuntimeStorage) - } - fn take() -> Self::Query { - U::take(&mut RuntimeStorage) - } - fn append<'a, I, R>(items: R) -> Result<(), &'static str> where - I: 'a + Encode, - T: EncodeAppend, - R: IntoIterator, - R::IntoIter: ExactSizeIterator, - { - U::append(items, &mut RuntimeStorage) - } - fn append_or_put<'a, I, R>(items: R) where - I: 'a + Encode + Clone, - T: EncodeAppend + FromIterator, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - U::append_or_put(items, &mut RuntimeStorage) - } - fn decode_len() -> Result - where T: codec::DecodeLength, T: Len - { - U::decode_len(&mut RuntimeStorage) - } + where T: codec::DecodeLength + Len; } /// A strongly-typed map in storage. pub trait StorageMap { /// The type that get/take return. type Query; - /// Something that can provide the default value of this storage type. - type Default: StorageDefault; - - /// Get the prefix key in storage. - fn prefix() -> &'static [u8]; /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for>(key: KeyArg) -> Vec; + fn hashed_key_for>(key: KeyArg) -> Vec; /// Does the value (explicitly) exist in storage? fn exists>(key: KeyArg) -> bool; @@ -257,190 +123,101 @@ pub trait StorageMap { /// Take the value under a key. fn take>(key: KeyArg) -> Self::Query; -} - -impl StorageMap for U where U: hashed::generator::StorageMap { - type Query = U::Query; - type Default = U::Default; - - fn prefix() -> &'static [u8] { - >::prefix() - } - - fn key_for>(key: KeyArg) -> Vec { - >::key_for(key.borrow()) - } - - fn exists>(key: KeyArg) -> bool { - U::exists(key.borrow(), &RuntimeStorage) - } - - fn get>(key: KeyArg) -> Self::Query { - U::get(key.borrow(), &RuntimeStorage) - } - - fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2) { - U::swap(key1.borrow(), key2.borrow(), &mut RuntimeStorage) - } - - fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg) { - U::insert(key.borrow(), val.borrow(), &mut RuntimeStorage) - } - - fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) where V: AsRef { - U::insert_ref(key.borrow(), val, &mut RuntimeStorage) - } - - fn remove>(key: KeyArg) { - U::remove(key.borrow(), &mut RuntimeStorage) - } - - fn mutate, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R { - U::mutate(key.borrow(), f, &mut RuntimeStorage) - } - - fn take>(key: KeyArg) -> Self::Query { - U::take(key.borrow(), &mut RuntimeStorage) - } -} - -/// A storage map with values that can be appended to. -pub trait AppendableStorageMap: StorageMap { - /// Append the given item to the value in the storage. - /// - /// `T` is required to implement `codec::EncodeAppend`. - fn append<'a, KeyArg, I, R>( - key: KeyArg, - items: R, - ) -> Result<(), &'static str> where - KeyArg: Borrow, - I: 'a + codec::Encode, - V: EncodeAppend, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator; /// Append the given items to the value in the storage. /// - /// `T` is required to implement `codec::EncodeAppend`. - /// - /// Upon any failure, it replaces `items` as the new value (assuming that the previous stored - /// data is simply corrupt and no longer usable). - /// - /// WARNING: use with care; if your use-case is not _exactly_ as what this function is doing, - /// you should use append and sensibly handle failure within the runtime code if it happens. - fn append_or_insert<'a, KeyArg, I, R>( - key: KeyArg, - items: R, - ) where - KeyArg: Borrow, - I: 'a + codec::Encode + Clone, - V: codec::EncodeAppend + FromIterator, - R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator; -} - -impl AppendableStorageMap for U - where U: hashed::generator::AppendableStorageMap -{ - fn append<'a, KeyArg, I, R>( - key: KeyArg, - items: R, - ) -> Result<(), &'static str> where + /// `V` is required to implement `codec::EncodeAppend`. + fn append<'a, I, R, KeyArg>(key: KeyArg, items: R) -> Result<(), &'static str> + where KeyArg: Borrow, I: 'a + codec::Encode, - V: EncodeAppend, + V: codec::EncodeAppend, R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - U::append(key.borrow(), items, &mut RuntimeStorage) - } + R::IntoIter: ExactSizeIterator; - fn append_or_insert<'a, KeyArg, I, R>( - key: KeyArg, - items: R, - ) where + /// Safely append the given items to the value in the storage. If a codec error occurs, then the + /// old (presumably corrupt) value is replaced with the given `items`. + /// + /// `T` is required to implement `codec::EncodeAppend`. + fn append_or_insert<'a, I, R, KeyArg>(key: KeyArg, items: R) + where KeyArg: Borrow, I: 'a + codec::Encode + Clone, - V: codec::EncodeAppend + FromIterator, + V: codec::EncodeAppend + crate::rstd::iter::FromIterator, R: IntoIterator + Clone, - R::IntoIter: ExactSizeIterator, - { - U::append_or_insert(key.borrow(), items, &mut RuntimeStorage) - } -} + R::IntoIter: ExactSizeIterator; -/// A storage map with a decodable length. -pub trait DecodeLengthStorageMap: StorageMap { /// Read the length of the value in a fast way, without decoding the entire value. /// /// `T` is required to implement `Codec::DecodeLength`. /// - /// Has the same logic as [`StorageValue`](trait.StorageValue.html). + /// Note that `0` is returned as the default value if no encoded value exists at the given key. + /// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()` + /// function for this purpose. fn decode_len>(key: KeyArg) -> Result - where V: codec::DecodeLength, V: Len; + where V: codec::DecodeLength + Len; } -impl DecodeLengthStorageMap for U - where U: hashed::generator::DecodeLengthStorageMap -{ - fn decode_len>(key: KeyArg) -> Result - where V: codec::DecodeLength, V: Len - { - U::decode_len(key.borrow(), &mut RuntimeStorage) - } -} - -/// A storage map that can be enumerated. +/// A strongly-typed linked map in storage. /// -/// Primarily useful for off-chain computations. -/// Runtime implementors should avoid enumerating storage entries on-chain. -pub trait EnumerableStorageMap: StorageMap { +/// Similar to `StorageMap` but allows to enumerate other elements and doesn't implement append. +pub trait StorageLinkedMap { + /// The type that get/take return. + type Query; + + /// The type that iterates over all `(key, value)`. + type Enumerator: Iterator; + + /// Does the value (explicitly) exist in storage? + fn exists>(key: KeyArg) -> bool; + + /// Load the value associated with the given key from the map. + fn get>(key: KeyArg) -> Self::Query; + + /// Swap the values of two keys. + fn swap, KeyArg2: Borrow>(key1: KeyArg1, key2: KeyArg2); + + /// Store a value to be associated with the given key from the map. + fn insert, ValArg: Borrow>(key: KeyArg, val: ValArg); + + /// Store a value under this key into the provided storage instance; this can take any reference + /// type that derefs to `T` (and has `Encode` implemented). + fn insert_ref, ValArg: ?Sized + Encode>(key: KeyArg, val: &ValArg) where V: AsRef; + + /// Remove the value under a key. + fn remove>(key: KeyArg); + + /// Mutate the value under a key. + fn mutate, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R; + + /// Take the value under a key. + fn take>(key: KeyArg) -> Self::Query; + /// Return current head element. fn head() -> Option; /// Enumerate all elements in the map. - fn enumerate() -> Box> where K: 'static, V: 'static; -} + fn enumerate() -> Self::Enumerator; -impl EnumerableStorageMap for U - where U: hashed::generator::EnumerableStorageMap -{ - fn head() -> Option { - >::head(&RuntimeStorage) - } - - fn enumerate() -> Box> where K: 'static, V: 'static { - >::enumerate(&RuntimeStorage) - } + /// Read the length of the value in a fast way, without decoding the entire value. + /// + /// `T` is required to implement `Codec::DecodeLength`. + /// + /// Note that `0` is returned as the default value if no encoded value exists at the given key. + /// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()` + /// function for this purpose. + fn decode_len>(key: KeyArg) -> Result + where V: codec::DecodeLength + Len; } /// An implementation of a map with a two keys. /// /// It provides an important ability to efficiently remove all entries /// that have a common first key. -/// -/// # Mapping of keys to a storage path -/// -/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. -/// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part -/// is a hash of a `Key2`. -/// -/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. pub trait StorageDoubleMap { /// The type that get/take returns. type Query; - fn prefix() -> &'static [u8]; - - fn key_for(k1: &KArg1, k2: &KArg2) -> Vec - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode; - - fn prefix_for(k1: &KArg1) -> Vec where KArg1: ?Sized + Encode, K1: Borrow; - fn exists(k1: &KArg1, k2: &KArg2) -> bool where K1: Borrow, @@ -501,204 +278,3 @@ pub trait StorageDoubleMap { I: codec::Encode, V: EncodeAppend; } - -impl StorageDoubleMap for U -where - U: unhashed::generator::StorageDoubleMap -{ - type Query = U::Query; - - fn prefix() -> &'static [u8] { - >::prefix() - } - - fn key_for(k1: &KArg1, k2: &KArg2) -> Vec - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - { - >::key_for(k1, k2) - } - - fn prefix_for(k1: &KArg1) -> Vec where KArg1: ?Sized + Encode, K1: Borrow { - >::prefix_for(k1) - } - - fn exists(k1: &KArg1, k2: &KArg2) -> bool - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - { - U::exists(k1, k2, &RuntimeStorage) - } - - fn get(k1: &KArg1, k2: &KArg2) -> Self::Query - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - { - U::get(k1, k2, &RuntimeStorage) - } - - fn take(k1: &KArg1, k2: &KArg2) -> Self::Query - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - { - U::take(k1.borrow(), k2.borrow(), &mut RuntimeStorage) - } - - fn insert(k1: &KArg1, k2: &KArg2, val: &VArg) - where - K1: Borrow, - K2: Borrow, - V: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - VArg: ?Sized + Encode, - { - U::insert(k1, k2, val, &mut RuntimeStorage) - } - - fn remove(k1: &KArg1, k2: &KArg2) - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - { - U::remove(k1, k2, &mut RuntimeStorage) - } - - fn remove_prefix(k1: &KArg1) where KArg1: ?Sized + Encode, K1: Borrow { - U::remove_prefix(k1, &mut RuntimeStorage) - } - - fn mutate(k1: &KArg1, k2: &KArg2, f: F) -> R - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - F: FnOnce(&mut Self::Query) -> R - { - U::mutate(k1, k2, f, &mut RuntimeStorage) - } - - fn append( - k1: &KArg1, - k2: &KArg2, - items: &[I], - ) -> Result<(), &'static str> - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - I: codec::Encode, - V: EncodeAppend, - { - U::append(k1, k2, items, &mut RuntimeStorage) - } -} - -/// child storage NOTE could replace unhashed by having only one kind of storage (root being null storage -/// key (storage_key can become Option<&[u8]>). -/// This module is a currently only a variant of unhashed with additional `storage_key`. -/// Note that `storage_key` must be unique and strong (strong in the sense of being long enough to -/// avoid collision from a resistant hash function (which unique implies)). -pub mod child { - use super::{Codec, Decode, Vec}; - - /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. - pub fn get(storage_key: &[u8], key: &[u8]) -> Option { - runtime_io::child_storage(storage_key, key).map(|v| { - Decode::decode(&mut &v[..]).expect("storage is not null, therefore must be a valid type") - }) - } - - /// Return the value of the item in storage under `key`, or the type's default if there is no - /// explicit entry. - pub fn get_or_default(storage_key: &[u8], key: &[u8]) -> T { - get(storage_key, key).unwrap_or_else(Default::default) - } - - /// Return the value of the item in storage under `key`, or `default_value` if there is no - /// explicit entry. - pub fn get_or(storage_key: &[u8], key: &[u8], default_value: T) -> T { - get(storage_key, key).unwrap_or(default_value) - } - - /// Return the value of the item in storage under `key`, or `default_value()` if there is no - /// explicit entry. - pub fn get_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { - get(storage_key, key).unwrap_or_else(default_value) - } - - /// Put `value` in storage under `key`. - pub fn put(storage_key: &[u8], key: &[u8], value: &T) { - value.using_encoded(|slice| runtime_io::set_child_storage(storage_key, key, slice)); - } - - /// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise. - pub fn take(storage_key: &[u8], key: &[u8]) -> Option { - let r = get(storage_key, key); - if r.is_some() { - kill(storage_key, key); - } - r - } - - /// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage, - /// the default for its type. - pub fn take_or_default(storage_key: &[u8], key: &[u8]) -> T { - take(storage_key, key).unwrap_or_else(Default::default) - } - - /// Return the value of the item in storage under `key`, or `default_value` if there is no - /// explicit entry. Ensure there is no explicit entry on return. - pub fn take_or(storage_key: &[u8],key: &[u8], default_value: T) -> T { - take(storage_key, key).unwrap_or(default_value) - } - - /// Return the value of the item in storage under `key`, or `default_value()` if there is no - /// explicit entry. Ensure there is no explicit entry on return. - pub fn take_or_else T>(storage_key: &[u8], key: &[u8], default_value: F) -> T { - take(storage_key, key).unwrap_or_else(default_value) - } - - /// Check to see if `key` has an explicit entry in storage. - pub fn exists(storage_key: &[u8], key: &[u8]) -> bool { - runtime_io::read_child_storage(storage_key, key, &mut [0;0][..], 0).is_some() - } - - /// Remove all `storage_key` key/values - pub fn kill_storage(storage_key: &[u8]) { - runtime_io::kill_child_storage(storage_key) - } - - /// Ensure `key` has no explicit entry in storage. - pub fn kill(storage_key: &[u8], key: &[u8]) { - runtime_io::clear_child_storage(storage_key, key); - } - - /// Get a Vec of bytes from storage. - pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option> { - runtime_io::child_storage(storage_key, key) - } - - /// Put a raw byte slice into storage. - pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) { - runtime_io::set_child_storage(storage_key, key, value) - } - - pub use super::unhashed::StorageVec; -} diff --git a/substrate/srml/support/src/storage/storage_items.rs b/substrate/srml/support/src/storage/storage_items.rs index a2a5c3229f..ac120c31e7 100644 --- a/substrate/srml/support/src/storage/storage_items.rs +++ b/substrate/srml/support/src/storage/storage_items.rs @@ -50,109 +50,127 @@ pub use crate::rstd::marker::PhantomData; #[doc(hidden)] pub use crate::rstd::boxed::Box; +#[doc(hidden)] +pub fn id(t: T) -> T { + t +} + +#[doc(hidden)] +pub use Some; + +#[doc(hidden)] +pub fn unwrap_or_default(t: Option) -> T { + t.unwrap_or_else(|| Default::default()) +} + +#[doc(hidden)] +pub fn require(t: Option) -> T { + t.expect("Required values must be in storage") +} + // FIXME #1466 Remove this in favor of `decl_storage` macro. /// Declares strongly-typed wrappers around codec-compatible types in storage. #[macro_export] macro_rules! storage_items { // simple values ($name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); + $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); + $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); + $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); + $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); + $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); + $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); + $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty); + $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); + $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty); + $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $key => $ty); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); + $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty); + $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $key => $ty); storage_items!($($t)*); }; // maps ($name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() () (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (id) (id) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (unwrap_or_default) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; ($name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; (pub $name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => { - $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]); + $crate::__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (Some) $name: $prefix => map [$kty => $ty]); storage_items!($($t)*); }; @@ -163,110 +181,53 @@ macro_rules! storage_items { #[doc(hidden)] macro_rules! __storage_items_internal { // generator for values. - (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { - $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $key => $ty } - pub fn $get_fn() -> $gettype { <$name as $crate::storage::hashed::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) } + (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $key:expr => $ty:ty) => { + $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($into_query) ($into_opt_val) $name : $key => $ty } + pub fn $get_fn() -> $gettype { <$name as $crate::storage::StorageValue<$ty>> :: get() } }; - (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { + (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $key:expr => $ty:ty) => { $($vis)* struct $name; - impl $crate::storage::hashed::generator::StorageValue<$ty> for $name { + impl $crate::storage::generator::StorageValue<$ty> for $name { type Query = $gettype; - type Default = (); - /// Get the storage key. - fn key() -> &'static [u8] { + fn unhashed_key() -> &'static [u8] { $key } - /// Load the value from the provided storage instance. - fn get>(storage: &S) -> Self::Query { - storage.$getter($key) + fn from_optional_value_to_query(v: Option<$ty>) -> Self::Query { + $crate::storage::storage_items::$into_query(v) } - /// Take a value from storage, removing it afterwards. - fn take>(storage: &mut S) -> Self::Query { - storage.$taker($key) - } - - /// Mutate this value. - fn mutate R, S: $crate::HashedStorage<$crate::Twox128>>(f: F, storage: &mut S) -> R { - let mut val = >::get(storage); - - let ret = f(&mut val); - - $crate::__handle_wrap_internal!($wraptype { - // raw type case - >::put(&val, storage) - } { - // Option<> type case - match val { - Some(ref val) => >::put(&val, storage), - None => >::kill(storage), - } - }); - - ret + fn from_query_to_optional_value(v: Self::Query) -> Option<$ty> { + $crate::storage::storage_items::$into_opt_val(v) } } }; // generator for maps. - (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { - $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] } - pub fn $get_fn>(key: K) -> $gettype { - <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) + (($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($into_query) ($into_opt_val) $name : $prefix => map [$kty => $ty] } + pub fn $get_fn>(key: K) -> $gettype { + <$name as $crate::storage::StorageMap<$kty, $ty>> :: get(key.borrow()) } }; - (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($into_query:ident) ($into_opt_val:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { $($vis)* struct $name; - impl $crate::storage::hashed::generator::StorageMap<$kty, $ty> for $name { + impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { type Query = $gettype; type Hasher = $crate::Blake2_256; - type Default = (); - /// Get the prefix key in storage. fn prefix() -> &'static [u8] { $prefix } - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &$kty) -> $crate::rstd::vec::Vec { - let mut key = $prefix.to_vec(); - $crate::codec::Encode::encode_to(x, &mut key); - key + fn from_optional_value_to_query(v: Option<$ty>) -> Self::Query { + $crate::storage::storage_items::$into_query(v) } - /// Load the value associated with the given key from the map. - fn get>(key: &$kty, storage: &S) -> Self::Query { - let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key); - storage.$getter(&key[..]) - } - - /// Take the value, reading and removing it. - fn take>(key: &$kty, storage: &mut S) -> Self::Query { - let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key); - storage.$taker(&key[..]) - } - - /// Mutate the value under a key. - fn mutate R, S: $crate::HashedStorage>(key: &$kty, f: F, storage: &mut S) -> R { - let mut val = >::take(key, storage); - - let ret = f(&mut val); - - $crate::__handle_wrap_internal!($wraptype { - // raw type case - >::insert(key, &val, storage) - } { - // Option<> type case - match val { - Some(ref val) => >::insert(key, &val, storage), - None => >::remove(key, storage), - } - }); - - ret + fn from_query_to_optional_value(v: Self::Query) -> Option<$ty> { + $crate::storage::storage_items::$into_opt_val(v) } } }; @@ -292,12 +253,10 @@ macro_rules! __handle_wrap_internal { // Do not complain about unused `dispatch` and `dispatch_aux`. #[allow(dead_code)] mod tests { - use std::collections::HashMap; - use super::*; use crate::metadata::*; use crate::metadata::StorageHasher; use crate::rstd::marker::PhantomData; - use crate::storage::hashed::generator::*; + use crate::storage::{StorageValue, StorageMap}; storage_items! { Value: b"a" => u32; @@ -306,23 +265,25 @@ mod tests { #[test] fn value() { - let mut storage = HashMap::new(); - assert!(Value::get(&storage).is_none()); - Value::put(&100_000, &mut storage); - assert_eq!(Value::get(&storage), Some(100_000)); - Value::kill(&mut storage); - assert!(Value::get(&storage).is_none()); + runtime_io::with_storage(&mut Default::default(), || { + assert!(Value::get().is_none()); + Value::put(&100_000); + assert_eq!(Value::get(), Some(100_000)); + Value::kill(); + assert!(Value::get().is_none()); + }) } #[test] fn map() { - let mut storage = HashMap::new(); - assert!(Map::get(&5, &storage).is_none()); - Map::insert(&5, &[1; 32], &mut storage); - assert_eq!(Map::get(&5, &storage), Some([1; 32])); - assert_eq!(Map::take(&5, &mut storage), Some([1; 32])); - assert!(Map::get(&5, &storage).is_none()); - assert!(Map::get(&999, &storage).is_none()); + runtime_io::with_storage(&mut Default::default(), || { + assert!(Map::get(&5).is_none()); + Map::insert(&5, &[1; 32]); + assert_eq!(Map::get(&5), Some([1; 32])); + assert_eq!(Map::take(&5), Some([1; 32])); + assert!(Map::get(&5).is_none()); + assert!(Map::get(&999).is_none()); + }) } pub trait Trait { @@ -380,7 +341,7 @@ mod tests { COMPLEXTYPE3: ([u32;25]); } add_extra_genesis { - build(|_, _| {}); + build(|_| {}); } } @@ -756,7 +717,7 @@ mod test2 { add_extra_genesis { config(_marker) : ::std::marker::PhantomData; config(extra_field) : u32 = 32; - build(|_, _| {}); + build(|_| {}); } } @@ -797,7 +758,7 @@ mod test3 { #[cfg(test)] #[allow(dead_code)] mod test_append_and_len { - use crate::storage::{AppendableStorageMap, DecodeLengthStorageMap, StorageMap, StorageValue}; + use crate::storage::{StorageMap, StorageValue, StorageLinkedMap}; use runtime_io::{with_externalities, TestExternalities}; use codec::{Encode, Decode}; @@ -952,5 +913,3 @@ mod test_append_and_len { }); } } - - diff --git a/substrate/srml/support/src/storage/unhashed/mod.rs b/substrate/srml/support/src/storage/unhashed.rs similarity index 98% rename from substrate/srml/support/src/storage/unhashed/mod.rs rename to substrate/srml/support/src/storage/unhashed.rs index 5d086c36c4..3c6a5074bd 100644 --- a/substrate/srml/support/src/storage/unhashed/mod.rs +++ b/substrate/srml/support/src/storage/unhashed.rs @@ -14,13 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Operation on unhashed runtime storage +//! Operation on unhashed runtime storage. use crate::rstd::borrow::Borrow; use super::{Codec, Encode, Decode, KeyedVec, Vec}; -pub mod generator; - /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. pub fn get(key: &[u8]) -> Option { runtime_io::storage(key).map(|val| { diff --git a/substrate/srml/support/src/storage/unhashed/generator.rs b/substrate/srml/support/src/storage/unhashed/generator.rs deleted file mode 100644 index a5385af8fb..0000000000 --- a/substrate/srml/support/src/storage/unhashed/generator.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright 2019 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -use crate::codec::{self, Encode, EncodeAppend}; -use crate::rstd::{borrow::Borrow, vec::Vec}; - -/// Abstraction around storage with unhashed access. -pub trait UnhashedStorage { - /// true if the key exists in storage. - fn exists(&self, key: &[u8]) -> bool; - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. - fn get(&self, key: &[u8]) -> Option; - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if - /// it's not there. - fn require(&self, key: &[u8]) -> T { - self.get(key).expect("Required values must be in storage") - } - - /// Load the bytes of a key from storage. Can panic if the type is incorrect. The type's - /// default is returned if it's not there. - fn get_or_default(&self, key: &[u8]) -> T { - self.get(key).unwrap_or_default() - } - - /// Put a value in under a key. - fn put(&mut self, key: &[u8], val: &T); - - /// Remove the bytes of a key from storage. - fn kill(&mut self, key: &[u8]); - - /// Remove the bytes of a key from storage. - fn kill_prefix(&mut self, prefix: &[u8]); - - /// Take a value from storage, deleting it after reading. - fn take(&mut self, key: &[u8]) -> Option { - let value = self.get(key); - self.kill(key); - value - } - - /// Take a value from storage, deleting it after reading. - fn take_or_panic(&mut self, key: &[u8]) -> T { - self.take(key).expect("Required values must be in storage") - } - - /// Take a value from storage, deleting it after reading. - fn take_or_default(&mut self, key: &[u8]) -> T { - self.take(key).unwrap_or_default() - } - - /// Get a Vec of bytes from storage. - fn get_raw(&self, key: &[u8]) -> Option>; - - /// Put a raw byte slice into storage. - fn put_raw(&mut self, key: &[u8], value: &[u8]); -} - -// We use a construct like this during when genesis storage is being built. -#[cfg(feature = "std")] -impl UnhashedStorage for sr_primitives::StorageOverlay { - fn exists(&self, key: &[u8]) -> bool { - self.contains_key(key) - } - - fn get(&self, key: &[u8]) -> Option { - self.get(key) - .map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type.")) - } - - fn put(&mut self, key: &[u8], val: &T) { - self.insert(key.to_vec(), codec::Encode::encode(val)); - } - - fn kill(&mut self, key: &[u8]) { - self.remove(key); - } - - fn kill_prefix(&mut self, prefix: &[u8]) { - self.retain(|key, _| { - !key.starts_with(prefix) - }) - } - - fn get_raw(&self, key: &[u8]) -> Option> { - self.get(key).cloned() - } - - fn put_raw(&mut self, key: &[u8], value: &[u8]) { - self.insert(key.to_vec(), value.to_vec()); - } -} - -/// An implementation of a map with a two keys. -/// -/// It provides an important ability to efficiently remove all entries -/// that have a common first key. -/// -/// # Mapping of keys to a storage path -/// -/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts. -/// The first part is a hash of a concatenation of the `PREFIX` and `Key1`. And the second part -/// is a hash of a `Key2`. -/// -/// /!\ be careful while choosing the Hash, indeed malicious could craft second keys to lower the trie. -pub trait StorageDoubleMap { - /// The type that get/take returns. - type Query; - - /// Get the prefix key in storage. - fn prefix() -> &'static [u8]; - - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for( - k1: &KArg1, - k2: &KArg2, - ) -> Vec where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode; - - /// Get the storage prefix used to fetch keys corresponding to a specific key1. - fn prefix_for(k1: &KArg1) -> Vec where KArg1: ?Sized + Encode, K1: Borrow; - - /// true if the value is defined in storage. - fn exists( - k1: &KArg1, - k2: &KArg2, - storage: &S, - ) -> bool where K1: Borrow, K2: Borrow, KArg1: ?Sized + Encode, KArg2: ?Sized + Encode { - storage.exists(&Self::key_for(k1, k2)) - } - - /// Load the value associated with the given key from the map. - fn get( - k1: &KArg1, - k2: &KArg2, - storage: &S, - ) -> Self::Query where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode; - - /// Take the value under a key. - fn take( - k1: &KArg1, - k2: &KArg2, - storage: &mut S, - ) -> Self::Query where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode; - - /// Store a value to be associated with the given key from the map. - fn insert( - k1: &KArg1, - k2: &KArg2, - val: &VArg, - storage: &mut S, - ) where - K1: Borrow, - K2: Borrow, - V: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - VArg: ?Sized + Encode, - { - storage.put(&Self::key_for(k1, k2), val); - } - - /// Remove the value under a key. - fn remove( - k1: &KArg1, - k2: &KArg2, - storage: &mut S, - ) where K1: Borrow, K2: Borrow, KArg1: ?Sized + Encode, KArg2: ?Sized + Encode { - storage.kill(&Self::key_for(k1, k2)); - } - - /// Removes all entries that shares the `k1` as the first key. - fn remove_prefix( - k1: &KArg1, - storage: &mut S, - ) where KArg1: ?Sized + Encode, K1: Borrow { - storage.kill_prefix(&Self::prefix_for(k1)); - } - - /// Mutate the value under a key. - fn mutate( - k1: &KArg1, - k2: &KArg2, - f: F, - storage: &mut S, - ) -> R where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - F: FnOnce(&mut Self::Query) -> R; - - /// Append the given items to the value under the key specified. - fn append( - k1: &KArg1, - k2: &KArg2, - items: &[I], - storage: &mut S, - ) -> Result<(), &'static str> - where - K1: Borrow, - K2: Borrow, - KArg1: ?Sized + Encode, - KArg2: ?Sized + Encode, - I: codec::Encode, - V: EncodeAppend, - { - let key = Self::key_for(k1, k2); - let new_val = ::append( - storage.get_raw(&key).unwrap_or_default(), - items, - ).map_err(|_| "Could not append given item")?; - storage.put_raw(&key, &new_val); - Ok(()) - } -} diff --git a/substrate/srml/support/src/traits.rs b/substrate/srml/support/src/traits.rs index a5e52f5f66..355f05992f 100644 --- a/substrate/srml/support/src/traits.rs +++ b/substrate/srml/support/src/traits.rs @@ -26,16 +26,6 @@ use crate::sr_primitives::ConsensusEngineId; use super::for_each_tuple; -/// A trait that can return the default value of a storage item. This must only ever be implemented -/// for a special delegator struct for each storage item -pub trait StorageDefault: Sized { - /// Return the default value of type `V`. `None`, if `V` does not have a proper default value. - fn default() -> Option; -} - -// FIXME #1466 This is needed for `storage_items!`. Should be removed once it is deprecated. -impl StorageDefault for () { fn default() -> Option { Some(Default::default()) } } - /// Anything that can have a `::len()` method. pub trait Len { /// Return the length of data type. diff --git a/substrate/srml/support/test/tests/final_keys.rs b/substrate/srml/support/test/tests/final_keys.rs index 9c770075c4..af8e01cc5f 100644 --- a/substrate/srml/support/test/tests/final_keys.rs +++ b/substrate/srml/support/test/tests/final_keys.rs @@ -15,7 +15,7 @@ // along with Substrate. If not, see . use runtime_io::{with_externalities, Blake2Hasher}; -use srml_support::{StorageValue, StorageMap, StorageDoubleMap}; +use srml_support::{StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap}; use srml_support::storage::unhashed; use codec::{Encode, Decode}; diff --git a/substrate/srml/support/test/tests/instance.rs b/substrate/srml/support/test/tests/instance.rs index e9c660eea3..48af8926dd 100644 --- a/substrate/srml/support/test/tests/instance.rs +++ b/substrate/srml/support/test/tests/instance.rs @@ -23,11 +23,11 @@ use srml_support::{ DecodeDifferent, StorageMetadata, StorageEntryModifier, StorageEntryType, DefaultByteGetter, StorageEntryMetadata, StorageHasher }, + StorageValue, StorageMap, StorageLinkedMap, StorageDoubleMap, }; use inherents::{ ProvideInherent, InherentData, InherentIdentifier, RuntimeString, MakeFatalError }; -use srml_support::{StorageValue, StorageMap, StorageDoubleMap, EnumerableStorageMap}; use primitives::{H256, sr25519}; mod system; @@ -75,7 +75,7 @@ mod module1 { add_extra_genesis { config(test) : T::BlockNumber; - build(|_, config: &Self| { + build(|config: &Self| { println!("{}", config.test); }); } @@ -304,53 +304,27 @@ fn new_test_ext() -> runtime_io::TestExternalities { #[test] fn storage_instance_independance() { - with_externalities(&mut new_test_ext(), || { - let mut map = std::collections::btree_map::BTreeMap::new(); - for key in [ - module2::Value::::key().to_vec(), - module2::Value::::key().to_vec(), - module2::Value::::key().to_vec(), - module2::Value::::key().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::Map::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::LinkedMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::DoubleMap::::prefix().to_vec(), - module2::Map::::key_for(0), - module2::Map::::key_for(0).to_vec(), - module2::Map::::key_for(0).to_vec(), - module2::Map::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0), - module2::LinkedMap::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0).to_vec(), - module2::LinkedMap::::key_for(0).to_vec(), - module2::Map::::key_for(1), - module2::Map::::key_for(1).to_vec(), - module2::Map::::key_for(1).to_vec(), - module2::Map::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1), - module2::LinkedMap::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1).to_vec(), - module2::LinkedMap::::key_for(1).to_vec(), - module2::DoubleMap::::prefix_for(&1), - module2::DoubleMap::::prefix_for(&1).to_vec(), - module2::DoubleMap::::prefix_for(&1).to_vec(), - module2::DoubleMap::::prefix_for(&1).to_vec(), - module2::DoubleMap::::key_for(&1, &1), - module2::DoubleMap::::key_for(&1, &1).to_vec(), - module2::DoubleMap::::key_for(&1, &1).to_vec(), - module2::DoubleMap::::key_for(&1, &1).to_vec(), - ].iter() { - assert!(map.insert(key, ()).is_none()) - } + let mut storage = (std::collections::HashMap::new(), std::collections::HashMap::new()); + runtime_io::with_storage(&mut storage, || { + module2::Value::::put(0); + module2::Value::::put(0); + module2::Value::::put(0); + module2::Value::::put(0); + module2::Map::::insert(0, 0); + module2::Map::::insert(0, 0); + module2::Map::::insert(0, 0); + module2::Map::::insert(0, 0); + module2::LinkedMap::::insert(0, vec![]); + module2::LinkedMap::::insert(0, vec![]); + module2::LinkedMap::::insert(0, vec![]); + module2::LinkedMap::::insert(0, vec![]); + module2::DoubleMap::::insert(&0, &0, &0); + module2::DoubleMap::::insert(&0, &0, &0); + module2::DoubleMap::::insert(&0, &0, &0); + module2::DoubleMap::::insert(&0, &0, &0); }); + // 16 storage values + 4 linked_map head. + assert_eq!(storage.0.len(), 16 + 4); } #[test] diff --git a/substrate/srml/system/src/lib.rs b/substrate/srml/system/src/lib.rs index 91959f43e4..3fa4733ba0 100644 --- a/substrate/srml/system/src/lib.rs +++ b/substrate/srml/system/src/lib.rs @@ -116,7 +116,7 @@ use safe_mix::TripletMix; use codec::{Encode, Decode}; #[cfg(any(feature = "std", test))] -use runtime_io::{twox_128, TestExternalities, Blake2Hasher}; +use runtime_io::{TestExternalities, Blake2Hasher}; #[cfg(any(feature = "std", test))] use primitives::ChangesTrieConfiguration; @@ -425,19 +425,17 @@ decl_storage! { #[serde(with = "primitives::bytes")] config(code): Vec; - build( - |storage: &mut (sr_primitives::StorageOverlay, sr_primitives::ChildrenStorageOverlay), - config: &GenesisConfig| - { + build(|config: &GenesisConfig| { use codec::Encode; - storage.0.insert(well_known_keys::CODE.to_vec(), config.code.clone()); - storage.0.insert(well_known_keys::EXTRINSIC_INDEX.to_vec(), 0u32.encode()); + runtime_io::set_storage(well_known_keys::CODE, &config.code); + runtime_io::set_storage(well_known_keys::EXTRINSIC_INDEX, &0u32.encode()); if let Some(ref changes_trie_config) = config.changes_trie_config { - storage.0.insert( - well_known_keys::CHANGES_TRIE_CONFIG.to_vec(), - changes_trie_config.encode()); + runtime_io::set_storage( + well_known_keys::CHANGES_TRIE_CONFIG, + &changes_trie_config.encode(), + ); } }); } @@ -703,9 +701,9 @@ impl Module { #[cfg(any(feature = "std", test))] pub fn externalities() -> TestExternalities { TestExternalities::new((map![ - twox_128(&>::key_for(T::BlockNumber::zero())).to_vec() => [69u8; 32].encode(), - twox_128(>::key()).to_vec() => T::BlockNumber::one().encode(), - twox_128(>::key()).to_vec() => [69u8; 32].encode() + >::hashed_key_for(T::BlockNumber::zero()) => [69u8; 32].encode(), + >::hashed_key().to_vec() => T::BlockNumber::one().encode(), + >::hashed_key().to_vec() => [69u8; 32].encode() ], map![])) }