Forward port blake2 storage support (#2360)

* move storage maps to blake2_128 (#2268)

* remove default hash, introduce twox_128 and blake2

* use blake2_128 & create ext_blake2_128

* refactor code

* add benchmark

* factorize generator

* fix

* parameterizable hasher

* some fix

* fix

* fix

* fix

* metadata

* fix

* remove debug print

* map -> blake2_256

* fix test

* fix test

* Apply suggestions from code review

Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>

* impl twox 128 concat (#2353)

* impl twox_128_concat

* comment addressed

* fix

* impl twox_128->64_concat

* fix test

* Fix compilation and cleanup some docs

* Apply suggestions from code review

Co-Authored-By: bkchr <bkchr@users.noreply.github.com>
This commit is contained in:
Bastian Köcher
2019-04-24 11:05:22 +02:00
committed by Gavin Wood
parent 21d1ee4e99
commit f0862606b7
38 changed files with 1101 additions and 732 deletions
+7 -7
View File
@@ -1536,7 +1536,7 @@ impl<B, E, Block, RA> backend::AuxStore for Client<B, E, Block, RA>
pub(crate) mod tests { pub(crate) mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use super::*; use super::*;
use primitives::twox_128; use primitives::blake2_256;
use runtime_primitives::traits::DigestItem as DigestItemT; use runtime_primitives::traits::DigestItem as DigestItemT;
use runtime_primitives::generic::DigestItem; use runtime_primitives::generic::DigestItem;
use test_client::{self, TestClient, AccountKeyring}; use test_client::{self, TestClient, AccountKeyring};
@@ -1586,12 +1586,12 @@ pub(crate) mod tests {
} }
// prepare test cases // prepare test cases
let alice = twox_128(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec(); let alice = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into())).to_vec();
let bob = twox_128(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec(); let bob = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Bob.into())).to_vec();
let charlie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec(); let charlie = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Charlie.into())).to_vec();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let eve = twox_128(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec(); let eve = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Eve.into())).to_vec();
let ferdie = twox_128(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec(); let ferdie = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Ferdie.into())).to_vec();
let test_cases = vec![ let test_cases = vec![
(1, 4, alice.clone(), vec![(4, 0), (1, 0)]), (1, 4, alice.clone(), vec![(4, 0), (1, 0)]),
(1, 3, alice.clone(), vec![(1, 0)]), (1, 3, alice.clone(), vec![(1, 0)]),
+3 -3
View File
@@ -404,7 +404,7 @@ pub mod tests {
use crate::light::fetcher::{Fetcher, FetchChecker, LightDataChecker, use crate::light::fetcher::{Fetcher, FetchChecker, LightDataChecker,
RemoteCallRequest, RemoteHeaderRequest}; RemoteCallRequest, RemoteHeaderRequest};
use crate::light::blockchain::tests::{DummyStorage, DummyBlockchain}; use crate::light::blockchain::tests::{DummyStorage, DummyBlockchain};
use primitives::{twox_128, Blake2Hasher}; use primitives::{blake2_256, Blake2Hasher};
use primitives::storage::{StorageKey, well_known_keys}; use primitives::storage::{StorageKey, well_known_keys};
use runtime_primitives::generic::BlockId; use runtime_primitives::generic::BlockId;
use state_machine::Backend; use state_machine::Backend;
@@ -587,7 +587,7 @@ pub mod tests {
// we're testing this test case here: // we're testing this test case here:
// (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]), // (1, 4, dave.clone(), vec![(4, 0), (1, 1), (1, 0)]),
let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); let (remote_client, remote_roots, _) = prepare_client_with_key_changes();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let dave = StorageKey(dave); let dave = StorageKey(dave);
// 'fetch' changes proof from remote node: // 'fetch' changes proof from remote node:
@@ -699,7 +699,7 @@ pub mod tests {
let (remote_client, remote_roots, _) = prepare_client_with_key_changes(); let (remote_client, remote_roots, _) = prepare_client_with_key_changes();
let local_cht_root = cht::compute_root::<Header, Blake2Hasher, _>( let local_cht_root = cht::compute_root::<Header, Blake2Hasher, _>(
4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap(); 4, 0, remote_roots.iter().cloned().map(|ct| Ok(Some(ct)))).unwrap();
let dave = twox_128(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec(); let dave = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Dave.into())).to_vec();
let dave = StorageKey(dave); let dave = StorageKey(dave);
// 'fetch' changes proof from remote node: // 'fetch' changes proof from remote node:
+54 -1
View File
@@ -28,7 +28,7 @@ use wasmi::memory_units::{Pages};
use state_machine::{Externalities, ChildStorageKey}; use state_machine::{Externalities, ChildStorageKey};
use crate::error::{Error, ErrorKind, Result}; use crate::error::{Error, ErrorKind, Result};
use crate::wasm_utils::UserError; use crate::wasm_utils::UserError;
use primitives::{blake2_256, twox_128, twox_256, ed25519, sr25519, Pair}; use primitives::{blake2_128, blake2_256, twox_64, twox_128, twox_256, ed25519, sr25519, Pair};
use primitives::hexdisplay::HexDisplay; use primitives::hexdisplay::HexDisplay;
use primitives::sandbox as sandbox_primitives; use primitives::sandbox as sandbox_primitives;
use primitives::{H256, Blake2Hasher}; use primitives::{H256, Blake2Hasher};
@@ -448,6 +448,30 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
ext_chain_id() -> u64 => { ext_chain_id() -> u64 => {
Ok(this.ext.chain_id()) Ok(this.ext.chain_id())
}, },
ext_twox_64(data: *const u8, len: u32, out: *mut u8) => {
let result: [u8; 8] = if len == 0 {
let hashed = twox_64(&[0u8; 0]);
debug_trace!(target: "xxhash", "XXhash: '' -> {}", HexDisplay::from(&hashed));
this.hash_lookup.insert(hashed.to_vec(), vec![]);
hashed
} else {
let key = this.memory.get(data, len as usize).map_err(|_| UserError("Invalid attempt to get key in ext_twox_64"))?;
let hashed_key = twox_64(&key);
debug_trace!(target: "xxhash", "XXhash: {} -> {}",
if let Ok(_skey) = ::std::str::from_utf8(&key) {
_skey
} else {
&format!("{}", HexDisplay::from(&key))
},
HexDisplay::from(&hashed_key)
);
this.hash_lookup.insert(hashed_key.to_vec(), key);
hashed_key
};
this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_twox_64"))?;
Ok(())
},
ext_twox_128(data: *const u8, len: u32, out: *mut u8) => { ext_twox_128(data: *const u8, len: u32, out: *mut u8) => {
let result: [u8; 16] = if len == 0 { let result: [u8; 16] = if len == 0 {
let hashed = twox_128(&[0u8; 0]); let hashed = twox_128(&[0u8; 0]);
@@ -481,6 +505,21 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_twox_256"))?; this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_twox_256"))?;
Ok(()) Ok(())
}, },
ext_blake2_128(data: *const u8, len: u32, out: *mut u8) => {
let result: [u8; 16] = if len == 0 {
let hashed = blake2_128(&[0u8; 0]);
this.hash_lookup.insert(hashed.to_vec(), vec![]);
hashed
} else {
let key = this.memory.get(data, len as usize).map_err(|_| UserError("Invalid attempt to get key in ext_blake2_128"))?;
let hashed_key = blake2_128(&key);
this.hash_lookup.insert(hashed_key.to_vec(), key);
hashed_key
};
this.memory.set(out, &result).map_err(|_| UserError("Invalid attempt to set result in ext_blake2_128"))?;
Ok(())
},
ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => { ext_blake2_256(data: *const u8, len: u32, out: *mut u8) => {
let result: [u8; 32] = if len == 0 { let result: [u8; 32] = if len == 0 {
blake2_256(&[0u8; 0]) blake2_256(&[0u8; 0])
@@ -940,6 +979,20 @@ mod tests {
); );
} }
#[test]
fn blake2_128_should_work() {
let mut ext = TestExternalities::default();
let test_code = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm");
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_128", &[]).unwrap(),
blake2_128(&b""[..]).encode()
);
assert_eq!(
WasmExecutor::new().call(&mut ext, 8, &test_code[..], "test_blake2_128", b"Hello world!").unwrap(),
blake2_128(&b"Hello world!"[..]).encode()
);
}
#[test] #[test]
fn twox_256_should_work() { fn twox_256_should_work() {
let mut ext = TestExternalities::default(); let mut ext = TestExternalities::default();
+2 -1
View File
@@ -7,7 +7,7 @@ use alloc::vec::Vec;
use alloc::slice; use alloc::slice;
use runtime_io::{ use runtime_io::{
set_storage, storage, clear_prefix, print, blake2_256, set_storage, storage, clear_prefix, print, blake2_128, blake2_256,
twox_128, twox_256, ed25519_verify, sr25519_verify, enumerated_trie_root twox_128, twox_256, ed25519_verify, sr25519_verify, enumerated_trie_root
}; };
@@ -68,6 +68,7 @@ impl_stubs!(
input.to_vec() input.to_vec()
}, },
test_blake2_256 => |input| blake2_256(input).to_vec(), test_blake2_256 => |input| blake2_256(input).to_vec(),
test_blake2_128 => |input| blake2_128(input).to_vec(),
test_twox_256 => |input| twox_256(input).to_vec(), test_twox_256 => |input| twox_256(input).to_vec(),
test_twox_128 => |input| twox_128(input).to_vec(), test_twox_128 => |input| twox_128(input).to_vec(),
test_ed25519_verify => |input: &[u8]| { test_ed25519_verify => |input: &[u8]| {
+4 -2
View File
@@ -31,8 +31,10 @@ regex = {version = "1.1", optional = true }
[dev-dependencies] [dev-dependencies]
substrate-serializer = { path = "../serializer" } substrate-serializer = { path = "../serializer" }
pretty_assertions = "0.6.1" pretty_assertions = "0.6"
heapsize = "0.4.2" heapsize = "0.4"
hex-literal = "0.1"
rand = "0.6"
[features] [features]
default = ["std"] default = ["std"]
@@ -0,0 +1,60 @@
// Copyright 2019 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// TODO: Move benchmark to criterion #2354
#![feature(test)]
extern crate test;
use hex_literal::{hex, hex_impl};
use substrate_primitives::hashing::{twox_128, blake2_128};
const MAX_KEY_SIZE: u32 = 32;
fn data_set() -> Vec<Vec<u8>> {
use rand::SeedableRng;
use rand::Rng;
let rnd: [u8; 32] = rand::rngs::StdRng::seed_from_u64(12).gen();
let mut rnd = rnd.iter().cycle();
let mut res = Vec::new();
for size in 1..=MAX_KEY_SIZE {
for _ in 0..1_000 {
let value = (0..size)
.map(|_| rnd.next().unwrap().clone())
.collect();
res.push(value);
}
}
res
}
fn bench_hash_128(b: &mut test::Bencher, f: &Fn(&[u8]) -> [u8; 16]) {
let data_set = data_set();
b.iter(|| {
for data in &data_set {
let _a = f(data);
}
});
}
#[bench]
fn bench_blake2_128(b: &mut test::Bencher) {
bench_hash_128(b, &blake2_128);
}
#[bench]
fn bench_twox_128(b: &mut test::Bencher) {
bench_hash_128(b, &twox_128);
}
+17
View File
@@ -55,6 +55,23 @@ pub fn blake2_128(data: &[u8]) -> [u8; 16] {
r r
} }
/// Do a XX 64-bit hash and place result in `dest`.
pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) {
use ::core::hash::Hasher;
let mut h0 = twox_hash::XxHash::with_seed(0);
h0.write(data);
let r0 = h0.finish();
use byteorder::{ByteOrder, LittleEndian};
LittleEndian::write_u64(&mut dest[0..8], r0);
}
/// Do a XX 64-bit hash and return result.
pub fn twox_64(data: &[u8]) -> [u8; 8] {
let mut r: [u8; 8] = [0; 8];
twox_64_into(data, &mut r);
r
}
/// Do a XX 128-bit hash and place result in `dest`. /// Do a XX 128-bit hash and place result in `dest`.
pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) { pub fn twox_128_into(data: &[u8], dest: &mut [u8; 16]) {
use ::core::hash::Hasher; use ::core::hash::Hasher;
+1 -1
View File
@@ -46,7 +46,7 @@ pub use impl_serde::serialize as bytes;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod hashing; pub mod hashing;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use hashing::{blake2_256, twox_128, twox_256}; pub use hashing::{blake2_128, blake2_256, twox_64, twox_128, twox_256};
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod hexdisplay; pub mod hexdisplay;
pub mod crypto; pub mod crypto;
+3 -3
View File
@@ -17,7 +17,7 @@
use super::*; use super::*;
use self::error::{Error, ErrorKind}; use self::error::{Error, ErrorKind};
use sr_io::twox_128; use sr_io::blake2_256;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use consensus::BlockOrigin; use consensus::BlockOrigin;
use test_client::{self, runtime, AccountKeyring, TestClient, BlockBuilderExt}; use test_client::{self, runtime, AccountKeyring, TestClient, BlockBuilderExt};
@@ -88,7 +88,7 @@ fn should_send_initial_storage_changes_and_notifications() {
{ {
let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote)); let api = State::new(Arc::new(test_client::new()), Subscriptions::new(remote));
let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into())); let alice_balance_key = blake2_256(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into()));
api.subscribe_storage(Default::default(), subscriber, Some(vec![ api.subscribe_storage(Default::default(), subscriber, Some(vec![
StorageKey(alice_balance_key.to_vec()), StorageKey(alice_balance_key.to_vec()),
@@ -147,7 +147,7 @@ fn should_query_storage() {
let block2_hash = add_block(1); let block2_hash = add_block(1);
let genesis_hash = client.genesis_hash(); let genesis_hash = client.genesis_hash();
let alice_balance_key = twox_128(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into())); let alice_balance_key = blake2_256(&test_runtime::system::balance_of_key(AccountKeyring::Alice.into()));
let mut expected = vec![ let mut expected = vec![
StorageChangeSet { StorageChangeSet {
+2 -2
View File
@@ -18,8 +18,8 @@
pub use parity_codec as codec; pub use parity_codec as codec;
// re-export hashing functions. // re-export hashing functions.
pub use primitives::{ pub use primitives::{
blake2_256, twox_128, twox_256, ed25519, Blake2Hasher, sr25519, blake2_128, blake2_256, twox_128, twox_256, twox_64, ed25519, Blake2Hasher,
Pair sr25519, Pair
}; };
pub use tiny_keccak::keccak256 as keccak_256; pub use tiny_keccak::keccak256 as keccak_256;
// Switch to this after PoC-3 // Switch to this after PoC-3
+20
View File
@@ -273,7 +273,9 @@ extern_functions! {
/// Hash calculation and verification /// Hash calculation and verification
fn ext_blake2_256_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8); fn ext_blake2_256_enumerated_trie_root(values_data: *const u8, lens_data: *const u32, lens_len: u32, result: *mut u8);
fn ext_blake2_128(data: *const u8, len: u32, out: *mut u8);
fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8); fn ext_blake2_256(data: *const u8, len: u32, out: *mut u8);
fn ext_twox_64(data: *const u8, len: u32, out: *mut u8);
fn ext_twox_128(data: *const u8, len: u32, out: *mut u8); fn ext_twox_128(data: *const u8, len: u32, out: *mut u8);
fn ext_twox_256(data: *const u8, len: u32, out: *mut u8); fn ext_twox_256(data: *const u8, len: u32, out: *mut u8);
fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8); fn ext_keccak_256(data: *const u8, len: u32, out: *mut u8);
@@ -544,6 +546,15 @@ pub fn blake2_256(data: &[u8]) -> [u8; 32] {
result result
} }
/// Conduct a 128-bit Blake2 hash.
pub fn blake2_128(data: &[u8]) -> [u8; 16] {
let mut result: [u8; 16] = Default::default();
unsafe {
ext_blake2_128.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
}
result
}
/// Conduct a 256-bit Keccak hash. /// Conduct a 256-bit Keccak hash.
pub fn keccak_256(data: &[u8]) -> [u8; 32] { pub fn keccak_256(data: &[u8]) -> [u8; 32] {
let mut result: [u8; 32] = Default::default(); let mut result: [u8; 32] = Default::default();
@@ -571,6 +582,15 @@ pub fn twox_128(data: &[u8]) -> [u8; 16] {
result result
} }
/// Conduct two XX hashes to give a 64-bit result.
pub fn twox_64(data: &[u8]) -> [u8; 8] {
let mut result: [u8; 8] = Default::default();
unsafe {
ext_twox_64.get()(data.as_ptr(), data.len() as u32, result.as_mut_ptr());
}
result
}
/// Verify a ed25519 signature. /// Verify a ed25519 signature.
pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool { pub fn ed25519_verify<P: AsRef<[u8]>>(sig: &[u8; 64], msg: &[u8], pubkey: P) -> bool {
unsafe { unsafe {
-8
View File
@@ -88,14 +88,6 @@ pub use serde::{Serialize, Deserialize, de::DeserializeOwned};
/// Complex storage builder stuff. /// Complex storage builder stuff.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub trait BuildStorage: Sized { pub trait BuildStorage: Sized {
/// Hash given slice.
///
/// Default to xx128 hashing.
fn hash(data: &[u8]) -> [u8; 16] {
let r = runtime_io::twox_128(data);
log::trace!(target: "build_storage", "{} <= {}", substrate_primitives::hexdisplay::HexDisplay::from(&r), ascii_format(data));
r
}
/// Build the storage out of this builder. /// Build the storage out of this builder.
fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> { fn build_storage(self) -> Result<(StorageOverlay, ChildrenStorageOverlay), String> {
let mut storage = Default::default(); let mut storage = Default::default();
@@ -17,7 +17,7 @@
//! Tool for creating the genesis block. //! Tool for creating the genesis block.
use std::collections::HashMap; use std::collections::HashMap;
use runtime_io::twox_128; use runtime_io::{blake2_256, twox_128};
use super::AccountId; use super::AccountId;
use parity_codec::{Encode, KeyedVec, Joiner}; use parity_codec::{Encode, KeyedVec, Joiner};
use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys}; use primitives::{ChangesTrieConfiguration, map, storage::well_known_keys};
@@ -47,7 +47,7 @@ impl GenesisConfig {
let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec(); let wasm_runtime = include_bytes!("../wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm").to_vec();
let mut map: HashMap<Vec<u8>, Vec<u8>> = self.balances.iter() let mut map: HashMap<Vec<u8>, Vec<u8>> = self.balances.iter()
.map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance))) .map(|&(ref account, balance)| (account.to_keyed_vec(b"balance:"), vec![].and(&balance)))
.map(|(k, v)| (twox_128(&k[..])[..].to_vec(), v.to_vec())) .map(|(k, v)| (blake2_256(&k[..])[..].to_vec(), v.to_vec()))
.chain(vec![ .chain(vec![
(well_known_keys::CODE.into(), wasm_runtime), (well_known_keys::CODE.into(), wasm_runtime),
(well_known_keys::HEAP_PAGES.into(), vec![].and(&(16 as u64))), (well_known_keys::HEAP_PAGES.into(), vec![].and(&(16 as u64))),
+12 -12
View File
@@ -18,7 +18,7 @@
//! and depositing logs. //! and depositing logs.
use rstd::prelude::*; use rstd::prelude::*;
use runtime_io::{storage_root, enumerated_trie_root, storage_changes_root, twox_128}; use runtime_io::{storage_root, enumerated_trie_root, storage_changes_root, twox_128, blake2_256};
use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_support::storage::{self, StorageValue, StorageMap};
use runtime_support::storage_items; use runtime_support::storage_items;
use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Digest as DigestT}; use runtime_primitives::traits::{Hash as HashT, BlakeTwo256, Digest as DigestT};
@@ -45,11 +45,11 @@ pub fn balance_of_key(who: AccountId) -> Vec<u8> {
} }
pub fn balance_of(who: AccountId) -> u64 { pub fn balance_of(who: AccountId) -> u64 {
storage::get_or(&balance_of_key(who), 0) storage::hashed::get_or(&blake2_256, &balance_of_key(who), 0)
} }
pub fn nonce_of(who: AccountId) -> u64 { pub fn nonce_of(who: AccountId) -> u64 {
storage::get_or(&who.to_keyed_vec(NONCE_OF), 0) storage::hashed::get_or(&blake2_256, &who.to_keyed_vec(NONCE_OF), 0)
} }
/// Get authorities at given block. /// Get authorities at given block.
@@ -152,7 +152,7 @@ pub fn validate_transaction(utx: Extrinsic) -> TransactionValidity {
let tx = utx.transfer(); let tx = utx.transfer();
let nonce_key = tx.from.to_keyed_vec(NONCE_OF); let nonce_key = tx.from.to_keyed_vec(NONCE_OF);
let expected_nonce: u64 = storage::get_or(&nonce_key, 0); let expected_nonce: u64 = storage::hashed::get_or(&blake2_256, &nonce_key, 0);
if tx.nonce < expected_nonce { if tx.nonce < expected_nonce {
return TransactionValidity::Invalid(ApplyError::Stale as i8); return TransactionValidity::Invalid(ApplyError::Stale as i8);
} }
@@ -241,26 +241,26 @@ fn execute_transaction_backend(utx: &Extrinsic) -> ApplyResult {
fn execute_transfer_backend(tx: &Transfer) -> ApplyResult { fn execute_transfer_backend(tx: &Transfer) -> ApplyResult {
// check nonce // check nonce
let nonce_key = tx.from.to_keyed_vec(NONCE_OF); let nonce_key = tx.from.to_keyed_vec(NONCE_OF);
let expected_nonce: u64 = storage::get_or(&nonce_key, 0); let expected_nonce: u64 = storage::hashed::get_or(&blake2_256, &nonce_key, 0);
if !(tx.nonce == expected_nonce) { if !(tx.nonce == expected_nonce) {
return Err(ApplyError::Stale) return Err(ApplyError::Stale)
} }
// increment nonce in storage // increment nonce in storage
storage::put(&nonce_key, &(expected_nonce + 1)); storage::hashed::put(&blake2_256, &nonce_key, &(expected_nonce + 1));
// check sender balance // check sender balance
let from_balance_key = tx.from.to_keyed_vec(BALANCE_OF); let from_balance_key = tx.from.to_keyed_vec(BALANCE_OF);
let from_balance: u64 = storage::get_or(&from_balance_key, 0); let from_balance: u64 = storage::hashed::get_or(&blake2_256, &from_balance_key, 0);
// enact transfer // enact transfer
if !(tx.amount <= from_balance) { if !(tx.amount <= from_balance) {
return Err(ApplyError::CantPay) return Err(ApplyError::CantPay)
} }
let to_balance_key = tx.to.to_keyed_vec(BALANCE_OF); let to_balance_key = tx.to.to_keyed_vec(BALANCE_OF);
let to_balance: u64 = storage::get_or(&to_balance_key, 0); let to_balance: u64 = storage::hashed::get_or(&blake2_256, &to_balance_key, 0);
storage::put(&from_balance_key, &(from_balance - tx.amount)); storage::hashed::put(&blake2_256, &from_balance_key, &(from_balance - tx.amount));
storage::put(&to_balance_key, &(to_balance + tx.amount)); storage::hashed::put(&blake2_256, &to_balance_key, &(to_balance + tx.amount));
Ok(ApplyOutcome::Success) Ok(ApplyOutcome::Success)
} }
@@ -295,7 +295,7 @@ fn info_expect_equal_hash(given: &Hash, expected: &Hash) {
mod tests { mod tests {
use super::*; use super::*;
use runtime_io::{with_externalities, twox_128, TestExternalities}; use runtime_io::{with_externalities, twox_128, blake2_256, TestExternalities};
use parity_codec::{Joiner, KeyedVec}; use parity_codec::{Joiner, KeyedVec};
use substrate_test_client::{AuthorityKeyring, AccountKeyring}; use substrate_test_client::{AuthorityKeyring, AccountKeyring};
use crate::{Header, Transfer}; use crate::{Header, Transfer};
@@ -313,7 +313,7 @@ mod tests {
twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Alice.to_raw_public().to_vec(), twox_128(&0u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Alice.to_raw_public().to_vec(),
twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Bob.to_raw_public().to_vec(), twox_128(&1u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Bob.to_raw_public().to_vec(),
twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Charlie.to_raw_public().to_vec(), twox_128(&2u32.to_keyed_vec(well_known_keys::AUTHORITY_PREFIX)).to_vec() => AuthorityKeyring::Charlie.to_raw_public().to_vec(),
twox_128(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] blake2_256(&AccountKeyring::Alice.to_raw_public().to_keyed_vec(b"balance:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
]) ])
} }
+2 -4
View File
@@ -2223,7 +2223,6 @@ version = "1.0.0"
dependencies = [ dependencies = [
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 1.0.0", "sr-std 1.0.0",
"substrate-primitives 1.0.0", "substrate-primitives 1.0.0",
] ]
@@ -2238,7 +2237,6 @@ dependencies = [
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "paste 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 1.0.0", "sr-io 1.0.0",
"sr-primitives 1.0.0", "sr-primitives 1.0.0",
"sr-std 1.0.0", "sr-std 1.0.0",
@@ -2577,7 +2575,7 @@ dependencies = [
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2595,7 +2593,6 @@ dependencies = [
"memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-io 1.0.0", "sr-io 1.0.0",
"sr-primitives 1.0.0", "sr-primitives 1.0.0",
"sr-std 1.0.0", "sr-std 1.0.0",
@@ -2628,6 +2625,7 @@ dependencies = [
"memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 1.0.0", "sr-std 1.0.0",
"substrate-primitives 1.0.0",
"trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
+1
View File
@@ -2751,6 +2751,7 @@ dependencies = [
"memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 1.0.0", "sr-std 1.0.0",
"substrate-primitives 1.0.0",
"trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
+13 -13
View File
@@ -34,7 +34,7 @@ mod tests {
use keyring::{AuthorityKeyring, AccountKeyring}; use keyring::{AuthorityKeyring, AccountKeyring};
use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency}; use runtime_support::{Hashable, StorageValue, StorageMap, traits::Currency};
use state_machine::{CodeExecutor, Externalities, TestExternalities}; use state_machine::{CodeExecutor, Externalities, TestExternalities};
use primitives::{twox_128, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, use primitives::{twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue,
NativeOrEncoded}; NativeOrEncoded};
use node_primitives::{Hash, BlockNumber, AccountId}; use node_primitives::{Hash, BlockNumber, AccountId};
use runtime_primitives::traits::{Header as HeaderT, Hash as HashT}; use runtime_primitives::traits::{Header as HeaderT, Hash as HashT};
@@ -119,13 +119,13 @@ mod tests {
#[test] #[test]
fn panic_execution_with_foreign_code_gives_error() { fn panic_execution_with_foreign_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
@@ -152,13 +152,13 @@ mod tests {
#[test] #[test]
fn bad_extrinsic_with_native_equivalent_code_gives_error() { fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
@@ -185,13 +185,13 @@ mod tests {
#[test] #[test]
fn successful_execution_with_native_equivalent_code_gives_ok() { fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(COMPACT_CODE, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
@@ -222,13 +222,13 @@ mod tests {
#[test] #[test]
fn successful_execution_with_foreign_code_gives_ok() { fn successful_execution_with_foreign_code_gives_ok() {
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(BLOATY_CODE, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
@@ -796,13 +796,13 @@ mod tests {
fn panic_execution_gives_error() { fn panic_execution_gives_error() {
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm"); let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.wasm");
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(foreign_code, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(foreign_code, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![69u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![70u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
@@ -818,13 +818,13 @@ mod tests {
fn successful_execution_gives_ok() { fn successful_execution_gives_ok() {
let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm"); let foreign_code = include_bytes!("../../runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm");
let mut t = TestExternalities::<Blake2Hasher>::new_with_code(foreign_code, map![ let mut t = TestExternalities::<Blake2Hasher>::new_with_code(foreign_code, map![
twox_128(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], blake2_256(&<balances::FreeBalance<Runtime>>::key_for(alice())).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], twox_128(<balances::TotalIssuance<Runtime>>::key()).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::ExistentialDeposit<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::CreationFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransferFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<indices::NextEnumSet<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32], blake2_256(&<system::BlockHash<Runtime>>::key_for(0)).to_vec() => vec![0u8; 32],
twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16], twox_128(<balances::TransactionBaseFee<Runtime>>::key()).to_vec() => vec![0u8; 16],
twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16] twox_128(<balances::TransactionByteFee<Runtime>>::key()).to_vec() => vec![0u8; 16]
]); ]);
+1 -1
View File
@@ -59,7 +59,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: create_runtime_str!("node"), spec_name: create_runtime_str!("node"),
impl_name: create_runtime_str!("substrate-node"), impl_name: create_runtime_str!("substrate-node"),
authoring_version: 10, authoring_version: 10,
spec_version: 64, spec_version: 65,
impl_version: 65, impl_version: 65,
apis: RUNTIME_API_VERSIONS, apis: RUNTIME_API_VERSIONS,
}; };
+1
View File
@@ -2901,6 +2901,7 @@ dependencies = [
"memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "memory-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"sr-std 1.0.0", "sr-std 1.0.0",
"substrate-primitives 1.0.0",
"trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-db 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)", "trie-root 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
+1 -1
View File
@@ -443,7 +443,7 @@ mod tests {
header: Header { header: Header {
parent_hash: [69u8; 32].into(), parent_hash: [69u8; 32].into(),
number: 1, number: 1,
state_root: hex!("49cd58a254ccf6abc4a023d9a22dcfc421e385527a250faec69f8ad0d8ed3e48").into(), state_root: hex!("4c10fddf15e63c91ff2aa13ab3a9b7f6b19938d533829489e72ba40278a08fac").into(),
extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(),
digest: Digest { logs: vec![], }, digest: Digest { logs: vec![], },
}, },
+8 -7
View File
@@ -96,16 +96,17 @@ decl_storage! {
}): T::AccountIndex; }): T::AccountIndex;
/// The enumeration sets. /// The enumeration sets.
pub EnumSet get(enum_set): map T::AccountIndex => Vec<T::AccountId>; pub EnumSet get(enum_set) build(|config: &GenesisConfig<T>| {
(0..(config.ids.len() + ENUM_SET_SIZE - 1) / ENUM_SET_SIZE)
.map(|i| (
T::AccountIndex::sa(i),
config.ids[i * ENUM_SET_SIZE..config.ids.len().min((i + 1) * ENUM_SET_SIZE)].to_owned(),
))
.collect::<Vec<_>>()
}): map T::AccountIndex => Vec<T::AccountId>;
} }
add_extra_genesis { add_extra_genesis {
config(ids): Vec<T::AccountId>; config(ids): Vec<T::AccountId>;
build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig<T>| {
for i in 0..(config.ids.len() + ENUM_SET_SIZE - 1) / ENUM_SET_SIZE {
storage.insert(GenesisConfig::<T>::hash(&<EnumSet<T>>::key_for(T::AccountIndex::sa(i))).to_vec(),
config.ids[i * ENUM_SET_SIZE..config.ids.len().min((i + 1) * ENUM_SET_SIZE)].to_owned().encode());
}
});
} }
} }
+18 -3
View File
@@ -253,17 +253,30 @@ impl std::fmt::Debug for DefaultByteGetter {
} }
} }
/// Hasher used by storage maps
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub enum StorageHasher {
Blake2_128,
Blake2_256,
Twox128,
Twox256,
Twox64Concat,
}
/// A storage function type. /// A storage function type.
#[derive(Clone, PartialEq, Eq, Encode)] #[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub enum StorageFunctionType { pub enum StorageFunctionType {
Plain(DecodeDifferentStr), Plain(DecodeDifferentStr),
Map { Map {
hasher: StorageHasher,
key: DecodeDifferentStr, key: DecodeDifferentStr,
value: DecodeDifferentStr, value: DecodeDifferentStr,
is_linked: bool, is_linked: bool,
}, },
DoubleMap { DoubleMap {
hasher: StorageHasher,
key1: DecodeDifferentStr, key1: DecodeDifferentStr,
key2: DecodeDifferentStr, key2: DecodeDifferentStr,
value: DecodeDifferentStr, value: DecodeDifferentStr,
@@ -312,8 +325,10 @@ pub enum RuntimeMetadata {
V1(RuntimeMetadataDeprecated), V1(RuntimeMetadataDeprecated),
/// Version 2 for runtime metadata. No longer used. /// Version 2 for runtime metadata. No longer used.
V2(RuntimeMetadataDeprecated), V2(RuntimeMetadataDeprecated),
/// Version 3 for runtime metadata. /// Version 3 for runtime metadata. No longer used.
V3(RuntimeMetadataV3), V3(RuntimeMetadataDeprecated),
/// Version 4 for runtime metadata.
V4(RuntimeMetadataV4),
} }
/// Enum that should fail. /// Enum that should fail.
@@ -336,7 +351,7 @@ impl Decode for RuntimeMetadataDeprecated {
/// The metadata of a runtime. /// The metadata of a runtime.
#[derive(Eq, Encode, PartialEq)] #[derive(Eq, Encode, PartialEq)]
#[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))] #[cfg_attr(feature = "std", derive(Decode, Debug, Serialize))]
pub struct RuntimeMetadataV3 { pub struct RuntimeMetadataV4 {
pub modules: DecodeDifferentArray<ModuleMetadata>, pub modules: DecodeDifferentArray<ModuleMetadata>,
} }
+2 -2
View File
@@ -7,7 +7,7 @@ edition = "2018"
[dependencies] [dependencies]
hex-literal = { version = "0.1.0", optional = true } hex-literal = { version = "0.1.0", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] }
parity-codec = { version = "3.5.1", default-features = false, features = ["derive"] } codec = { package = "parity-codec", version = "3.5.1", default-features = false, features = ["derive"] }
srml-metadata = { path = "../metadata", default-features = false } srml-metadata = { path = "../metadata", default-features = false }
sr-std = { path = "../../core/sr-std", default-features = false } sr-std = { path = "../../core/sr-std", default-features = false }
runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false } runtime_io = { package = "sr-io", path = "../../core/sr-io", default-features = false }
@@ -30,7 +30,7 @@ std = [
"bitmask/std", "bitmask/std",
"serde", "serde",
"runtime_io/std", "runtime_io/std",
"parity-codec/std", "codec/std",
"sr-std/std", "sr-std/std",
"sr-primitives/std", "sr-primitives/std",
"srml-metadata/std", "srml-metadata/std",
@@ -67,13 +67,13 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
let mutate_impl = if !is_option { let mutate_impl = if !is_option {
quote!{ quote!{
<Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage) <Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::put(&val, storage)
} }
} else { } else {
quote!{ quote!{
match val { match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageValue<#typ>>::put(&val, storage), Some(ref val) => <Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::put(&val, storage),
None => <Self as #scrate::storage::generator::StorageValue<#typ>>::kill(storage), None => <Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::kill(storage),
} }
} }
}; };
@@ -96,9 +96,12 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
// generator for value // generator for value
quote!{ quote!{
#( #[ #attrs ] )* #( #[ #attrs ] )*
#visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>
(#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>);
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageValue<#typ> for #name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable>
#scrate::storage::hashed::generator::StorageValue<#typ> for #name<#traitinstance, #instance>
{
type Query = #value_type; type Query = #value_type;
/// Get the storage key. /// Get the storage key.
@@ -107,20 +110,20 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
/// Load the value from the provided storage instance. /// Load the value from the provided storage instance.
fn get<S: #scrate::GenericStorage>(storage: &S) -> Self::Query { fn get<S: #scrate::HashedStorage<#scrate::Twox128>>(storage: &S) -> Self::Query {
storage.get(<Self as #scrate::storage::generator::StorageValue<#typ>>::key()) storage.get(<Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault) .#option_simple_1(|| #fielddefault)
} }
/// Take a value from storage, removing it afterwards. /// Take a value from storage, removing it afterwards.
fn take<S: #scrate::GenericStorage>(storage: &S) -> Self::Query { fn take<S: #scrate::HashedStorage<#scrate::Twox128>>(storage: &S) -> Self::Query {
storage.take(<Self as #scrate::storage::generator::StorageValue<#typ>>::key()) storage.take(<Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::key())
.#option_simple_1(|| #fielddefault) .#option_simple_1(|| #fielddefault)
} }
/// Mutate the value under a key. /// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::HashedStorage<#scrate::Twox128>>(f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageValue<#typ>>::get(storage); let mut val = <Self as #scrate::storage::hashed::generator::StorageValue<#typ>>::get(storage);
let ret = f(&mut val); let ret = f(&mut val);
#mutate_impl ; #mutate_impl ;
@@ -130,7 +133,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
pub fn map(self, kty: &syn::Type) -> TokenStream2 { pub fn map(self, hasher: TokenStream2, kty: &syn::Type) -> TokenStream2 {
let Self { let Self {
scrate, scrate,
visibility, visibility,
@@ -147,15 +150,17 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos; let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option); let option_simple_1 = option_unwrap(is_option);
let as_map = quote!{ <Self as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>> };
let mutate_impl = if !is_option { let mutate_impl = if !is_option {
quote!{ quote!{
<Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage) #as_map::insert(key, &val, storage)
} }
} else { } else {
quote!{ quote!{
match val { match val {
Some(ref val) => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::insert(key, &val, storage), Some(ref val) => #as_map::insert(key, &val, storage),
None => <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::remove(key, storage), None => #as_map::remove(key, storage),
} }
} }
}; };
@@ -178,11 +183,16 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
// generator for map // generator for map
quote!{ quote!{
#( #[ #attrs ] )* #( #[ #attrs ] )*
#visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>
(#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>);
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable>
#scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance>
{
type Query = #value_type; type Query = #value_type;
type Hasher = #scrate::#hasher;
/// Get the prefix key in storage. /// Get the prefix key in storage.
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
#final_prefix #final_prefix
@@ -190,26 +200,26 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
/// Get the storage key used to fetch a value corresponding to a specific key. /// Get the storage key used to fetch a value corresponding to a specific key.
fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec<u8> { fn key_for(x: &#kty) -> #scrate::rstd::vec::Vec<u8> {
let mut key = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::prefix().to_vec(); let mut key = #as_map::prefix().to_vec();
#scrate::codec::Encode::encode_to(x, &mut key); #scrate::codec::Encode::encode_to(x, &mut key);
key key
} }
/// Load the value associated with the given key from the map. /// Load the value associated with the given key from the map.
fn get<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query { fn get<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, storage: &S) -> Self::Query {
let key = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key); let key = #as_map::key_for(key);
storage.get(&key[..]).#option_simple_1(|| #fielddefault) storage.get(&key[..]).#option_simple_1(|| #fielddefault)
} }
/// Take the value, reading and removing it. /// Take the value, reading and removing it.
fn take<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query { fn take<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, storage: &S) -> Self::Query {
let key = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(key); let key = #as_map::key_for(key);
storage.take(&key[..]).#option_simple_1(|| #fielddefault) storage.take(&key[..]).#option_simple_1(|| #fielddefault)
} }
/// Mutate the value under a key /// Mutate the value under a key
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, f: F, storage: &S) -> R {
let mut val = <Self as #scrate::storage::generator::StorageMap<#kty, #typ>>::get(key, storage); let mut val = #as_map::get(key, storage);
let ret = f(&mut val); let ret = f(&mut val);
#mutate_impl ; #mutate_impl ;
@@ -220,7 +230,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
pub fn linked_map(self, kty: &syn::Type) -> TokenStream2 { pub fn linked_map(self, hasher: TokenStream2, kty: &syn::Type) -> TokenStream2 {
let Self { let Self {
scrate, scrate,
visibility, visibility,
@@ -264,8 +274,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
let name_lowercase = name.to_string().to_lowercase(); let name_lowercase = name.to_string().to_lowercase();
let inner_module = syn::Ident::new(&format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span()); let inner_module = syn::Ident::new(&format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span());
let linkage = syn::Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span()); let linkage = syn::Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span());
let phantom_data = quote! { #scrate::storage::generator::PhantomData }; let phantom_data = quote! { #scrate::rstd::marker::PhantomData };
let as_map = quote!{ <Self as #scrate::storage::generator::StorageMap<#kty, #typ>> }; let as_map = quote!{ <Self as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>> };
let put_or_insert = quote! { let put_or_insert = quote! {
match linkage { match linkage {
Some(linkage) => storage.put(key_for, &(val, linkage)), Some(linkage) => storage.put(key_for, &(val, linkage)),
@@ -316,14 +326,17 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
pub _data: #phantom_data<V>, pub _data: #phantom_data<V>,
} }
impl<'a, S: #scrate::GenericStorage, #traitinstance: #traittype, #instance #bound_instantiable> Iterator for Enumerator<'a, S, #kty, (#typ, #traitinstance, #instance)> impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #traitinstance: #traittype, #instance #bound_instantiable>
Iterator for Enumerator<'a, S, #kty, (#typ, #traitinstance, #instance)>
where #traitinstance: 'a where #traitinstance: 'a
{ {
type Item = (#kty, #typ); type Item = (#kty, #typ);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let next = self.next.take()?; let next = self.next.take()?;
let key_for = <super::#name<#traitinstance, #instance> as #scrate::storage::generator::StorageMap<#kty, #typ>>::key_for(&next); let key_for = <super::#name<#traitinstance, #instance>
as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>>::key_for(&next);
let (val, linkage): (#typ, Linkage<#kty>) = self.storage.get(&*key_for) 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"); .expect("previous/next only contain existing entires; we enumerate using next; entry exists; qed");
self.next = linkage.next; self.next = linkage.next;
@@ -336,26 +349,26 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
/// ///
/// Takes care of updating previous and next elements points /// Takes care of updating previous and next elements points
/// as well as updates head if the element is first or last. /// as well as updates head if the element is first or last.
fn remove_linkage<S: #scrate::GenericStorage>(linkage: Linkage<#kty>, storage: &S); fn remove_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(linkage: Linkage<#kty>, storage: &S);
/// Read the contained data and it's linkage. /// Read the contained data and it's linkage.
fn read_with_linkage<S: #scrate::GenericStorage>(storage: &S, key: &[u8]) -> Option<(#value_type, Linkage<#kty>)>; fn read_with_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S, key: &[u8]) -> Option<(#value_type, Linkage<#kty>)>;
/// Generate linkage for newly inserted element. /// Generate linkage for newly inserted element.
/// ///
/// Takes care of updating head and previous head's pointer. /// Takes care of updating head and previous head's pointer.
fn new_head_linkage<S: #scrate::GenericStorage>( fn new_head_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(
storage: &S, storage: &S,
key: &#kty, key: &#kty,
) -> Linkage<#kty>; ) -> Linkage<#kty>;
/// Read current head pointer. /// Read current head pointer.
fn read_head<S: #scrate::GenericStorage>(storage: &S) -> Option<#kty>; fn read_head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S) -> Option<#kty>;
/// Overwrite current head pointer. /// Overwrite current head pointer.
/// ///
/// If `None` is given head is removed from storage. /// If `None` is given head is removed from storage.
fn write_head<S: #scrate::GenericStorage>(storage: &S, head: Option<&#kty>); fn write_head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S, head: Option<&#kty>);
} }
} }
}; };
@@ -365,7 +378,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#phantom_data<(#traitinstance #comma_instance)>); #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#phantom_data<(#traitinstance #comma_instance)>);
impl<#traitinstance: #traittype, #instance #bound_instantiable> self::#inner_module::Utils<#traitinstance, #instance> for #name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable> self::#inner_module::Utils<#traitinstance, #instance> for #name<#traitinstance, #instance> {
fn remove_linkage<S: #scrate::GenericStorage>( fn remove_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(
linkage: self::#inner_module::Linkage<#kty>, linkage: self::#inner_module::Linkage<#kty>,
storage: &S, storage: &S,
) { ) {
@@ -394,14 +407,14 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
fn read_with_linkage<S: #scrate::GenericStorage>( fn read_with_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(
storage: &S, storage: &S,
key: &[u8], key: &[u8],
) -> Option<(#value_type, self::#inner_module::Linkage<#kty>)> { ) -> Option<(#value_type, self::#inner_module::Linkage<#kty>)> {
storage.get(key) storage.get(key)
} }
fn new_head_linkage<S: #scrate::GenericStorage>( fn new_head_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(
storage: &S, storage: &S,
key: &#kty, key: &#kty,
) -> self::#inner_module::Linkage<#kty> { ) -> self::#inner_module::Linkage<#kty> {
@@ -433,11 +446,11 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
fn read_head<S: #scrate::GenericStorage>(storage: &S) -> Option<#kty> { fn read_head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S) -> Option<#kty> {
storage.get(#final_head_key) storage.get(#final_head_key)
} }
fn write_head<S: #scrate::GenericStorage>(storage: &S, head: Option<&#kty>) { fn write_head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S, head: Option<&#kty>) {
match head { match head {
Some(head) => storage.put(#final_head_key, head), Some(head) => storage.put(#final_head_key, head),
None => storage.kill(#final_head_key), None => storage.kill(#final_head_key),
@@ -451,9 +464,13 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#structure #structure
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable>
#scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#traitinstance, #instance>
{
type Query = #value_type; type Query = #value_type;
type Hasher = #scrate::#hasher;
/// Get the prefix key in storage. /// Get the prefix key in storage.
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
#final_prefix #final_prefix
@@ -467,12 +484,12 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
/// Load the value associated with the given key from the map. /// Load the value associated with the given key from the map.
fn get<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query { fn get<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, storage: &S) -> Self::Query {
storage.get(&*#as_map::key_for(key)).#option_simple_1(|| #fielddefault) storage.get(&*#as_map::key_for(key)).#option_simple_1(|| #fielddefault)
} }
/// Take the value, reading and removing it. /// Take the value, reading and removing it.
fn take<S: #scrate::GenericStorage>(key: &#kty, storage: &S) -> Self::Query { fn take<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, storage: &S) -> Self::Query {
use self::#inner_module::Utils; use self::#inner_module::Utils;
let res: Option<(#value_type, self::#inner_module::Linkage<#kty>)> = storage.take(&*#as_map::key_for(key)); let res: Option<(#value_type, self::#inner_module::Linkage<#kty>)> = storage.take(&*#as_map::key_for(key));
@@ -486,12 +503,12 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
/// Remove the value under a key. /// Remove the value under a key.
fn remove<S: #scrate::GenericStorage>(key: &#kty, storage: &S) { fn remove<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, storage: &S) {
#as_map::take(key, storage); #as_map::take(key, storage);
} }
/// Store a value to be associated with the given key from the map. /// Store a value to be associated with the given key from the map.
fn insert<S: #scrate::GenericStorage>(key: &#kty, val: &#typ, storage: &S) { fn insert<S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, val: &#typ, storage: &S) {
use self::#inner_module::Utils; use self::#inner_module::Utils;
let key_for = &*#as_map::key_for(key); let key_for = &*#as_map::key_for(key);
@@ -505,7 +522,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
/// Mutate the value under a key /// Mutate the value under a key
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericStorage>(key: &#kty, f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::HashedStorage<#scrate::#hasher>>(key: &#kty, f: F, storage: &S) -> R {
use self::#inner_module::Utils; use self::#inner_module::Utils;
let key_for = &*#as_map::key_for(key); let key_for = &*#as_map::key_for(key);
@@ -519,20 +536,22 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #scrate::storage::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance, #instance> { impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable>
fn head<S: #scrate::GenericStorage>(storage: &S) -> Option<#kty> { #scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ> for #name<#traitinstance, #instance>
{
fn head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S) -> Option<#kty> {
use self::#inner_module::Utils; use self::#inner_module::Utils;
Self::read_head(storage) Self::read_head(storage)
} }
fn enumerate<'a, S: #scrate::GenericStorage>(storage: &'a S) -> #scrate::storage::generator::Box<dyn Iterator<Item = (#kty, #typ)> + 'a> where fn enumerate<'a, S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &'a S) -> #scrate::rstd::boxed::Box<dyn Iterator<Item = (#kty, #typ)> + 'a> where
#kty: 'a, #kty: 'a,
#typ: 'a, #typ: 'a,
{ {
use self::#inner_module::{Utils, Enumerator}; use self::#inner_module::{Utils, Enumerator};
#scrate::storage::generator::Box::new(Enumerator { #scrate::rstd::boxed::Box::new(Enumerator {
next: Self::read_head(storage), next: Self::read_head(storage),
storage, storage,
_data: #phantom_data::<(#typ, #traitinstance, #instance)>::default(), _data: #phantom_data::<(#typ, #traitinstance, #instance)>::default(),
@@ -542,7 +561,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} }
} }
pub fn double_map(self, k1ty: &syn::Type, k2ty: &syn::Type, k2_hasher: TokenStream2) -> TokenStream2 { pub fn double_map(self, hasher: TokenStream2, k1ty: &syn::Type, k2ty: &syn::Type, k2_hasher: TokenStream2) -> TokenStream2 {
let Self { let Self {
scrate, scrate,
visibility, visibility,
@@ -593,11 +612,20 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
// generator for double map // generator for double map
quote!{ quote!{
#( #[ #attrs ] )* #( #[ #attrs ] )*
#visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>(#scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>); #visibility struct #name<#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance>
(#scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>);
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable>
#scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#traitinstance, #instance>
{
type Query = #value_type; type Query = #value_type;
fn prefix_for(k1: &#k1ty) -> Vec<u8> {
let mut key = #as_double_map::prefix().to_vec();
#scrate::codec::Encode::encode_to(k1, &mut key);
#scrate::Hashable::#hasher(&key).to_vec()
}
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
#final_prefix #final_prefix
} }
@@ -608,17 +636,17 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
key key
} }
fn get<S: #scrate::GenericUnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query { fn get<S: #scrate::UnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query {
let key = #as_double_map::key_for(key1, key2); let key = #as_double_map::key_for(key1, key2);
storage.get(&key).#option_simple_1(|| #fielddefault) storage.get(&key).#option_simple_1(|| #fielddefault)
} }
fn take<S: #scrate::GenericUnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query { fn take<S: #scrate::UnhashedStorage>(key1: &#k1ty, key2: &#k2ty, storage: &S) -> Self::Query {
let key = #as_double_map::key_for(key1, key2); let key = #as_double_map::key_for(key1, key2);
storage.take(&key).#option_simple_1(|| #fielddefault) storage.take(&key).#option_simple_1(|| #fielddefault)
} }
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::GenericUnhashedStorage>(key1: &#k1ty, key2: &#k2ty, f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: #scrate::UnhashedStorage>(key1: &#k1ty, key2: &#k2ty, f: F, storage: &S) -> R {
let mut val = #as_double_map::get(key1, key2, storage); let mut val = #as_double_map::get(key1, key2, storage);
let ret = f(&mut val); let ret = f(&mut val);
@@ -23,6 +23,8 @@ use srml_support_procedural_tools::{ToTokens, Parse, custom_keyword, custom_keyw
use syn::{Ident, Token}; use syn::{Ident, Token};
use syn::token::CustomKeyword; use syn::token::CustomKeyword;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
mod impls; mod impls;
@@ -138,6 +140,7 @@ enum DeclStorageType {
#[derive(Parse, ToTokens, Debug)] #[derive(Parse, ToTokens, Debug)]
struct DeclStorageMap { struct DeclStorageMap {
pub map_keyword: ext::CustomToken<MapKeyword>, pub map_keyword: ext::CustomToken<MapKeyword>,
pub hasher: Option<SetHasher>,
pub key: syn::Type, pub key: syn::Type,
pub ass_keyword: Token![=>], pub ass_keyword: Token![=>],
pub value: syn::Type, pub value: syn::Type,
@@ -146,6 +149,7 @@ struct DeclStorageMap {
#[derive(Parse, ToTokens, Debug)] #[derive(Parse, ToTokens, Debug)]
struct DeclStorageLinkedMap { struct DeclStorageLinkedMap {
pub map_keyword: ext::CustomToken<LinkedMapKeyword>, pub map_keyword: ext::CustomToken<LinkedMapKeyword>,
pub hasher: Option<SetHasher>,
pub key: syn::Type, pub key: syn::Type,
pub ass_keyword: Token![=>], pub ass_keyword: Token![=>],
pub value: syn::Type, pub value: syn::Type,
@@ -154,19 +158,22 @@ struct DeclStorageLinkedMap {
#[derive(Parse, ToTokens, Debug)] #[derive(Parse, ToTokens, Debug)]
struct DeclStorageDoubleMap { struct DeclStorageDoubleMap {
pub map_keyword: ext::CustomToken<DoubleMapKeyword>, pub map_keyword: ext::CustomToken<DoubleMapKeyword>,
pub hasher: Option<SetHasher>,
pub key1: syn::Type, pub key1: syn::Type,
pub comma_keyword: Token![,], pub comma_keyword: Token![,],
pub key2_hasher: DeclStorageDoubleMapHasher, pub key2_hasher: Hasher,
pub key2: ext::Parens<syn::Type>, pub key2: ext::Parens<syn::Type>,
pub ass_keyword: Token![=>], pub ass_keyword: Token![=>],
pub value: syn::Type, pub value: syn::Type,
} }
#[derive(Parse, ToTokens, Debug)] #[derive(Parse, ToTokens, Debug)]
enum DeclStorageDoubleMapHasher { enum Hasher {
Blake2_256(ext::CustomToken<Blake2_256Keyword>), Blake2_256(ext::CustomToken<Blake2_256Keyword>),
Blake2_128(ext::CustomToken<Blake2_128Keyword>),
Twox256(ext::CustomToken<Twox256Keyword>), Twox256(ext::CustomToken<Twox256Keyword>),
Twox128(ext::CustomToken<Twox128Keyword>), Twox128(ext::CustomToken<Twox128Keyword>),
Twox64Concat(ext::CustomToken<Twox64ConcatKeyword>),
} }
#[derive(Parse, ToTokens, Debug)] #[derive(Parse, ToTokens, Debug)]
@@ -175,6 +182,64 @@ struct DeclStorageDefault {
pub expr: syn::Expr, pub expr: syn::Expr,
} }
#[derive(Parse, ToTokens, Debug)]
struct SetHasher {
pub hasher_keyword: ext::CustomToken<SetHasher>,
pub inner: ext::Parens<Hasher>,
}
#[derive(Debug, Clone)]
enum HasherKind {
Blake2_256,
Blake2_128,
Twox256,
Twox128,
Twox64Concat,
}
impl From<&SetHasher> for HasherKind {
fn from(set_hasher: &SetHasher) -> Self {
match set_hasher.inner.content {
Hasher::Blake2_256(_) => HasherKind::Blake2_256,
Hasher::Blake2_128(_) => HasherKind::Blake2_128,
Hasher::Twox256(_) => HasherKind::Twox256,
Hasher::Twox128(_) => HasherKind::Twox128,
Hasher::Twox64Concat(_) => HasherKind::Twox64Concat,
}
}
}
impl HasherKind {
fn into_storage_hasher_struct(&self) -> TokenStream2 {
match self {
HasherKind::Blake2_256 => quote!( Blake2_256 ),
HasherKind::Blake2_128 => quote!( Blake2_128 ),
HasherKind::Twox256 => quote!( Twox256 ),
HasherKind::Twox128 => quote!( Twox128 ),
HasherKind::Twox64Concat => quote!( Twox64Concat ),
}
}
fn into_hashable_fn(&self) -> TokenStream2 {
match self {
HasherKind::Blake2_256 => quote!( blake2_256 ),
HasherKind::Blake2_128 => quote!( blake2_128 ),
HasherKind::Twox256 => quote!( twox_256 ),
HasherKind::Twox128 => quote!( twox_128 ),
HasherKind::Twox64Concat => quote!( twox_64_concat),
}
}
fn into_metadata(&self) -> TokenStream2 {
match self {
HasherKind::Blake2_256 => quote!( StorageHasher::Blake2_256 ),
HasherKind::Blake2_128 => quote!( StorageHasher::Blake2_128 ),
HasherKind::Twox256 => quote!( StorageHasher::Twox256 ),
HasherKind::Twox128 => quote!( StorageHasher::Twox128 ),
HasherKind::Twox64Concat => quote!( StorageHasher::Twox64Concat ),
}
}
}
custom_keyword_impl!(SpecificHiddenCrate, "hiddencrate", "hiddencrate as keyword"); custom_keyword_impl!(SpecificHiddenCrate, "hiddencrate", "hiddencrate as keyword");
custom_keyword_impl!(DeclStorageConfig, "config", "build as keyword"); custom_keyword_impl!(DeclStorageConfig, "config", "build as keyword");
custom_keyword!(ConfigKeyword, "config", "config as keyword"); custom_keyword!(ConfigKeyword, "config", "config as keyword");
@@ -186,6 +251,9 @@ custom_keyword!(MapKeyword, "map", "map as keyword");
custom_keyword!(LinkedMapKeyword, "linked_map", "linked_map as keyword"); custom_keyword!(LinkedMapKeyword, "linked_map", "linked_map as keyword");
custom_keyword!(DoubleMapKeyword, "double_map", "double_map as keyword"); custom_keyword!(DoubleMapKeyword, "double_map", "double_map as keyword");
custom_keyword!(Blake2_256Keyword, "blake2_256", "Blake2_256 as keyword"); custom_keyword!(Blake2_256Keyword, "blake2_256", "Blake2_256 as keyword");
custom_keyword!(Twox256Keyword, "twox_256", "Twox_256 as keyword"); custom_keyword!(Blake2_128Keyword, "blake2_128", "Blake2_128 as keyword");
custom_keyword!(Twox128Keyword, "twox_128", "Twox_128 as keyword"); custom_keyword!(Twox256Keyword, "twox_256", "Twox256 as keyword");
custom_keyword!(Twox128Keyword, "twox_128", "Twox128 as keyword");
custom_keyword!(Twox64ConcatKeyword, "twox_64_concat", "Twox64Concat as keyword");
custom_keyword_impl!(ExtraGenesisSkipPhantomDataField, "extra_genesis_skip_phantom_data_field", "extra_genesis_skip_phantom_data_field as keyword"); custom_keyword_impl!(ExtraGenesisSkipPhantomDataField, "extra_genesis_skip_phantom_data_field", "extra_genesis_skip_phantom_data_field as keyword");
custom_keyword_impl!(SetHasher, "hasher", "storage hasher");
@@ -156,13 +156,13 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #module_ident<#traitinstance, #instance> { impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #module_ident<#traitinstance, #instance> {
#impl_store_fns #impl_store_fns
#[doc(hidden)] #[doc(hidden)]
pub fn store_metadata() -> #scrate::storage::generator::StorageMetadata { pub fn store_metadata() -> #scrate::metadata::StorageMetadata {
#scrate::storage::generator::StorageMetadata { #scrate::metadata::StorageMetadata {
functions: #scrate::storage::generator::DecodeDifferent::Encode(#store_functions_to_metadata) , functions: #scrate::metadata::DecodeDifferent::Encode(#store_functions_to_metadata) ,
} }
} }
#[doc(hidden)] #[doc(hidden)]
pub fn store_metadata_functions() -> &'static [#scrate::storage::generator::StorageFunctionMetadata] { pub fn store_metadata_functions() -> &'static [#scrate::metadata::StorageFunctionMetadata] {
#store_functions_to_metadata #store_functions_to_metadata
} }
#[doc(hidden)] #[doc(hidden)]
@@ -284,7 +284,7 @@ fn decl_store_extra_genesis(
use #scrate::codec::{Encode, Decode}; use #scrate::codec::{Encode, Decode};
let v = (#builder)(&self); let v = (#builder)(&self);
<#name<#traitinstance, #instance> as #scrate::storage::generator::StorageValue<#typ>>::put(&v, &storage); <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageValue<#typ>>::put(&v, &storage);
}} }}
}, },
DeclStorageTypeInfosKind::Map { key_type, .. } => { DeclStorageTypeInfosKind::Map { key_type, .. } => {
@@ -294,7 +294,7 @@ fn decl_store_extra_genesis(
let data = (#builder)(&self); let data = (#builder)(&self);
for (k, v) in data.into_iter() { for (k, v) in data.into_iter() {
<#name<#traitinstance, #instance> as #scrate::storage::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, &storage); <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageMap<#key_type, #typ>>::insert(&k, &v, &storage);
} }
}} }}
}, },
@@ -402,7 +402,7 @@ fn decl_store_extra_genesis(
quote!{ quote!{
#[serde(skip)] #[serde(skip)]
pub _genesis_phantom_data: #scrate::storage::generator::PhantomData<(#traitinstance #comma_instance)>, pub _genesis_phantom_data: #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>,
}, },
quote!{ quote!{
_genesis_phantom_data: Default::default(), _genesis_phantom_data: Default::default(),
@@ -440,12 +440,12 @@ fn decl_store_extra_genesis(
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl#fparam_impl #scrate::runtime_primitives::BuildStorage for GenesisConfig#sparam { impl#fparam_impl #scrate::runtime_primitives::BuildStorage for GenesisConfig#sparam {
fn assimilate_storage(self, r: &mut #scrate::runtime_primitives::StorageOverlay, c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay) -> ::std::result::Result<(), String> { fn assimilate_storage(self, r: &mut #scrate::runtime_primitives::StorageOverlay, c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay) -> ::std::result::Result<(), String> {
use #scrate::rstd::{cell::RefCell, marker::PhantomData}; use #scrate::rstd::cell::RefCell;
let storage = (RefCell::new(r), PhantomData::<Self>::default()); let storage = RefCell::new(r);
#builders #builders
let r = storage.0.into_inner(); let r = storage.into_inner();
#scall(r, c, &self); #scall(r, c, &self);
@@ -589,14 +589,14 @@ fn decl_storage_items(
DeclStorageTypeInfosKind::Simple => { DeclStorageTypeInfosKind::Simple => {
i.simple_value() i.simple_value()
}, },
DeclStorageTypeInfosKind::Map { key_type, is_linked: false } => { DeclStorageTypeInfosKind::Map { key_type, is_linked: false, hasher } => {
i.map(key_type) i.map(hasher.into_storage_hasher_struct(), key_type)
}, },
DeclStorageTypeInfosKind::Map { key_type, is_linked: true } => { DeclStorageTypeInfosKind::Map { key_type, is_linked: true, hasher } => {
i.linked_map(key_type) i.linked_map(hasher.into_storage_hasher_struct(), key_type)
}, },
DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher } => { DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher, hasher } => {
i.double_map(key1_type, key2_type, key2_hasher) i.double_map(hasher.into_hashable_fn(), key1_type, key2_type, key2_hasher)
}, },
}; };
impls.extend(implementation) impls.extend(implementation)
@@ -662,15 +662,15 @@ fn impl_store_fns(
quote!{ quote!{
#( #[ #attrs ] )* #( #[ #attrs ] )*
pub fn #get_fn() -> #value_type { pub fn #get_fn() -> #value_type {
<#name<#traitinstance, #instance> as #scrate::storage::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage) <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageValue<#typ>> :: get(&#scrate::storage::RuntimeStorage)
} }
} }
}, },
DeclStorageTypeInfosKind::Map { key_type, .. } => { DeclStorageTypeInfosKind::Map { key_type, .. } => {
quote!{ quote!{
#( #[ #attrs ] )* #( #[ #attrs ] )*
pub fn #get_fn<K: #scrate::storage::generator::Borrow<#key_type>>(key: K) -> #value_type { pub fn #get_fn<K: #scrate::rstd::borrow::Borrow<#key_type>>(key: K) -> #value_type {
<#name<#traitinstance, #instance> as #scrate::storage::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage) <#name<#traitinstance, #instance> as #scrate::storage::hashed::generator::StorageMap<#key_type, #typ>> :: get(key.borrow(), &#scrate::storage::RuntimeStorage)
} }
} }
} }
@@ -678,8 +678,8 @@ fn impl_store_fns(
quote!{ quote!{
pub fn #get_fn<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #value_type pub fn #get_fn<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #value_type
where where
KArg1: #scrate::storage::generator::Borrow<#key1_type>, KArg1: #scrate::rstd::borrow::Borrow<#key1_type>,
KArg2: #scrate::storage::generator::Borrow<#key2_type>, KArg2: #scrate::rstd::borrow::Borrow<#key2_type>,
{ {
<#name<#traitinstance> as #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>> :: get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage) <#name<#traitinstance> as #scrate::storage::unhashed::generator::StorageDoubleMap<#key1_type, #key2_type, #typ>> :: get(k1.borrow(), k2.borrow(), &#scrate::storage::RuntimeStorage)
} }
@@ -727,42 +727,46 @@ fn store_functions_to_metadata (
let stype = match type_infos.kind { let stype = match type_infos.kind {
DeclStorageTypeInfosKind::Simple => { DeclStorageTypeInfosKind::Simple => {
quote!{ quote!{
#scrate::storage::generator::StorageFunctionType::Plain( #scrate::metadata::StorageFunctionType::Plain(
#scrate::storage::generator::DecodeDifferent::Encode(#styp), #scrate::metadata::DecodeDifferent::Encode(#styp),
) )
} }
}, },
DeclStorageTypeInfosKind::Map { key_type, is_linked } => { DeclStorageTypeInfosKind::Map { key_type, is_linked, hasher } => {
let hasher = hasher.into_metadata();
let kty = clean_type_string(&quote!(#key_type).to_string()); let kty = clean_type_string(&quote!(#key_type).to_string());
quote!{ quote!{
#scrate::storage::generator::StorageFunctionType::Map { #scrate::metadata::StorageFunctionType::Map {
key: #scrate::storage::generator::DecodeDifferent::Encode(#kty), hasher: #scrate::metadata::#hasher,
value: #scrate::storage::generator::DecodeDifferent::Encode(#styp), key: #scrate::metadata::DecodeDifferent::Encode(#kty),
value: #scrate::metadata::DecodeDifferent::Encode(#styp),
is_linked: #is_linked, is_linked: #is_linked,
} }
} }
}, },
DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher } => { DeclStorageTypeInfosKind::DoubleMap { key1_type, key2_type, key2_hasher, hasher } => {
let hasher = hasher.into_metadata();
let k1ty = clean_type_string(&quote!(#key1_type).to_string()); let k1ty = clean_type_string(&quote!(#key1_type).to_string());
let k2ty = clean_type_string(&quote!(#key2_type).to_string()); let k2ty = clean_type_string(&quote!(#key2_type).to_string());
let k2_hasher = clean_type_string(&key2_hasher.to_string()); let k2_hasher = clean_type_string(&key2_hasher.to_string());
quote!{ quote!{
#scrate::storage::generator::StorageFunctionType::DoubleMap { #scrate::metadata::StorageFunctionType::DoubleMap {
key1: #scrate::storage::generator::DecodeDifferent::Encode(#k1ty), hasher: #scrate::metadata::#hasher,
key2: #scrate::storage::generator::DecodeDifferent::Encode(#k2ty), key1: #scrate::metadata::DecodeDifferent::Encode(#k1ty),
value: #scrate::storage::generator::DecodeDifferent::Encode(#styp), key2: #scrate::metadata::DecodeDifferent::Encode(#k2ty),
key2_hasher: #scrate::storage::generator::DecodeDifferent::Encode(#k2_hasher), value: #scrate::metadata::DecodeDifferent::Encode(#styp),
key2_hasher: #scrate::metadata::DecodeDifferent::Encode(#k2_hasher),
} }
} }
}, },
}; };
let modifier = if type_infos.is_option { let modifier = if type_infos.is_option {
quote!{ quote!{
#scrate::storage::generator::StorageFunctionModifier::Optional #scrate::metadata::StorageFunctionModifier::Optional
} }
} else { } else {
quote!{ quote!{
#scrate::storage::generator::StorageFunctionModifier::Default #scrate::metadata::StorageFunctionModifier::Default
} }
}; };
let default = default_value.inner.as_ref().map(|d| &d.expr) let default = default_value.inner.as_ref().map(|d| &d.expr)
@@ -786,16 +790,16 @@ fn store_functions_to_metadata (
let struct_name = proc_macro2::Ident::new(&("__GetByteStruct".to_string() + &str_name), name.span()); let struct_name = proc_macro2::Ident::new(&("__GetByteStruct".to_string() + &str_name), name.span());
let cache_name = proc_macro2::Ident::new(&("__CACHE_GET_BYTE_STRUCT_".to_string() + &str_name), name.span()); let cache_name = proc_macro2::Ident::new(&("__CACHE_GET_BYTE_STRUCT_".to_string() + &str_name), name.span());
let item = quote! { let item = quote! {
#scrate::storage::generator::StorageFunctionMetadata { #scrate::metadata::StorageFunctionMetadata {
name: #scrate::storage::generator::DecodeDifferent::Encode(#str_name), name: #scrate::metadata::DecodeDifferent::Encode(#str_name),
modifier: #modifier, modifier: #modifier,
ty: #stype, ty: #stype,
default: #scrate::storage::generator::DecodeDifferent::Encode( default: #scrate::metadata::DecodeDifferent::Encode(
#scrate::storage::generator::DefaultByteGetter( #scrate::metadata::DefaultByteGetter(
&#struct_name::<#traitinstance, #instance>(#scrate::rstd::marker::PhantomData) &#struct_name::<#traitinstance, #instance>(#scrate::rstd::marker::PhantomData)
) )
), ),
documentation: #scrate::storage::generator::DecodeDifferent::Encode(&[ #docs ]), documentation: #scrate::metadata::DecodeDifferent::Encode(&[ #docs ]),
}, },
}; };
items.extend(item); items.extend(item);
@@ -806,7 +810,7 @@ fn store_functions_to_metadata (
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
static #cache_name: #scrate::once_cell::sync::OnceCell<#scrate::rstd::vec::Vec<u8>> = #scrate::once_cell::sync::OnceCell::INIT; static #cache_name: #scrate::once_cell::sync::OnceCell<#scrate::rstd::vec::Vec<u8>> = #scrate::once_cell::sync::OnceCell::INIT;
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> {
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> { fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode; use #scrate::codec::Encode;
#cache_name.get_or_init(|| { #cache_name.get_or_init(|| {
@@ -816,7 +820,7 @@ fn store_functions_to_metadata (
} }
} }
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::storage::generator::DefaultByte for #struct_name<#traitinstance, #instance> { impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> {
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> { fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode; use #scrate::codec::Encode;
let def_val: #value_type = #default; let def_val: #value_type = #default;
@@ -848,10 +852,12 @@ pub(crate) struct DeclStorageTypeInfos<'a> {
enum DeclStorageTypeInfosKind<'a> { enum DeclStorageTypeInfosKind<'a> {
Simple, Simple,
Map { Map {
hasher: HasherKind,
key_type: &'a syn::Type, key_type: &'a syn::Type,
is_linked: bool, is_linked: bool,
}, },
DoubleMap { DoubleMap {
hasher: HasherKind,
key1_type: &'a syn::Type, key1_type: &'a syn::Type,
key2_type: &'a syn::Type, key2_type: &'a syn::Type,
key2_hasher: TokenStream2, key2_hasher: TokenStream2,
@@ -871,14 +877,17 @@ fn get_type_infos(storage_type: &DeclStorageType) -> DeclStorageTypeInfos {
let (value_type, kind) = match storage_type { let (value_type, kind) = match storage_type {
DeclStorageType::Simple(ref st) => (st, DeclStorageTypeInfosKind::Simple), DeclStorageType::Simple(ref st) => (st, DeclStorageTypeInfosKind::Simple),
DeclStorageType::Map(ref map) => (&map.value, DeclStorageTypeInfosKind::Map { DeclStorageType::Map(ref map) => (&map.value, DeclStorageTypeInfosKind::Map {
hasher: map.hasher.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256),
key_type: &map.key, key_type: &map.key,
is_linked: false, is_linked: false,
}), }),
DeclStorageType::LinkedMap(ref map) => (&map.value, DeclStorageTypeInfosKind::Map { DeclStorageType::LinkedMap(ref map) => (&map.value, DeclStorageTypeInfosKind::Map {
hasher: map.hasher.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256),
key_type: &map.key, key_type: &map.key,
is_linked: true, is_linked: true,
}), }),
DeclStorageType::DoubleMap(ref map) => (&map.value, DeclStorageTypeInfosKind::DoubleMap { DeclStorageType::DoubleMap(ref map) => (&map.value, DeclStorageTypeInfosKind::DoubleMap {
hasher: map.hasher.as_ref().map(|h| h.into()).unwrap_or(HasherKind::Blake2_256),
key1_type: &map.key1, key1_type: &map.key1,
key2_type: &map.key2.content, key2_type: &map.key2.content,
key2_hasher: { let h = &map.key2_hasher; quote! { #h } }, key2_hasher: { let h = &map.key2_hasher; quote! { #h } },
@@ -72,7 +72,7 @@ groups_impl!(Braces, Brace, Brace, parse_braces);
groups_impl!(Brackets, Bracket, Bracket, parse_brackets); groups_impl!(Brackets, Bracket, Bracket, parse_brackets);
groups_impl!(Parens, Paren, Parenthesis, parse_parens); groups_impl!(Parens, Paren, Parenthesis, parse_parens);
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct CustomToken<T>(std::marker::PhantomData<T>); pub struct CustomToken<T>(std::marker::PhantomData<T>);
impl<T: CustomKeyword> Parse for CustomToken<T> { impl<T: CustomKeyword> Parse for CustomToken<T> {
+12 -27
View File
@@ -24,29 +24,19 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// # Simple Event Example: /// # Simple Event Example:
/// ///
/// ```rust /// ```rust
/// #[macro_use] /// srml_support::decl_event!(
/// extern crate srml_support; /// pub enum Event {
/// #[macro_use]
/// extern crate parity_codec as codec;
///
/// decl_event!(
/// pub enum Event {
/// Success, /// Success,
/// Failure(String), /// Failure(String),
/// } /// }
/// ); /// );
///
///# fn main() {} ///# fn main() {}
/// ``` /// ```
/// ///
/// # Generic Event Example: /// # Generic Event Example:
/// ///
/// ```rust /// ```rust
/// #[macro_use]
/// extern crate srml_support;
/// extern crate parity_codec as codec;
/// #[macro_use]
/// extern crate parity_codec;
///
/// trait Trait { /// trait Trait {
/// type Balance; /// type Balance;
/// type Token; /// type Token;
@@ -54,8 +44,8 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// ///
/// mod event1 { /// mod event1 {
/// // Event that specifies the generic parameter explicitly (`Balance`). /// // Event that specifies the generic parameter explicitly (`Balance`).
/// decl_event!( /// srml_support::decl_event!(
/// pub enum Event<T> where Balance = <T as super::Trait>::Balance { /// pub enum Event<T> where Balance = <T as super::Trait>::Balance {
/// Message(Balance), /// Message(Balance),
/// } /// }
/// ); /// );
@@ -65,8 +55,8 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// // Event that uses the generic parameter `Balance`. /// // Event that uses the generic parameter `Balance`.
/// // If no name for the generic parameter is specified explicitly, /// // If no name for the generic parameter is specified explicitly,
/// // the name will be taken from the type name of the trait. /// // the name will be taken from the type name of the trait.
/// decl_event!( /// srml_support::decl_event!(
/// pub enum Event<T> where <T as super::Trait>::Balance { /// pub enum Event<T> where <T as super::Trait>::Balance {
/// Message(Balance), /// Message(Balance),
/// } /// }
/// ); /// );
@@ -74,12 +64,13 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// ///
/// mod event3 { /// mod event3 {
/// // And we even support declaring multiple generic parameters! /// // And we even support declaring multiple generic parameters!
/// decl_event!( /// srml_support::decl_event!(
/// pub enum Event<T> where <T as super::Trait>::Balance, <T as super::Trait>::Token { /// pub enum Event<T> where <T as super::Trait>::Balance, <T as super::Trait>::Token {
/// Message(Balance, Token), /// Message(Balance, Token),
/// } /// }
/// ); /// );
/// } /// }
///
///# fn main() {} ///# fn main() {}
/// ``` /// ```
/// ///
@@ -88,12 +79,6 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// # Generic Event with Instance Example: /// # Generic Event with Instance Example:
/// ///
/// ```rust /// ```rust
/// #[macro_use]
/// extern crate srml_support;
/// extern crate parity_codec as codec;
/// #[macro_use]
/// extern crate parity_codec;
///
///# struct DefaultInstance; ///# struct DefaultInstance;
///# trait Instance {} ///# trait Instance {}
///# impl Instance for DefaultInstance {} ///# impl Instance for DefaultInstance {}
@@ -103,7 +88,7 @@ pub use srml_metadata::{EventMetadata, DecodeDifferent, OuterEventMetadata, FnEn
/// } /// }
/// ///
/// // For module with instances, DefaultInstance is optionnal /// // For module with instances, DefaultInstance is optionnal
/// decl_event!( /// srml_support::decl_event!(
/// pub enum Event<T, I: Instance = DefaultInstance> where /// pub enum Event<T, I: Instance = DefaultInstance> where
/// <T as Trait>::Balance, /// <T as Trait>::Balance,
/// <T as Trait>::Token /// <T as Trait>::Token
@@ -504,7 +489,7 @@ macro_rules! __impl_outer_event_json_metadata {
mod tests { mod tests {
use super::*; use super::*;
use serde::Serialize; use serde::Serialize;
use parity_codec::{Encode, Decode}; use codec::{Encode, Decode};
mod system { mod system {
pub trait Trait { pub trait Trait {
+13 -2
View File
@@ -17,16 +17,24 @@
//! Hashable trait. //! Hashable trait.
use crate::codec::Codec; use crate::codec::Codec;
use runtime_io::{blake2_256, twox_128, twox_256}; use runtime_io::{blake2_128, blake2_256, twox_128, twox_256};
use crate::storage::hashed::generator::StorageHasher;
use crate::Twox64Concat;
use crate::rstd::prelude::Vec;
/// Trait for available hash functions. // This trait must be kept coherent with srml-support-procedural HasherKind usage
pub trait Hashable: Sized { pub trait Hashable: Sized {
fn blake2_128(&self) -> [u8; 16];
fn blake2_256(&self) -> [u8; 32]; fn blake2_256(&self) -> [u8; 32];
fn twox_128(&self) -> [u8; 16]; fn twox_128(&self) -> [u8; 16];
fn twox_256(&self) -> [u8; 32]; fn twox_256(&self) -> [u8; 32];
fn twox_64_concat(&self) -> Vec<u8>;
} }
impl<T: Codec> Hashable for T { impl<T: Codec> Hashable for T {
fn blake2_128(&self) -> [u8; 16] {
self.using_encoded(blake2_128)
}
fn blake2_256(&self) -> [u8; 32] { fn blake2_256(&self) -> [u8; 32] {
self.using_encoded(blake2_256) self.using_encoded(blake2_256)
} }
@@ -36,4 +44,7 @@ impl<T: Codec> Hashable for T {
fn twox_256(&self) -> [u8; 32] { fn twox_256(&self) -> [u8; 32] {
self.using_encoded(twox_256) self.using_encoded(twox_256)
} }
fn twox_64_concat(&self) -> Vec<u8> {
self.using_encoded(Twox64Concat::hash)
}
} }
+15 -9
View File
@@ -27,7 +27,7 @@ pub use serde;
#[doc(hidden)] #[doc(hidden)]
pub use sr_std as rstd; pub use sr_std as rstd;
#[doc(hidden)] #[doc(hidden)]
pub use parity_codec as codec; pub use codec;
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[doc(hidden)] #[doc(hidden)]
pub use once_cell; pub use once_cell;
@@ -35,8 +35,8 @@ pub use once_cell;
pub use paste; pub use paste;
pub use sr_primitives as runtime_primitives; pub use sr_primitives as runtime_primitives;
pub use self::storage::generator::Storage as GenericStorage; pub use self::storage::hashed::generator::{HashedStorage, Twox256, Twox128, Blake2_256, Blake2_128, Twox64Concat};
pub use self::storage::unhashed::generator::UnhashedStorage as GenericUnhashedStorage; pub use self::storage::unhashed::generator::UnhashedStorage;
#[macro_use] #[macro_use]
pub mod dispatch; pub mod dispatch;
@@ -56,7 +56,7 @@ pub mod inherent;
mod double_map; mod double_map;
pub mod traits; pub mod traits;
pub use self::storage::{StorageVec, StorageList, StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap}; pub use self::storage::{StorageList, StorageValue, StorageMap, EnumerableStorageMap, StorageDoubleMap};
pub use self::hashable::Hashable; pub use self::hashable::Hashable;
pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType}; pub use self::dispatch::{Parameter, Dispatchable, Callable, IsSubType};
pub use self::double_map::StorageDoubleMapWithHasher; pub use self::double_map::StorageDoubleMapWithHasher;
@@ -179,13 +179,13 @@ macro_rules! for_each_tuple {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use parity_codec::Codec; use codec::Codec;
use runtime_io::{with_externalities, Blake2Hasher}; use runtime_io::{with_externalities, Blake2Hasher};
use runtime_primitives::BuildStorage; use runtime_primitives::BuildStorage;
pub use srml_metadata::{ pub use srml_metadata::{
DecodeDifferent, StorageMetadata, StorageFunctionMetadata, DecodeDifferent, StorageMetadata, StorageFunctionMetadata,
StorageFunctionType, StorageFunctionModifier, StorageFunctionType, StorageFunctionModifier,
DefaultByte, DefaultByteGetter, DefaultByte, DefaultByteGetter, StorageHasher
}; };
pub use rstd::marker::PhantomData; pub use rstd::marker::PhantomData;
@@ -209,11 +209,11 @@ mod tests {
decl_storage! { decl_storage! {
trait Store for Module<T: Trait> as Example { trait Store for Module<T: Trait> as Example {
pub Data get(data) build(|_| vec![(15u32, 42u64)]): linked_map u32 => u64; pub Data get(data) build(|_| vec![(15u32, 42u64)]): linked_map hasher(twox_64_concat) u32 => u64;
pub GenericData get(generic_data): linked_map T::BlockNumber => T::BlockNumber; pub GenericData get(generic_data): linked_map hasher(twox_128) T::BlockNumber => T::BlockNumber;
pub GenericData2 get(generic_data2): linked_map T::BlockNumber => Option<T::BlockNumber>; pub GenericData2 get(generic_data2): linked_map T::BlockNumber => Option<T::BlockNumber>;
pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): double_map u32, blake2_256(u32) => u64; pub DataDM config(test_config) build(|_| vec![(15u32, 16u32, 42u64)]): double_map hasher(twox_64_concat) u32, blake2_256(u32) => u64;
pub GenericDataDM: double_map T::BlockNumber, twox_128(T::BlockNumber) => T::BlockNumber; pub GenericDataDM: double_map T::BlockNumber, twox_128(T::BlockNumber) => T::BlockNumber;
pub GenericData2DM: double_map T::BlockNumber, twox_256(T::BlockNumber) => Option<T::BlockNumber>; pub GenericData2DM: double_map T::BlockNumber, twox_256(T::BlockNumber) => Option<T::BlockNumber>;
} }
@@ -354,6 +354,7 @@ mod tests {
name: DecodeDifferent::Encode("Data"), name: DecodeDifferent::Encode("Data"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{ ty: StorageFunctionType::Map{
hasher: StorageHasher::Twox64Concat,
key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true key: DecodeDifferent::Encode("u32"), value: DecodeDifferent::Encode("u64"), is_linked: true
}, },
default: DecodeDifferent::Encode( default: DecodeDifferent::Encode(
@@ -365,6 +366,7 @@ mod tests {
name: DecodeDifferent::Encode("GenericData"), name: DecodeDifferent::Encode("GenericData"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map{ ty: StorageFunctionType::Map{
hasher: StorageHasher::Twox128,
key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true
}, },
default: DecodeDifferent::Encode( default: DecodeDifferent::Encode(
@@ -376,6 +378,7 @@ mod tests {
name: DecodeDifferent::Encode("GenericData2"), name: DecodeDifferent::Encode("GenericData2"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map{ ty: StorageFunctionType::Map{
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true key: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"), is_linked: true
}, },
default: DecodeDifferent::Encode( default: DecodeDifferent::Encode(
@@ -387,6 +390,7 @@ mod tests {
name: DecodeDifferent::Encode("DataDM"), name: DecodeDifferent::Encode("DataDM"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::DoubleMap{ ty: StorageFunctionType::DoubleMap{
hasher: StorageHasher::Twox64Concat,
key1: DecodeDifferent::Encode("u32"), key1: DecodeDifferent::Encode("u32"),
key2: DecodeDifferent::Encode("u32"), key2: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("u64"), value: DecodeDifferent::Encode("u64"),
@@ -401,6 +405,7 @@ mod tests {
name: DecodeDifferent::Encode("GenericDataDM"), name: DecodeDifferent::Encode("GenericDataDM"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::DoubleMap{ ty: StorageFunctionType::DoubleMap{
hasher: StorageHasher::Blake2_256,
key1: DecodeDifferent::Encode("T::BlockNumber"), key1: DecodeDifferent::Encode("T::BlockNumber"),
key2: DecodeDifferent::Encode("T::BlockNumber"), key2: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"),
@@ -415,6 +420,7 @@ mod tests {
name: DecodeDifferent::Encode("GenericData2DM"), name: DecodeDifferent::Encode("GenericData2DM"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::DoubleMap{ ty: StorageFunctionType::DoubleMap{
hasher: StorageHasher::Blake2_256,
key1: DecodeDifferent::Encode("T::BlockNumber"), key1: DecodeDifferent::Encode("T::BlockNumber"),
key2: DecodeDifferent::Encode("T::BlockNumber"), key2: DecodeDifferent::Encode("T::BlockNumber"),
value: DecodeDifferent::Encode("T::BlockNumber"), value: DecodeDifferent::Encode("T::BlockNumber"),
+9 -5
View File
@@ -16,10 +16,14 @@
pub use srml_metadata::{ pub use srml_metadata::{
DecodeDifferent, FnEncode, RuntimeMetadata, DecodeDifferent, FnEncode, RuntimeMetadata,
ModuleMetadata, RuntimeMetadataV3, ModuleMetadata, RuntimeMetadataV4,
DefaultByteGetter, RuntimeMetadataPrefixed, DefaultByteGetter, RuntimeMetadataPrefixed,
StorageMetadata, StorageFunctionMetadata,
StorageFunctionType, StorageFunctionModifier,
DefaultByte, StorageHasher
}; };
/// Implements the metadata support for the given runtime and all its modules. /// Implements the metadata support for the given runtime and all its modules.
/// ///
/// Example: /// Example:
@@ -36,8 +40,8 @@ macro_rules! impl_runtime_metadata {
) => { ) => {
impl $runtime { impl $runtime {
pub fn metadata() -> $crate::metadata::RuntimeMetadataPrefixed { pub fn metadata() -> $crate::metadata::RuntimeMetadataPrefixed {
$crate::metadata::RuntimeMetadata::V3 ( $crate::metadata::RuntimeMetadata::V4 (
$crate::metadata::RuntimeMetadataV3 { $crate::metadata::RuntimeMetadataV4 {
modules: $crate::__runtime_modules_to_metadata!($runtime;; $( $rest )*), modules: $crate::__runtime_modules_to_metadata!($runtime;; $( $rest )*),
} }
).into() ).into()
@@ -377,8 +381,8 @@ mod tests {
event_module2::Module with Event Storage Call, event_module2::Module with Event Storage Call,
); );
const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V3( const EXPECTED_METADATA: RuntimeMetadata = RuntimeMetadata::V4(
RuntimeMetadataV3 { RuntimeMetadataV4 {
modules: DecodeDifferent::Encode(&[ modules: DecodeDifferent::Encode(&[
ModuleMetadata { ModuleMetadata {
name: DecodeDifferent::Encode("system"), name: DecodeDifferent::Encode("system"),
@@ -0,0 +1,285 @@
// 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 <http://www.gnu.org/licenses/>.
//! Abstract storage to use on HashedStorage trait
use crate::codec;
use crate::rstd::prelude::{Vec, Box};
#[cfg(feature = "std")]
use crate::storage::unhashed::generator::UnhashedStorage;
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(twox128(key), key)`
pub struct Twox64Concat;
impl StorageHasher for Twox64Concat {
type Output = Vec<u8>;
fn hash(x: &[u8]) -> Vec<u8> {
twox_64(x)
.into_iter()
.chain(x.into_iter())
.cloned()
.collect::<Vec<_>>()
}
}
#[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<H: StorageHasher> {
/// 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<T: codec::Decode>(&self, key: &[u8]) -> Option<T>;
/// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if
/// it's not there.
fn require<T: codec::Decode>(&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<T: codec::Decode + Default>(&self, key: &[u8]) -> T {
self.get(key).unwrap_or_default()
}
/// Put a value in under a key.
fn put<T: codec::Encode>(&self, key: &[u8], val: &T);
/// Remove the bytes of a key from storage.
fn kill(&self, key: &[u8]);
/// Take a value from storage, deleting it after reading.
fn take<T: codec::Decode>(&self, key: &[u8]) -> Option<T> {
let value = self.get(key);
self.kill(key);
value
}
/// Take a value from storage, deleting it after reading.
fn take_or_panic<T: codec::Decode>(&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<T: codec::Decode + Default>(&self, key: &[u8]) -> T {
self.take(key).unwrap_or_default()
}
/// Get a Vec of bytes from storage.
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Put a raw byte slice into storage.
fn put_raw(&self, key: &[u8], value: &[u8]);
}
// We use a construct like this during when genesis storage is being built.
#[cfg(feature = "std")]
impl<H: StorageHasher> HashedStorage<H> for std::cell::RefCell<&mut sr_primitives::StorageOverlay> {
fn exists(&self, key: &[u8]) -> bool {
UnhashedStorage::exists(self, &H::hash(key).as_ref())
}
fn get<T: codec::Decode>(&self, key: &[u8]) -> Option<T> {
UnhashedStorage::get(self, &H::hash(key).as_ref())
}
fn put<T: codec::Encode>(&self, key: &[u8], val: &T) {
UnhashedStorage::put(self, &H::hash(key).as_ref(), val)
}
fn kill(&self, key: &[u8]) {
UnhashedStorage::kill(self, &H::hash(key).as_ref())
}
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> {
UnhashedStorage::get_raw(self, &H::hash(key).as_ref())
}
fn put_raw(&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<T: codec::Codec> {
/// The type that get/take returns.
type Query;
/// Get the storage key.
fn key() -> &'static [u8];
/// true if the value is defined in storage.
fn exists<S: HashedStorage<Twox128>>(storage: &S) -> bool {
storage.exists(Self::key())
}
/// Load the value from the provided storage instance.
fn get<S: HashedStorage<Twox128>>(storage: &S) -> Self::Query;
/// Take a value from storage, removing it afterwards.
fn take<S: HashedStorage<Twox128>>(storage: &S) -> Self::Query;
/// Store a value under this key into the provided storage instance.
fn put<S: HashedStorage<Twox128>>(val: &T, storage: &S) {
storage.put(Self::key(), val)
}
/// Mutate this value
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: HashedStorage<Twox128>>(f: F, storage: &S) -> R;
/// Clear the storage value.
fn kill<S: HashedStorage<Twox128>>(storage: &S) {
storage.kill(Self::key())
}
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<S: HashedStorage<Twox128>, I: codec::Encode>(
items: &[I], storage: &S
) -> Result<(), &'static str> where T: codec::EncodeAppend<Item=I> {
let new_val = <T as codec::EncodeAppend>::append(
storage.get_raw(Self::key()).unwrap_or_default(),
items,
).ok_or_else(|| "Could not append given item")?;
storage.put_raw(Self::key(), &new_val);
Ok(())
}
}
/// A strongly-typed list in storage.
pub trait StorageList<T: codec::Codec> {
/// Get the prefix key in storage.
fn prefix() -> &'static [u8];
/// Get the key used to put the length field.
fn len_key() -> Vec<u8>;
/// Get the storage key used to fetch a value at a given index.
fn key_for(index: u32) -> Vec<u8>;
/// Read out all the items.
fn items<S: HashedStorage<Twox128>>(storage: &S) -> Vec<T>;
/// Set the current set of items.
fn set_items<S: HashedStorage<Twox128>>(items: &[T], storage: &S);
/// Set the item at the given index.
fn set_item<S: HashedStorage<Twox128>>(index: u32, item: &T, storage: &S);
/// Load the value at given index. Returns `None` if the index is out-of-bounds.
fn get<S: HashedStorage<Twox128>>(index: u32, storage: &S) -> Option<T>;
/// Load the length of the list
fn len<S: HashedStorage<Twox128>>(storage: &S) -> u32;
/// Clear the list.
fn clear<S: HashedStorage<Twox128>>(storage: &S);
}
/// A strongly-typed map in storage.
pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
/// The type that get/take returns.
type Query;
type Hasher: StorageHasher;
/// 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<u8>;
/// true if the value is defined in storage.
fn exists<S: HashedStorage<Self::Hasher>>(key: &K, storage: &S) -> bool {
storage.exists(&Self::key_for(key)[..])
}
/// Load the value associated with the given key from the map.
fn get<S: HashedStorage<Self::Hasher>>(key: &K, storage: &S) -> Self::Query;
/// Take the value under a key.
fn take<S: HashedStorage<Self::Hasher>>(key: &K, storage: &S) -> Self::Query;
/// Store a value to be associated with the given key from the map.
fn insert<S: HashedStorage<Self::Hasher>>(key: &K, val: &V, storage: &S) {
storage.put(&Self::key_for(key)[..], val);
}
/// Remove the value under a key.
fn remove<S: HashedStorage<Self::Hasher>>(key: &K, storage: &S) {
storage.kill(&Self::key_for(key)[..]);
}
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: HashedStorage<Self::Hasher>>(key: &K, f: F, storage: &S) -> R;
}
/// A `StorageMap` with enumerable entries.
pub trait EnumerableStorageMap<K: codec::Codec, V: codec::Codec>: StorageMap<K, V> {
/// Return current head element.
fn head<S: HashedStorage<Self::Hasher>>(storage: &S) -> Option<K>;
/// Enumerate all elements in the map.
fn enumerate<'a, S: HashedStorage<Self::Hasher>>(storage: &'a S) -> Box<dyn Iterator<Item = (K, V)> + 'a> where K: 'a, V: 'a;
}
@@ -0,0 +1,223 @@
// 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 <http://www.gnu.org/licenses/>.
//! 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};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Decode + Sized, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> Option<T> {
unhashed::get(&hash(key).as_ref())
}
/// 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<T: Decode + Sized + Default, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> T {
unhashed::get_or_default(&hash(key).as_ref())
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Decode + Sized, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], default_value: T) -> T {
unhashed::get_or(&hash(key).as_ref(), 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: Decode + Sized, F: FnOnce() -> T, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], default_value: F) -> T {
unhashed::get_or_else(&hash(key).as_ref(), default_value)
}
/// Put `value` in storage under `key`.
pub fn put<T: Encode, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], value: &T) {
unhashed::put(&hash(key).as_ref(), value)
}
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
pub fn take<T: Decode + Sized, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> Option<T> {
unhashed::take(&hash(key).as_ref())
}
/// 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<T: Decode + Sized + Default, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> T {
unhashed::take_or_default(&hash(key).as_ref())
}
/// 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<T: Decode + Sized, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], default_value: T) -> T {
unhashed::take_or(&hash(key).as_ref(), 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: Decode + Sized, F: FnOnce() -> T, HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], default_value: F) -> T {
unhashed::take_or_else(&hash(key).as_ref(), default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists<HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> bool {
unhashed::exists(&hash(key).as_ref())
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill<HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) {
unhashed::kill(&hash(key).as_ref())
}
/// Get a Vec of bytes from storage.
pub fn get_raw<HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8]) -> Option<Vec<u8>> {
unhashed::get_raw(&hash(key).as_ref())
}
/// Put a raw byte slice into storage.
pub fn put_raw<HashFn: Fn(&[u8]) -> R, R: AsRef<[u8]>>(hash: &HashFn, key: &[u8], value: &[u8]) {
unhashed::put_raw(&hash(key).as_ref(), value)
}
/// A trait to conveniently store a vector of storable data.
///
/// It uses twox_128 hasher. Final keys in trie are `twox_128(concatenation(PREFIX,count))`
pub trait StorageVec {
type Item: Default + Sized + Codec;
const PREFIX: &'static [u8];
/// Get the current set of items.
fn items() -> Vec<Self::Item> {
(0..Self::count()).into_iter().map(Self::item).collect()
}
/// Set the current set of items.
fn set_items<I, T>(items: I)
where
I: IntoIterator<Item=T>,
T: Borrow<Self::Item>,
{
let mut count: u32 = 0;
for i in items.into_iter() {
put(&twox_128, &count.to_keyed_vec(Self::PREFIX), i.borrow());
count = count.checked_add(1).expect("exceeded runtime storage capacity");
}
Self::set_count(count);
}
/// Push an item.
fn push(item: &Self::Item) {
let len = Self::count();
put(&twox_128, &len.to_keyed_vec(Self::PREFIX), item);
Self::set_count(len + 1);
}
fn set_item(index: u32, item: &Self::Item) {
if index < Self::count() {
put(&twox_128, &index.to_keyed_vec(Self::PREFIX), item);
}
}
fn clear_item(index: u32) {
if index < Self::count() {
kill(&twox_128, &index.to_keyed_vec(Self::PREFIX));
}
}
fn item(index: u32) -> Self::Item {
get_or_default(&twox_128, &index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(Self::clear_item);
put(&twox_128, &b"len".to_keyed_vec(Self::PREFIX), &count);
}
fn count() -> u32 {
get_or_default(&twox_128, &b"len".to_keyed_vec(Self::PREFIX))
}
}
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{twox_128, TestExternalities, with_externalities};
#[test]
fn integers_can_be_stored() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
let x = 69u32;
put(&twox_128, b":test", &x);
let y: u32 = get(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
with_externalities(&mut t, || {
let x = 69426942i64;
put(&twox_128, b":test", &x);
let y: i64 = get(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn bools_can_be_stored() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
let x = true;
put(&twox_128, b":test", &x);
let y: bool = get(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
with_externalities(&mut t, || {
let x = false;
put(&twox_128, b":test", &x);
let y: bool = get(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn vecs_can_be_retrieved() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
runtime_io::set_storage(&twox_128(b":test"), b"\x2cHello world");
let x = b"Hello world".to_vec();
let y = get::<Vec<u8>, _, _>(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn vecs_can_be_stored() {
let mut t = TestExternalities::default();
let x = b"Hello world".to_vec();
with_externalities(&mut t, || {
put(&twox_128, b":test", &x);
});
with_externalities(&mut t, || {
let y: Vec<u8> = get(&twox_128, b":test").unwrap();
assert_eq!(x, y);
});
}
}
+27 -224
View File
@@ -18,12 +18,14 @@
use crate::rstd::prelude::*; use crate::rstd::prelude::*;
use crate::rstd::borrow::Borrow; use crate::rstd::borrow::Borrow;
use runtime_io::{self, twox_128}; use codec::{Codec, Encode, Decode, KeyedVec, Input, EncodeAppend};
use crate::codec::{Codec, Encode, Decode, KeyedVec, Input, EncodeAppend}; use hashed::generator::{HashedStorage, StorageHasher};
use unhashed::generator::UnhashedStorage;
#[macro_use] #[macro_use]
pub mod generator; pub mod storage_items;
pub mod unhashed; pub mod unhashed;
pub mod hashed;
struct IncrementalInput<'a> { struct IncrementalInput<'a> {
key: &'a [u8], key: &'a [u8],
@@ -54,116 +56,44 @@ impl<'a> Input for IncrementalChildInput<'a> {
} }
} }
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Decode + Sized>(key: &[u8]) -> Option<T> {
unhashed::get(&twox_128(key))
}
/// 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<T: Decode + Sized + Default>(key: &[u8]) -> T {
unhashed::get_or_default(&twox_128(key))
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Decode + Sized>(key: &[u8], default_value: T) -> T {
unhashed::get_or(&twox_128(key), 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: Decode + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
unhashed::get_or_else(&twox_128(key), default_value)
}
/// Put `value` in storage under `key`.
pub fn put<T: Encode>(key: &[u8], value: &T) {
unhashed::put(&twox_128(key), value)
}
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
pub fn take<T: Decode + Sized>(key: &[u8]) -> Option<T> {
unhashed::take(&twox_128(key))
}
/// 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<T: Decode + Sized + Default>(key: &[u8]) -> T {
unhashed::take_or_default(&twox_128(key))
}
/// 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<T: Decode + Sized>(key: &[u8], default_value: T) -> T {
unhashed::take_or(&twox_128(key), 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: Decode + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
unhashed::take_or_else(&twox_128(key), default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
unhashed::exists(&twox_128(key))
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) {
unhashed::kill(&twox_128(key))
}
/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
unhashed::get_raw(&twox_128(key))
}
/// Put a raw byte slice into storage.
pub fn put_raw(key: &[u8], value: &[u8]) {
unhashed::put_raw(&twox_128(key), value)
}
/// The underlying runtime storage. /// The underlying runtime storage.
pub struct RuntimeStorage; pub struct RuntimeStorage;
impl crate::GenericStorage for RuntimeStorage { impl<H: StorageHasher> HashedStorage<H> for RuntimeStorage {
fn exists(&self, key: &[u8]) -> bool { fn exists(&self, key: &[u8]) -> bool {
exists(key) hashed::exists(&H::hash, key)
} }
/// Load the bytes of a key from storage. Can panic if the type is incorrect. /// Load the bytes of a key from storage. Can panic if the type is incorrect.
fn get<T: Decode>(&self, key: &[u8]) -> Option<T> { fn get<T: Decode>(&self, key: &[u8]) -> Option<T> {
get(key) hashed::get(&H::hash, key)
} }
/// Put a value in under a key. /// Put a value in under a key.
fn put<T: Encode>(&self, key: &[u8], val: &T) { fn put<T: Encode>(&self, key: &[u8], val: &T) {
put(key, val) hashed::put(&H::hash, key, val)
} }
/// Remove the bytes of a key from storage. /// Remove the bytes of a key from storage.
fn kill(&self, key: &[u8]) { fn kill(&self, key: &[u8]) {
kill(key) hashed::kill(&H::hash, key)
} }
/// Take a value from storage, deleting it after reading. /// Take a value from storage, deleting it after reading.
fn take<T: Decode>(&self, key: &[u8]) -> Option<T> { fn take<T: Decode>(&self, key: &[u8]) -> Option<T> {
take(key) hashed::take(&H::hash, key)
} }
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> { fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> {
get_raw(key) hashed::get_raw(&H::hash, key)
} }
fn put_raw(&self, key: &[u8], value: &[u8]) { fn put_raw(&self, key: &[u8], value: &[u8]) {
put_raw(key, value) hashed::put_raw(&H::hash, key, value)
} }
} }
impl crate::GenericUnhashedStorage for RuntimeStorage { impl UnhashedStorage for RuntimeStorage {
fn exists(&self, key: &[u8]) -> bool { fn exists(&self, key: &[u8]) -> bool {
unhashed::exists(key) unhashed::exists(key)
} }
@@ -235,11 +165,11 @@ pub trait StorageValue<T: Codec> {
where T: EncodeAppend<Item=I>; where T: EncodeAppend<Item=I>;
} }
impl<T: Codec, U> StorageValue<T> for U where U: generator::StorageValue<T> { impl<T: Codec, U> StorageValue<T> for U where U: hashed::generator::StorageValue<T> {
type Query = U::Query; type Query = U::Query;
fn key() -> &'static [u8] { fn key() -> &'static [u8] {
<U as generator::StorageValue<T>>::key() <U as hashed::generator::StorageValue<T>>::key()
} }
fn exists() -> bool { fn exists() -> bool {
U::exists(&RuntimeStorage) U::exists(&RuntimeStorage)
@@ -296,17 +226,17 @@ pub trait StorageList<T: Codec> {
fn clear(); fn clear();
} }
impl<T: Codec, U> StorageList<T> for U where U: generator::StorageList<T> { impl<T: Codec, U> StorageList<T> for U where U: hashed::generator::StorageList<T> {
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
<U as generator::StorageList<T>>::prefix() <U as hashed::generator::StorageList<T>>::prefix()
} }
fn len_key() -> Vec<u8> { fn len_key() -> Vec<u8> {
<U as generator::StorageList<T>>::len_key() <U as hashed::generator::StorageList<T>>::len_key()
} }
fn key_for(index: u32) -> Vec<u8> { fn key_for(index: u32) -> Vec<u8> {
<U as generator::StorageList<T>>::key_for(index) <U as hashed::generator::StorageList<T>>::key_for(index)
} }
fn items() -> Vec<T> { fn items() -> Vec<T> {
@@ -364,15 +294,15 @@ pub trait StorageMap<K: Codec, V: Codec> {
fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query; fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query;
} }
impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: generator::StorageMap<K, V> { impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: hashed::generator::StorageMap<K, V> {
type Query = U::Query; type Query = U::Query;
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
<U as generator::StorageMap<K, V>>::prefix() <U as hashed::generator::StorageMap<K, V>>::prefix()
} }
fn key_for<KeyArg: Borrow<K>>(key: KeyArg) -> Vec<u8> { fn key_for<KeyArg: Borrow<K>>(key: KeyArg) -> Vec<u8> {
<U as generator::StorageMap<K, V>>::key_for(key.borrow()) <U as hashed::generator::StorageMap<K, V>>::key_for(key.borrow())
} }
fn exists<KeyArg: Borrow<K>>(key: KeyArg) -> bool { fn exists<KeyArg: Borrow<K>>(key: KeyArg) -> bool {
@@ -412,13 +342,13 @@ pub trait EnumerableStorageMap<K: Codec, V: Codec>: StorageMap<K, V> {
fn enumerate() -> Box<dyn Iterator<Item = (K, V)>> where K: 'static, V: 'static; fn enumerate() -> Box<dyn Iterator<Item = (K, V)>> where K: 'static, V: 'static;
} }
impl<K: Codec, V: Codec, U> EnumerableStorageMap<K, V> for U where U: generator::EnumerableStorageMap<K, V> { impl<K: Codec, V: Codec, U> EnumerableStorageMap<K, V> for U where U: hashed::generator::EnumerableStorageMap<K, V> {
fn head() -> Option<K> { fn head() -> Option<K> {
<U as generator::EnumerableStorageMap<K, V>>::head(&RuntimeStorage) <U as hashed::generator::EnumerableStorageMap<K, V>>::head(&RuntimeStorage)
} }
fn enumerate() -> Box<dyn Iterator<Item = (K, V)>> where K: 'static, V: 'static { fn enumerate() -> Box<dyn Iterator<Item = (K, V)>> where K: 'static, V: 'static {
<U as generator::EnumerableStorageMap<K, V>>::enumerate(&RuntimeStorage) <U as hashed::generator::EnumerableStorageMap<K, V>>::enumerate(&RuntimeStorage)
} }
} }
@@ -525,72 +455,13 @@ where
} }
} }
/// A trait to conveniently store a vector of storable data.
pub trait StorageVec {
type Item: Default + Sized + Codec;
const PREFIX: &'static [u8];
/// Get the current set of items.
fn items() -> Vec<Self::Item> {
(0..Self::count()).into_iter().map(Self::item).collect()
}
/// Set the current set of items.
fn set_items<I, T>(items: I)
where
I: IntoIterator<Item=T>,
T: Borrow<Self::Item>,
{
let mut count: u32 = 0;
for i in items.into_iter() {
put(&count.to_keyed_vec(Self::PREFIX), i.borrow());
count = count.checked_add(1).expect("exceeded runtime storage capacity");
}
Self::set_count(count);
}
/// Push an item.
fn push(item: &Self::Item) {
let len = Self::count();
put(&len.to_keyed_vec(Self::PREFIX), item);
Self::set_count(len + 1);
}
fn set_item(index: u32, item: &Self::Item) {
if index < Self::count() {
put(&index.to_keyed_vec(Self::PREFIX), item);
}
}
fn clear_item(index: u32) {
if index < Self::count() {
kill(&index.to_keyed_vec(Self::PREFIX));
}
}
fn item(index: u32) -> Self::Item {
get_or_default(&index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(Self::clear_item);
put(&b"len".to_keyed_vec(Self::PREFIX), &count);
}
fn count() -> u32 {
get_or_default(&b"len".to_keyed_vec(Self::PREFIX))
}
}
/// child storage NOTE could replace unhashed by having only one kind of storage (root being null storage /// child storage NOTE could replace unhashed by having only one kind of storage (root being null storage
/// key (storage_key can become Option<&[u8]>). /// key (storage_key can become Option<&[u8]>).
/// This module is a currently only a variant of unhashed with additional `storage_key`. /// 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 /// 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)). /// avoid collision from a resistant hash function (which unique implies)).
pub mod child { pub mod child {
use super::{runtime_io, Codec, Decode, Vec, IncrementalChildInput}; use super::{Codec, Decode, Vec, IncrementalChildInput};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry. /// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Codec + Sized>(storage_key: &[u8], key: &[u8]) -> Option<T> { pub fn get<T: Codec + Sized>(storage_key: &[u8], key: &[u8]) -> Option<T> {
@@ -681,71 +552,3 @@ pub mod child {
pub use super::unhashed::StorageVec; pub use super::unhashed::StorageVec;
} }
#[cfg(test)]
mod tests {
use super::*;
use runtime_io::{twox_128, TestExternalities, with_externalities};
#[test]
fn integers_can_be_stored() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
let x = 69u32;
put(b":test", &x);
let y: u32 = get(b":test").unwrap();
assert_eq!(x, y);
});
with_externalities(&mut t, || {
let x = 69426942i64;
put(b":test", &x);
let y: i64 = get(b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn bools_can_be_stored() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
let x = true;
put(b":test", &x);
let y: bool = get(b":test").unwrap();
assert_eq!(x, y);
});
with_externalities(&mut t, || {
let x = false;
put(b":test", &x);
let y: bool = get(b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn vecs_can_be_retrieved() {
let mut t = TestExternalities::default();
with_externalities(&mut t, || {
runtime_io::set_storage(&twox_128(b":test"), b"\x2cHello world");
let x = b"Hello world".to_vec();
let y = get::<Vec<u8>>(b":test").unwrap();
assert_eq!(x, y);
});
}
#[test]
fn vecs_can_be_stored() {
let mut t = TestExternalities::default();
let x = b"Hello world".to_vec();
with_externalities(&mut t, || {
put(b":test", &x);
});
with_externalities(&mut t, || {
let y: Vec<u8> = get(b":test").unwrap();
assert_eq!(x, y);
});
}
}
@@ -46,10 +46,6 @@
//!# fn main() { } //!# fn main() { }
//! ``` //! ```
use crate::codec;
use crate::rstd::vec::Vec;
#[cfg(feature = "std")]
use crate::storage::unhashed::generator::UnhashedStorage;
#[doc(hidden)] #[doc(hidden)]
pub use crate::rstd::borrow::Borrow; pub use crate::rstd::borrow::Borrow;
#[doc(hidden)] #[doc(hidden)]
@@ -57,204 +53,6 @@ pub use crate::rstd::marker::PhantomData;
#[doc(hidden)] #[doc(hidden)]
pub use crate::rstd::boxed::Box; pub use crate::rstd::boxed::Box;
pub use srml_metadata::{
DecodeDifferent, StorageMetadata, StorageFunctionMetadata,
StorageFunctionType, StorageFunctionModifier,
DefaultByte, DefaultByteGetter,
};
/// Abstraction around storage.
pub trait Storage {
/// 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<T: codec::Decode>(&self, key: &[u8]) -> Option<T>;
/// Load the bytes of a key from storage. Can panic if the type is incorrect. Will panic if
/// it's not there.
fn require<T: codec::Decode>(&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<T: codec::Decode + Default>(&self, key: &[u8]) -> T { self.get(key).unwrap_or_default() }
/// Put a value in under a key.
fn put<T: codec::Encode>(&self, key: &[u8], val: &T);
/// Remove the bytes of a key from storage.
fn kill(&self, key: &[u8]);
/// Take a value from storage, deleting it after reading.
fn take<T: codec::Decode>(&self, key: &[u8]) -> Option<T> {
let value = self.get(key);
self.kill(key);
value
}
/// Take a value from storage, deleting it after reading.
fn take_or_panic<T: codec::Decode>(&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<T: codec::Decode + Default>(&self, key: &[u8]) -> T { self.take(key).unwrap_or_default() }
/// Get a Vec of bytes from storage.
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>>;
/// Put a raw byte slice into storage.
fn put_raw(&self, key: &[u8], value: &[u8]);
}
// We use a construct like this during when genesis storage is being built.
#[cfg(feature = "std")]
impl<S: sr_primitives::BuildStorage> Storage for (crate::rstd::cell::RefCell<&mut sr_primitives::StorageOverlay>, PhantomData<S>) {
fn exists(&self, key: &[u8]) -> bool {
UnhashedStorage::exists(self, &S::hash(key))
}
fn get<T: codec::Decode>(&self, key: &[u8]) -> Option<T> {
UnhashedStorage::get(self, &S::hash(key))
}
fn put<T: codec::Encode>(&self, key: &[u8], val: &T) {
UnhashedStorage::put(self, &S::hash(key), val)
}
fn kill(&self, key: &[u8]) {
UnhashedStorage::kill(self, &S::hash(key))
}
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> {
UnhashedStorage::get_raw(self, key)
}
fn put_raw(&self, key: &[u8], value: &[u8]) {
UnhashedStorage::put_raw(self, key, value)
}
}
/// A strongly-typed value kept in storage.
pub trait StorageValue<T: codec::Codec> {
/// The type that get/take returns.
type Query;
/// Get the storage key.
fn key() -> &'static [u8];
/// true if the value is defined in storage.
fn exists<S: Storage>(storage: &S) -> bool {
storage.exists(Self::key())
}
/// Load the value from the provided storage instance.
fn get<S: Storage>(storage: &S) -> Self::Query;
/// Take a value from storage, removing it afterwards.
fn take<S: Storage>(storage: &S) -> Self::Query;
/// Store a value under this key into the provided storage instance.
fn put<S: Storage>(val: &T, storage: &S) {
storage.put(Self::key(), val)
}
/// Mutate this value
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(f: F, storage: &S) -> R;
/// Clear the storage value.
fn kill<S: Storage>(storage: &S) {
storage.kill(Self::key())
}
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<S: Storage, I: codec::Encode>(
items: &[I], storage: &S
) -> Result<(), &'static str> where T: codec::EncodeAppend<Item=I> {
let new_val = <T as codec::EncodeAppend>::append(
storage.get_raw(Self::key()).unwrap_or_default(),
items,
).ok_or_else(|| "Could not append given item")?;
storage.put_raw(Self::key(), &new_val);
Ok(())
}
}
/// A strongly-typed list in storage.
pub trait StorageList<T: codec::Codec> {
/// Get the prefix key in storage.
fn prefix() -> &'static [u8];
/// Get the key used to put the length field.
fn len_key() -> Vec<u8>;
/// Get the storage key used to fetch a value at a given index.
fn key_for(index: u32) -> Vec<u8>;
/// Read out all the items.
fn items<S: Storage>(storage: &S) -> Vec<T>;
/// Set the current set of items.
fn set_items<S: Storage>(items: &[T], storage: &S);
/// Set the item at the given index.
fn set_item<S: Storage>(index: u32, item: &T, storage: &S);
/// Load the value at given index. Returns `None` if the index is out-of-bounds.
fn get<S: Storage>(index: u32, storage: &S) -> Option<T>;
/// Load the length of the list
fn len<S: Storage>(storage: &S) -> u32;
/// Clear the list.
fn clear<S: Storage>(storage: &S);
}
/// A strongly-typed map in storage.
pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
/// 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(x: &K) -> Vec<u8>;
/// true if the value is defined in storage.
fn exists<S: Storage>(key: &K, storage: &S) -> bool {
storage.exists(&Self::key_for(key)[..])
}
/// Load the value associated with the given key from the map.
fn get<S: Storage>(key: &K, storage: &S) -> Self::Query;
/// Take the value under a key.
fn take<S: Storage>(key: &K, storage: &S) -> Self::Query;
/// Store a value to be associated with the given key from the map.
fn insert<S: Storage>(key: &K, val: &V, storage: &S) {
storage.put(&Self::key_for(key)[..], val);
}
/// Remove the value under a key.
fn remove<S: Storage>(key: &K, storage: &S) {
storage.kill(&Self::key_for(key)[..]);
}
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: Storage>(key: &K, f: F, storage: &S) -> R;
}
/// A `StorageMap` with enumerable entries.
pub trait EnumerableStorageMap<K: codec::Codec, V: codec::Codec>: StorageMap<K, V> {
/// Return current head element.
fn head<S: Storage>(storage: &S) -> Option<K>;
/// Enumerate all elements in the map.
fn enumerate<'a, S: Storage>(storage: &'a S) -> Box<dyn Iterator<Item = (K, V)> + 'a> where K: 'a, V: 'a;
}
// FIXME #1466 Remove this in favor of `decl_storage` macro. // FIXME #1466 Remove this in favor of `decl_storage` macro.
/// Declares strongly-typed wrappers around codec-compatible types in storage. /// Declares strongly-typed wrappers around codec-compatible types in storage.
#[macro_export] #[macro_export]
@@ -380,12 +178,12 @@ macro_rules! __storage_items_internal {
// generator for values. // generator for values.
(($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { (($($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 } $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $key => $ty }
pub fn $get_fn() -> $gettype { <$name as $crate::storage::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) } pub fn $get_fn() -> $gettype { <$name as $crate::storage::hashed::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) }
}; };
(($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
$($vis)* struct $name; $($vis)* struct $name;
impl $crate::storage::generator::StorageValue<$ty> for $name { impl $crate::storage::hashed::generator::StorageValue<$ty> for $name {
type Query = $gettype; type Query = $gettype;
/// Get the storage key. /// Get the storage key.
@@ -394,29 +192,29 @@ macro_rules! __storage_items_internal {
} }
/// Load the value from the provided storage instance. /// Load the value from the provided storage instance.
fn get<S: $crate::GenericStorage>(storage: &S) -> Self::Query { fn get<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> Self::Query {
storage.$getter($key) storage.$getter($key)
} }
/// Take a value from storage, removing it afterwards. /// Take a value from storage, removing it afterwards.
fn take<S: $crate::GenericStorage>(storage: &S) -> Self::Query { fn take<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> Self::Query {
storage.$taker($key) storage.$taker($key)
} }
/// Mutate this value. /// Mutate this value.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::HashedStorage<$crate::Twox128>>(f: F, storage: &S) -> R {
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage); let mut val = <Self as $crate::storage::hashed::generator::StorageValue<$ty>>::get(storage);
let ret = f(&mut val); let ret = f(&mut val);
$crate::__handle_wrap_internal!($wraptype { $crate::__handle_wrap_internal!($wraptype {
// raw type case // raw type case
<Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage) <Self as $crate::storage::hashed::generator::StorageValue<$ty>>::put(&val, storage)
} { } {
// Option<> type case // Option<> type case
match val { match val {
Some(ref val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage), Some(ref val) => <Self as $crate::storage::hashed::generator::StorageValue<$ty>>::put(&val, storage),
None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage), None => <Self as $crate::storage::hashed::generator::StorageValue<$ty>>::kill(storage),
} }
}); });
@@ -428,15 +226,17 @@ macro_rules! __storage_items_internal {
(($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { (($($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] } $crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] }
pub fn $get_fn<K: $crate::storage::generator::Borrow<$kty>>(key: K) -> $gettype { pub fn $get_fn<K: $crate::storage::generator::Borrow<$kty>>(key: K) -> $gettype {
<$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage)
} }
}; };
(($($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) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => {
$($vis)* struct $name; $($vis)* struct $name;
impl $crate::storage::generator::StorageMap<$kty, $ty> for $name { impl $crate::storage::hashed::generator::StorageMap<$kty, $ty> for $name {
type Query = $gettype; type Query = $gettype;
type Hasher = $crate::Blake2_256;
/// Get the prefix key in storage. /// Get the prefix key in storage.
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
$prefix $prefix
@@ -450,31 +250,31 @@ macro_rules! __storage_items_internal {
} }
/// Load the value associated with the given key from the map. /// Load the value associated with the given key from the map.
fn get<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query { fn get<S: $crate::HashedStorage<Self::Hasher>>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key);
storage.$getter(&key[..]) storage.$getter(&key[..])
} }
/// Take the value, reading and removing it. /// Take the value, reading and removing it.
fn take<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query { fn take<S: $crate::HashedStorage<Self::Hasher>>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key);
storage.$taker(&key[..]) storage.$taker(&key[..])
} }
/// Mutate the value under a key. /// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) -> R { fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::HashedStorage<Self::Hasher>>(key: &$kty, f: F, storage: &S) -> R {
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage); let mut val = <Self as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::take(key, storage);
let ret = f(&mut val); let ret = f(&mut val);
$crate::__handle_wrap_internal!($wraptype { $crate::__handle_wrap_internal!($wraptype {
// raw type case // raw type case
<Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage) <Self as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage)
} { } {
// Option<> type case // Option<> type case
match val { match val {
Some(ref val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage), Some(ref val) => <Self as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage), None => <Self as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::remove(key, storage),
} }
}); });
@@ -487,19 +287,19 @@ macro_rules! __storage_items_internal {
$($vis)* struct $name; $($vis)* struct $name;
impl $name { impl $name {
fn clear_item<S: $crate::GenericStorage>(index: u32, storage: &S) { fn clear_item<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, storage: &S) {
if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { if index < <$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage) {
storage.kill(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)); storage.kill(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::key_for(index));
} }
} }
fn set_len<S: $crate::GenericStorage>(count: u32, storage: &S) { fn set_len<S: $crate::HashedStorage<$crate::Twox128>>(count: u32, storage: &S) {
(count..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage)).for_each(|i| $name::clear_item(i, storage)); (count..<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage)).for_each(|i| $name::clear_item(i, storage));
storage.put(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key(), &count); storage.put(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len_key(), &count);
} }
} }
impl $crate::storage::generator::StorageList<$ty> for $name { impl $crate::storage::hashed::generator::StorageList<$ty> for $name {
/// Get the prefix key in storage. /// Get the prefix key in storage.
fn prefix() -> &'static [u8] { fn prefix() -> &'static [u8] {
$prefix $prefix
@@ -520,43 +320,43 @@ macro_rules! __storage_items_internal {
} }
/// Read out all the items. /// Read out all the items.
fn items<S: $crate::GenericStorage>(storage: &S) -> $crate::rstd::vec::Vec<$ty> { fn items<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> $crate::rstd::vec::Vec<$ty> {
(0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage)) (0..<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage))
.map(|i| <$name as $crate::storage::generator::StorageList<$ty>>::get(i, storage).expect("all items within length are set; qed")) .map(|i| <$name as $crate::storage::hashed::generator::StorageList<$ty>>::get(i, storage).expect("all items within length are set; qed"))
.collect() .collect()
} }
/// Set the current set of items. /// Set the current set of items.
fn set_items<S: $crate::GenericStorage>(items: &[$ty], storage: &S) { fn set_items<S: $crate::HashedStorage<$crate::Twox128>>(items: &[$ty], storage: &S) {
$name::set_len(items.len() as u32, storage); $name::set_len(items.len() as u32, storage);
items.iter() items.iter()
.enumerate() .enumerate()
.for_each(|(i, item)| <$name as $crate::storage::generator::StorageList<$ty>>::set_item(i as u32, item, storage)); .for_each(|(i, item)| <$name as $crate::storage::hashed::generator::StorageList<$ty>>::set_item(i as u32, item, storage));
} }
fn set_item<S: $crate::GenericStorage>(index: u32, item: &$ty, storage: &S) { fn set_item<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, item: &$ty, storage: &S) {
if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { if index < <$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage) {
storage.put(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..], item); storage.put(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::key_for(index)[..], item);
} }
} }
/// Load the value at given index. Returns `None` if the index is out-of-bounds. /// Load the value at given index. Returns `None` if the index is out-of-bounds.
fn get<S: $crate::GenericStorage>(index: u32, storage: &S) -> Option<$ty> { fn get<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, storage: &S) -> Option<$ty> {
storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..]) storage.get(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::key_for(index)[..])
} }
/// Load the length of the list. /// Load the length of the list.
fn len<S: $crate::GenericStorage>(storage: &S) -> u32 { fn len<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> u32 {
storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key()).unwrap_or_default() storage.get(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len_key()).unwrap_or_default()
} }
/// Clear the list. /// Clear the list.
fn clear<S: $crate::GenericStorage>(storage: &S) { fn clear<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) {
for i in 0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage) { for i in 0..<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage) {
$name::clear_item(i, storage); $name::clear_item(i, storage);
} }
storage.kill(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key()[..]) storage.kill(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len_key()[..])
} }
} }
}; };
@@ -584,35 +384,11 @@ macro_rules! __handle_wrap_internal {
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use std::cell::RefCell; use std::cell::RefCell;
use codec::{Decode, Encode};
use super::*; use super::*;
use crate::metadata::*;
use crate::metadata::StorageHasher;
use crate::rstd::marker::PhantomData; use crate::rstd::marker::PhantomData;
use crate::storage::hashed::generator::*;
impl Storage for RefCell<HashMap<Vec<u8>, Vec<u8>>> {
fn exists(&self, key: &[u8]) -> bool {
self.borrow_mut().get(key).is_some()
}
fn get<T: Decode>(&self, key: &[u8]) -> Option<T> {
self.borrow_mut().get(key).map(|v| T::decode(&mut &v[..]).unwrap())
}
fn put<T: Encode>(&self, key: &[u8], val: &T) {
self.borrow_mut().insert(key.to_owned(), val.encode());
}
fn kill(&self, key: &[u8]) {
self.borrow_mut().remove(key);
}
fn put_raw(&self, key: &[u8], value: &[u8]) {
self.borrow_mut().insert(key.to_owned(), value.to_owned());
}
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> {
self.borrow().get(key).cloned()
}
}
storage_items! { storage_items! {
Value: b"a" => u32; Value: b"a" => u32;
@@ -622,7 +398,8 @@ mod tests {
#[test] #[test]
fn value() { fn value() {
let storage = RefCell::new(HashMap::new()); let mut overlay = HashMap::new();
let storage = RefCell::new(&mut overlay);
assert!(Value::get(&storage).is_none()); assert!(Value::get(&storage).is_none());
Value::put(&100_000, &storage); Value::put(&100_000, &storage);
assert_eq!(Value::get(&storage), Some(100_000)); assert_eq!(Value::get(&storage), Some(100_000));
@@ -632,7 +409,8 @@ mod tests {
#[test] #[test]
fn list() { fn list() {
let storage = RefCell::new(HashMap::new()); let mut overlay = HashMap::new();
let storage = RefCell::new(&mut overlay);
assert_eq!(List::len(&storage), 0); assert_eq!(List::len(&storage), 0);
assert!(List::items(&storage).is_empty()); assert!(List::items(&storage).is_empty());
@@ -651,7 +429,8 @@ mod tests {
#[test] #[test]
fn map() { fn map() {
let storage = RefCell::new(HashMap::new()); let mut overlay = HashMap::new();
let storage = RefCell::new(&mut overlay);
assert!(Map::get(&5, &storage).is_none()); assert!(Map::get(&5, &storage).is_none());
Map::insert(&5, &[1; 32], &storage); Map::insert(&5, &[1; 32], &storage);
assert_eq!(Map::get(&5, &storage), Some([1; 32])); assert_eq!(Map::get(&5, &storage), Some([1; 32]));
@@ -661,7 +440,7 @@ mod tests {
} }
pub trait Trait { pub trait Trait {
type Origin: codec::Encode + codec::Decode + ::std::default::Default; type Origin: crate::codec::Encode + crate::codec::Decode + ::std::default::Default;
type BlockNumber; type BlockNumber;
} }
@@ -850,6 +629,7 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32"), name: DecodeDifferent::Encode("MAPU32"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -863,6 +643,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32"), name: DecodeDifferent::Encode("PUBMAPU32"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -876,6 +657,7 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32MYDEF"), name: DecodeDifferent::Encode("MAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -889,6 +671,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32MYDEF"), name: DecodeDifferent::Encode("PUBMAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -902,6 +685,7 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32"), name: DecodeDifferent::Encode("GETMAPU32"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -915,6 +699,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32"), name: DecodeDifferent::Encode("PUBGETMAPU32"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -928,6 +713,7 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32MYDEF"), name: DecodeDifferent::Encode("GETMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -941,6 +727,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"), name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: false, is_linked: false,
@@ -954,6 +741,7 @@ mod tests {
name: DecodeDifferent::Encode("LINKEDMAPU32"), name: DecodeDifferent::Encode("LINKEDMAPU32"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: true, is_linked: true,
@@ -967,6 +755,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"), name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional, modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: true, is_linked: true,
@@ -980,6 +769,7 @@ mod tests {
name: DecodeDifferent::Encode("GETLINKEDMAPU32"), name: DecodeDifferent::Encode("GETLINKEDMAPU32"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: true, is_linked: true,
@@ -993,6 +783,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"), name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default, modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map { ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"), key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"), value: DecodeDifferent::Encode("String"),
is_linked: true, is_linked: true,
@@ -15,7 +15,6 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::codec; use crate::codec;
use runtime_io::twox_128;
use crate::rstd::vec::Vec; use crate::rstd::vec::Vec;
/// Abstraction around storage with unhashed access. /// Abstraction around storage with unhashed access.
@@ -65,36 +64,36 @@ pub trait UnhashedStorage {
// We use a construct like this during when genesis storage is being built. // We use a construct like this during when genesis storage is being built.
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<H> UnhashedStorage for (crate::rstd::cell::RefCell<&mut sr_primitives::StorageOverlay>, H) { impl UnhashedStorage for std::cell::RefCell<&mut sr_primitives::StorageOverlay> {
fn exists(&self, key: &[u8]) -> bool { fn exists(&self, key: &[u8]) -> bool {
self.0.borrow().contains_key(key) self.borrow().contains_key(key)
} }
fn get<T: codec::Decode>(&self, key: &[u8]) -> Option<T> { fn get<T: codec::Decode>(&self, key: &[u8]) -> Option<T> {
self.0.borrow().get(key) self.borrow().get(key)
.map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type.")) .map(|x| codec::Decode::decode(&mut x.as_slice()).expect("Unable to decode expected type."))
} }
fn put<T: codec::Encode>(&self, key: &[u8], val: &T) { fn put<T: codec::Encode>(&self, key: &[u8], val: &T) {
self.0.borrow_mut().insert(key.to_vec(), codec::Encode::encode(val)); self.borrow_mut().insert(key.to_vec(), codec::Encode::encode(val));
} }
fn kill(&self, key: &[u8]) { fn kill(&self, key: &[u8]) {
self.0.borrow_mut().remove(key); self.borrow_mut().remove(key);
} }
fn kill_prefix(&self, prefix: &[u8]) { fn kill_prefix(&self, prefix: &[u8]) {
self.0.borrow_mut().retain(|key, _| { self.borrow_mut().retain(|key, _| {
!key.starts_with(prefix) !key.starts_with(prefix)
}) })
} }
fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> { fn get_raw(&self, key: &[u8]) -> Option<Vec<u8>> {
self.0.borrow().get(key).cloned() self.borrow().get(key).cloned()
} }
fn put_raw(&self, key: &[u8], value: &[u8]) { fn put_raw(&self, key: &[u8], value: &[u8]) {
self.0.borrow_mut().insert(key.to_vec(), value.to_vec()); self.borrow_mut().insert(key.to_vec(), value.to_vec());
} }
} }
@@ -121,11 +120,7 @@ pub trait StorageDoubleMap<K1: codec::Codec, K2: codec::Codec, V: codec::Codec>
fn key_for(k1: &K1, k2: &K2) -> Vec<u8>; fn key_for(k1: &K1, k2: &K2) -> Vec<u8>;
/// Get the storage prefix used to fetch keys corresponding to a specific key1. /// Get the storage prefix used to fetch keys corresponding to a specific key1.
fn prefix_for(k1: &K1) -> Vec<u8> { fn prefix_for(k1: &K1) -> Vec<u8>;
let mut key = Self::prefix().to_vec();
codec::Encode::encode_to(k1, &mut key);
twox_128(&key).to_vec()
}
/// true if the value is defined in storage. /// true if the value is defined in storage.
fn exists<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &S) -> bool { fn exists<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &S) -> bool {
@@ -17,7 +17,7 @@
//! Operation on unhashed runtime storage //! Operation on unhashed runtime storage
use crate::rstd::borrow::Borrow; use crate::rstd::borrow::Borrow;
use super::{runtime_io, Codec, Encode, Decode, KeyedVec, Vec, IncrementalInput}; use super::{Codec, Encode, Decode, KeyedVec, Vec, IncrementalInput};
pub mod generator; pub mod generator;