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
@@ -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::borrow::Borrow;
use runtime_io::{self, twox_128};
use crate::codec::{Codec, Encode, Decode, KeyedVec, Input, EncodeAppend};
use codec::{Codec, Encode, Decode, KeyedVec, Input, EncodeAppend};
use hashed::generator::{HashedStorage, StorageHasher};
use unhashed::generator::UnhashedStorage;
#[macro_use]
pub mod generator;
pub mod storage_items;
pub mod unhashed;
pub mod hashed;
struct IncrementalInput<'a> {
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.
pub struct RuntimeStorage;
impl crate::GenericStorage for RuntimeStorage {
impl<H: StorageHasher> HashedStorage<H> for RuntimeStorage {
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.
fn get<T: Decode>(&self, key: &[u8]) -> Option<T> {
get(key)
hashed::get(&H::hash, key)
}
/// Put a value in under a key.
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.
fn kill(&self, key: &[u8]) {
kill(key)
hashed::kill(&H::hash, key)
}
/// Take a value from storage, deleting it after reading.
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>> {
get_raw(key)
hashed::get_raw(&H::hash, key)
}
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 {
unhashed::exists(key)
}
@@ -235,11 +165,11 @@ pub trait StorageValue<T: Codec> {
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;
fn key() -> &'static [u8] {
<U as generator::StorageValue<T>>::key()
<U as hashed::generator::StorageValue<T>>::key()
}
fn exists() -> bool {
U::exists(&RuntimeStorage)
@@ -296,17 +226,17 @@ pub trait StorageList<T: Codec> {
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] {
<U as generator::StorageList<T>>::prefix()
<U as hashed::generator::StorageList<T>>::prefix()
}
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> {
<U as generator::StorageList<T>>::key_for(index)
<U as hashed::generator::StorageList<T>>::key_for(index)
}
fn items() -> Vec<T> {
@@ -364,15 +294,15 @@ pub trait StorageMap<K: Codec, V: Codec> {
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;
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> {
<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 {
@@ -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;
}
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> {
<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 {
<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
/// key (storage_key can become Option<&[u8]>).
/// This module is a currently only a variant of unhashed with additional `storage_key`.
/// Note that `storage_key` must be unique and strong (strong in the sense of being long enough to
/// avoid collision from a resistant hash function (which unique implies)).
pub mod child {
use super::{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.
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;
}
#[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() { }
//! ```
use crate::codec;
use crate::rstd::vec::Vec;
#[cfg(feature = "std")]
use crate::storage::unhashed::generator::UnhashedStorage;
#[doc(hidden)]
pub use crate::rstd::borrow::Borrow;
#[doc(hidden)]
@@ -57,204 +53,6 @@ pub use crate::rstd::marker::PhantomData;
#[doc(hidden)]
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.
/// Declares strongly-typed wrappers around codec-compatible types in storage.
#[macro_export]
@@ -380,12 +178,12 @@ macro_rules! __storage_items_internal {
// generator for values.
(($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
$crate::__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $key => $ty }
pub fn $get_fn() -> $gettype { <$name as $crate::storage::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)* struct $name;
impl $crate::storage::generator::StorageValue<$ty> for $name {
impl $crate::storage::hashed::generator::StorageValue<$ty> for $name {
type Query = $gettype;
/// Get the storage key.
@@ -394,29 +192,29 @@ macro_rules! __storage_items_internal {
}
/// 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)
}
/// 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)
}
/// Mutate this value.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(f: F, storage: &S) -> R {
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage);
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::hashed::generator::StorageValue<$ty>>::get(storage);
let ret = f(&mut val);
$crate::__handle_wrap_internal!($wraptype {
// 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
match val {
Some(ref val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage),
None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage),
Some(ref val) => <Self as $crate::storage::hashed::generator::StorageValue<$ty>>::put(&val, 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]) => {
$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 {
<$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)* 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 Hasher = $crate::Blake2_256;
/// Get the prefix key in storage.
fn prefix() -> &'static [u8] {
$prefix
@@ -450,31 +250,31 @@ macro_rules! __storage_items_internal {
}
/// Load the value associated with the given key from the map.
fn get<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key);
fn get<S: $crate::HashedStorage<Self::Hasher>>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key);
storage.$getter(&key[..])
}
/// Take the value, reading and removing it.
fn take<S: $crate::GenericStorage>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key);
fn take<S: $crate::HashedStorage<Self::Hasher>>(key: &$kty, storage: &S) -> Self::Query {
let key = <$name as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::key_for(key);
storage.$taker(&key[..])
}
/// Mutate the value under a key.
fn mutate<R, F: FnOnce(&mut Self::Query) -> R, S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) -> R {
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage);
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::hashed::generator::StorageMap<$kty, $ty>>::take(key, storage);
let ret = f(&mut val);
$crate::__handle_wrap_internal!($wraptype {
// 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
match val {
Some(ref val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage),
Some(ref val) => <Self as $crate::storage::hashed::generator::StorageMap<$kty, $ty>>::insert(key, &val, 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;
impl $name {
fn clear_item<S: $crate::GenericStorage>(index: u32, storage: &S) {
if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) {
storage.kill(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index));
fn clear_item<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, storage: &S) {
if index < <$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage) {
storage.kill(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::key_for(index));
}
}
fn set_len<S: $crate::GenericStorage>(count: u32, storage: &S) {
(count..<$name as $crate::storage::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);
fn set_len<S: $crate::HashedStorage<$crate::Twox128>>(count: u32, storage: &S) {
(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::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.
fn prefix() -> &'static [u8] {
$prefix
@@ -520,43 +320,43 @@ macro_rules! __storage_items_internal {
}
/// Read out all the items.
fn items<S: $crate::GenericStorage>(storage: &S) -> $crate::rstd::vec::Vec<$ty> {
(0..<$name as $crate::storage::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"))
fn items<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> $crate::rstd::vec::Vec<$ty> {
(0..<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage))
.map(|i| <$name as $crate::storage::hashed::generator::StorageList<$ty>>::get(i, storage).expect("all items within length are set; qed"))
.collect()
}
/// 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);
items.iter()
.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) {
if index < <$name as $crate::storage::generator::StorageList<$ty>>::len(storage) {
storage.put(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..], item);
fn set_item<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, item: &$ty, storage: &S) {
if index < <$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(storage) {
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.
fn get<S: $crate::GenericStorage>(index: u32, storage: &S) -> Option<$ty> {
storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::key_for(index)[..])
fn get<S: $crate::HashedStorage<$crate::Twox128>>(index: u32, storage: &S) -> Option<$ty> {
storage.get(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::key_for(index)[..])
}
/// Load the length of the list.
fn len<S: $crate::GenericStorage>(storage: &S) -> u32 {
storage.get(&<$name as $crate::storage::generator::StorageList<$ty>>::len_key()).unwrap_or_default()
fn len<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) -> u32 {
storage.get(&<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len_key()).unwrap_or_default()
}
/// Clear the list.
fn clear<S: $crate::GenericStorage>(storage: &S) {
for i in 0..<$name as $crate::storage::generator::StorageList<$ty>>::len(storage) {
fn clear<S: $crate::HashedStorage<$crate::Twox128>>(storage: &S) {
for i in 0..<$name as $crate::storage::hashed::generator::StorageList<$ty>>::len(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 {
use std::collections::HashMap;
use std::cell::RefCell;
use codec::{Decode, Encode};
use super::*;
use crate::metadata::*;
use crate::metadata::StorageHasher;
use crate::rstd::marker::PhantomData;
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()
}
}
use crate::storage::hashed::generator::*;
storage_items! {
Value: b"a" => u32;
@@ -622,7 +398,8 @@ mod tests {
#[test]
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());
Value::put(&100_000, &storage);
assert_eq!(Value::get(&storage), Some(100_000));
@@ -632,7 +409,8 @@ mod tests {
#[test]
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!(List::items(&storage).is_empty());
@@ -651,7 +429,8 @@ mod tests {
#[test]
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());
Map::insert(&5, &[1; 32], &storage);
assert_eq!(Map::get(&5, &storage), Some([1; 32]));
@@ -661,7 +440,7 @@ mod tests {
}
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;
}
@@ -850,6 +629,7 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -863,6 +643,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -876,6 +657,7 @@ mod tests {
name: DecodeDifferent::Encode("MAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -889,6 +671,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBMAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -902,6 +685,7 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -915,6 +699,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -928,6 +713,7 @@ mod tests {
name: DecodeDifferent::Encode("GETMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -941,6 +727,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: false,
@@ -954,6 +741,7 @@ mod tests {
name: DecodeDifferent::Encode("LINKEDMAPU32"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
@@ -967,6 +755,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBLINKEDMAPU32MYDEF"),
modifier: StorageFunctionModifier::Optional,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
@@ -980,6 +769,7 @@ mod tests {
name: DecodeDifferent::Encode("GETLINKEDMAPU32"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
@@ -993,6 +783,7 @@ mod tests {
name: DecodeDifferent::Encode("PUBGETLINKEDMAPU32MYDEF"),
modifier: StorageFunctionModifier::Default,
ty: StorageFunctionType::Map {
hasher: StorageHasher::Blake2_256,
key: DecodeDifferent::Encode("u32"),
value: DecodeDifferent::Encode("String"),
is_linked: true,
@@ -15,7 +15,6 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::codec;
use runtime_io::twox_128;
use crate::rstd::vec::Vec;
/// 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.
#[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 {
self.0.borrow().contains_key(key)
self.borrow().contains_key(key)
}
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."))
}
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]) {
self.0.borrow_mut().remove(key);
self.borrow_mut().remove(key);
}
fn kill_prefix(&self, prefix: &[u8]) {
self.0.borrow_mut().retain(|key, _| {
self.borrow_mut().retain(|key, _| {
!key.starts_with(prefix)
})
}
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]) {
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>;
/// Get the storage prefix used to fetch keys corresponding to a specific key1.
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()
}
fn prefix_for(k1: &K1) -> Vec<u8>;
/// true if the value is defined in storage.
fn exists<S: UnhashedStorage>(k1: &K1, k2: &K2, storage: &S) -> bool {
@@ -17,7 +17,7 @@
//! Operation on unhashed runtime storage
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;