Rename Palette to FRAME (#4182)

* palette -> frame

* PALETTE, Palette -> FRAME

* Move folder pallete -> frame

* Update docs/Structure.adoc

Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com>

* Update docs/README.adoc

Co-Authored-By: Benjamin Kampmann <ben.kampmann@googlemail.com>

* Update README.adoc
This commit is contained in:
Shawn Tabrizi
2019-11-22 19:21:25 +01:00
committed by GitHub
parent 68351da29b
commit c9175b59ff
206 changed files with 485 additions and 483 deletions
@@ -0,0 +1,119 @@
// 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 child storages.
//!
//! This module is a currently only a variant of unhashed with additional `storage_key`.
//! Note that `storage_key` must be unique and strong (strong in the sense of being long enough to
//! avoid collision from a resistant hash function (which unique implies)).
// NOTE: could replace unhashed by having only one kind of storage (root being null storage key (storage_key can become Option<&[u8]>).
use crate::rstd::prelude::*;
use codec::{Codec, Encode, Decode};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T: Decode + Sized>(storage_key: &[u8], key: &[u8]) -> Option<T> {
runtime_io::storage::child_get(storage_key, key).and_then(|v| {
Decode::decode(&mut &v[..]).map(Some).unwrap_or_else(|_| {
// TODO #3700: error should be handleable.
runtime_print!("ERROR: Corrupted state in child trie at {:?}/{:?}", storage_key, key);
None
})
})
}
/// 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>(storage_key: &[u8], key: &[u8]) -> T {
get(storage_key, key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Decode + Sized>(storage_key: &[u8], key: &[u8], default_value: T) -> T {
get(storage_key, key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry.
pub fn get_or_else<T: Decode + Sized, F: FnOnce() -> T>(
storage_key: &[u8],
key: &[u8],
default_value: F,
) -> T {
get(storage_key, key).unwrap_or_else(default_value)
}
/// Put `value` in storage under `key`.
pub fn put<T: Encode>(storage_key: &[u8], key: &[u8], value: &T) {
value.using_encoded(|slice| runtime_io::storage::child_set(storage_key, key, slice));
}
/// Remove `key` from storage, returning its value if it had an explicit entry or `None` otherwise.
pub fn take<T: Decode + Sized>(storage_key: &[u8], key: &[u8]) -> Option<T> {
let r = get(storage_key, key);
if r.is_some() {
kill(storage_key, key);
}
r
}
/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage,
/// the default for its type.
pub fn take_or_default<T: Codec + Sized + Default>(storage_key: &[u8], key: &[u8]) -> T {
take(storage_key, key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or<T: Codec + Sized>(storage_key: &[u8],key: &[u8], default_value: T) -> T {
take(storage_key, key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or_else<T: Codec + Sized, F: FnOnce() -> T>(
storage_key: &[u8],
key: &[u8],
default_value: F,
) -> T {
take(storage_key, key).unwrap_or_else(default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(storage_key: &[u8], key: &[u8]) -> bool {
runtime_io::storage::child_read(storage_key, key, &mut [0;0][..], 0).is_some()
}
/// Remove all `storage_key` key/values
pub fn kill_storage(storage_key: &[u8]) {
runtime_io::storage::child_storage_kill(storage_key)
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(storage_key: &[u8], key: &[u8]) {
runtime_io::storage::child_clear(storage_key, key);
}
/// Get a Vec of bytes from storage.
pub fn get_raw(storage_key: &[u8], key: &[u8]) -> Option<Vec<u8>> {
runtime_io::storage::child_get(storage_key, key)
}
/// Put a raw byte slice into storage.
pub fn put_raw(storage_key: &[u8], key: &[u8], value: &[u8]) {
runtime_io::storage::child_set(storage_key, key, value)
}
@@ -0,0 +1,215 @@
// 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/>.
use rstd::prelude::*;
use rstd::borrow::Borrow;
use codec::{Ref, FullCodec, FullEncode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::StorageHasher};
/// Generator for `StorageDoubleMap` used by `decl_storage`.
///
/// # Mapping of keys to a storage path
///
/// The storage key (i.e. the key under which the `Value` will be stored) is created from two parts.
/// The first part is a hash of a concatenation of the `key1_prefix` and `Key1`. And the second part
/// is a hash of a `Key2`.
///
/// Thus value for (key1, key2) is stored at:
/// ```nocompile
/// Hasher1(key1_prefix ++ key1) ++ Hasher2(key2)
/// ```
///
/// # Warning
///
/// If the key1s are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
/// `blake2_256` must be used for Hasher1. Otherwise, other values in storage can be compromised.
/// If the key2s are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
/// `blake2_256` must be used for Hasher2. Otherwise, other items in storage with the same first
/// key can be compromised.
pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// The type that get/take returns.
type Query;
/// Hasher for the first key.
type Hasher1: StorageHasher;
/// Hasher for the second key.
type Hasher2: StorageHasher;
/// Get the prefix for first key.
fn key1_prefix() -> &'static [u8];
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
/// Convert a query to an optional value into storage.
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the first part of the key used in top storage.
fn storage_double_map_final_key1<KArg1>(k1: KArg1) -> <Self::Hasher1 as StorageHasher>::Output
where
KArg1: EncodeLike<K1>,
{
let mut final_key1 = Self::key1_prefix().to_vec();
k1.encode_to(&mut final_key1);
Self::Hasher1::hash(&final_key1)
}
/// Generate the full key used in top storage.
fn storage_double_map_final_key<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
let mut final_key = Self::storage_double_map_final_key1(k1).as_ref().to_vec();
final_key.extend_from_slice(k2.using_encoded(Self::Hasher2::hash).as_ref());
final_key
}
}
impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G
where
K1: FullEncode,
K2: FullEncode,
V: FullCodec,
G: StorageDoubleMap<K1, K2, V>,
{
type Query = G::Query;
fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
Self::storage_double_map_final_key(k1, k2)
}
fn exists<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> bool
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
unhashed::exists(&Self::storage_double_map_final_key(k1, k2))
}
fn get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
G::from_optional_value_to_query(unhashed::get(&Self::storage_double_map_final_key(k1, k2)))
}
fn take<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
let final_key = Self::storage_double_map_final_key(k1, k2);
let value = unhashed::take(&final_key);
G::from_optional_value_to_query(value)
}
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
VArg: EncodeLike<V>,
{
unhashed::put(&Self::storage_double_map_final_key(k1, k2), &val.borrow())
}
fn remove<KArg1, KArg2>(k1: KArg1, k2: KArg2)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
unhashed::kill(&Self::storage_double_map_final_key(k1, k2))
}
fn remove_prefix<KArg1>(k1: KArg1) where KArg1: EncodeLike<K1> {
unhashed::kill_prefix(Self::storage_double_map_final_key1(k1).as_ref())
}
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
F: FnOnce(&mut Self::Query) -> R,
{
let final_key = Self::storage_double_map_final_key(k1, k2);
let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref()));
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => unhashed::put(final_key.as_ref(), val),
None => unhashed::kill(final_key.as_ref()),
}
ret
}
fn append<Items, Item, EncodeLikeItem, KArg1, KArg2>(
k1: KArg1,
k2: KArg2,
items: Items,
) -> Result<(), &'static str>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator
{
let final_key = Self::storage_double_map_final_key(k1, k2);
let encoded_value = unhashed::get_raw(&final_key)
.unwrap_or_else(|| {
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
Some(value) => value.encode(),
None => vec![],
}
});
let new_val = V::append_or_new(
encoded_value,
items,
).map_err(|_| "Could not append given item")?;
unhashed::put_raw(&final_key, &new_val);
Ok(())
}
fn append_or_insert<Items, Item, EncodeLikeItem, KArg1, KArg2>(
k1: KArg1,
k2: KArg2,
items: Items,
)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
Items::IntoIter: ExactSizeIterator
{
Self::append(Ref::from(&k1), Ref::from(&k2), items.clone())
.unwrap_or_else(|_| Self::insert(k1, k2, items));
}
}
@@ -0,0 +1,497 @@
// 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/>.
use codec::{FullCodec, Encode, Decode, EncodeLike, Ref};
use crate::{storage::{self, unhashed}, hash::StorageHasher, traits::Len};
use rstd::marker::PhantomData;
/// Generator for `StorageLinkedMap` used by `decl_storage`.
///
/// # Mapping of keys to a storage path
///
/// The key for the head of the map is stored at one fixed path:
/// ```nocompile
/// Hasher(head_key)
/// ```
///
/// For each key, the value stored under that key is appended with a
/// [`Linkage`](struct.Linkage.html) (which hold previous and next key) at the path:
/// ```nocompile
/// Hasher(prefix ++ key)
/// ```
///
/// Enumeration is done by getting the head of the linked map and then iterating getting the
/// value and linkage stored at the key until the found linkage has no next key.
///
/// # Warning
///
/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
/// `blake2_256` must be used. Otherwise, other values in storage can be compromised.
pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> {
/// The type that get/take returns.
type Query;
/// Hasher used to insert into storage.
type Hasher: StorageHasher;
/// The family of key formats used for this map.
type KeyFormat: KeyFormat<Hasher=Self::Hasher>;
/// Prefix used to prepend each key.
fn prefix() -> &'static [u8];
/// The head key of the linked-map.
fn head_key() -> &'static [u8] {
<Self::KeyFormat as KeyFormat>::head_key()
}
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
/// Convert a query to an optional value into storage.
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the full key used in top storage.
fn storage_linked_map_final_key<KeyArg>(key: KeyArg) -> <Self::Hasher as StorageHasher>::Output
where
KeyArg: EncodeLike<K>,
{
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(Self::prefix(), &key)
}
/// Generate the hashed key for head
fn storage_linked_map_final_head_key() -> <Self::Hasher as StorageHasher>::Output {
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_head_key()
}
}
/// A type-abstracted key format used for a family of linked-map types.
pub trait KeyFormat {
type Hasher: StorageHasher;
/// Key used to store linked map head.
fn head_key() -> &'static [u8];
/// Generate the full key used in top storage.
fn storage_linked_map_final_key<K>(prefix: &[u8], key: &K)
-> <Self::Hasher as StorageHasher>::Output
where
K: Encode,
{
let mut final_key = prefix.to_vec();
key.encode_to(&mut final_key);
<Self::Hasher as StorageHasher>::hash(&final_key)
}
fn storage_linked_map_final_head_key()
-> <Self::Hasher as StorageHasher>::Output
{
<Self::Hasher as StorageHasher>::hash(Self::head_key())
}
}
/// Linkage data of an element (it's successor and predecessor)
#[derive(Encode, Decode)]
pub struct Linkage<Key> {
/// Previous element key in storage (None for the first element)
pub previous: Option<Key>,
/// Next element key in storage (None for the last element)
pub next: Option<Key>,
}
impl<Key> Default for Linkage<Key> {
fn default() -> Self {
Self {
previous: None,
next: None,
}
}
}
// Encode like a linkage.
#[derive(Encode)]
struct EncodeLikeLinkage<PKey: EncodeLike<Key>, NKey: EncodeLike<Key>, Key: Encode> {
// Previous element key in storage (None for the first element)
previous: Option<PKey>,
// Next element key in storage (None for the last element)
next: Option<NKey>,
// The key of the linkage this type encode to
phantom: core::marker::PhantomData<Key>,
}
/// A key-value pair iterator for enumerable map.
pub struct Enumerator<K, V, F> {
next: Option<K>,
prefix: &'static [u8],
_phantom: PhantomData<(V, F)>,
}
impl<K, V, F> Enumerator<K, V, F> {
/// Create an explicit enumerator for testing.
#[cfg(test)]
pub fn from_head(head: K, prefix: &'static [u8]) -> Self {
Enumerator {
next: Some(head),
prefix,
_phantom: Default::default(),
}
}
}
impl<K, V, F> Iterator for Enumerator<K, V, F>
where
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
let next = self.next.take()?;
let (val, linkage): (V, Linkage<K>) = {
let next_full_key = F::storage_linked_map_final_key(self.prefix, &next);
match read_with_linkage::<K, V>(next_full_key.as_ref()) {
Some(value) => value,
None => {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map head_key={:?}: \
next value doesn't exist at {:?}",
F::head_key(), next_full_key.as_ref(),
);
return None
}
}
};
self.next = linkage.next;
Some((next, val))
}
}
/// Update linkage when this element is removed.
///
/// Takes care of updating previous and next elements points
/// as well as updates head if the element is first or last.
fn remove_linkage<K, V, F>(linkage: Linkage<K>, prefix: &[u8])
where
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
let next_key = linkage.next.as_ref()
.map(|k| F::storage_linked_map_final_key(prefix, k))
.map(|x| x.as_ref().to_vec());
let prev_key = linkage.previous.as_ref()
.map(|k| F::storage_linked_map_final_key(prefix, k))
.map(|x| x.as_ref().to_vec());
if let Some(prev_key) = prev_key {
// Retrieve previous element and update `next`
if let Some(mut res) = read_with_linkage::<K, V>(prev_key.as_ref()) {
res.1.next = linkage.next;
unhashed::put(prev_key.as_ref(), &res);
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map head_key={:?}: \
previous value doesn't exist at {:?}",
F::head_key(), prev_key,
);
}
} else {
// we were first so let's update the head
write_head::<&K, K, F>(linkage.next.as_ref());
}
if let Some(next_key) = next_key {
// Update previous of next element
if let Some(mut res) = read_with_linkage::<K, V>(next_key.as_ref()) {
res.1.previous = linkage.previous;
unhashed::put(next_key.as_ref(), &res);
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map head_key={:?}: \
next value doesn't exist at {:?}",
F::head_key(), next_key,
);
}
}
}
/// Read the contained data and its linkage.
pub(super) fn read_with_linkage<K, V>(key: &[u8]) -> Option<(V, Linkage<K>)>
where
K: Decode,
V: Decode,
{
unhashed::get(key)
}
/// Generate linkage for newly inserted element.
///
/// Takes care of updating head and previous head's pointer.
pub(super) fn new_head_linkage<KeyArg, K, V, F>(key: KeyArg, prefix: &[u8]) -> Linkage<K>
where
KeyArg: EncodeLike<K>,
K: FullCodec,
V: FullCodec,
F: KeyFormat,
{
if let Some(head) = read_head::<K, F>() {
// update previous head predecessor
{
let head_key = F::storage_linked_map_final_key(prefix, &head);
if let Some((data, linkage)) = read_with_linkage::<K, V>(head_key.as_ref()) {
let new_linkage = EncodeLikeLinkage::<_, _, K> {
previous: Some(Ref::from(&key)),
next: linkage.next.as_ref(),
phantom: Default::default(),
};
unhashed::put(head_key.as_ref(), &(data, new_linkage));
} else {
// TODO #3700: error should be handleable.
runtime_print!(
"ERROR: Corrupted state: linked map head_key={:?}: \
head value doesn't exist at {:?}",
F::head_key(), head_key.as_ref(),
);
// Thus we consider we are first - update the head and produce empty linkage
write_head::<_, _, F>(Some(key));
return Linkage::default();
}
}
// update to current head
write_head::<_, _, F>(Some(key));
// return linkage with pointer to previous head
let mut linkage = Linkage::default();
linkage.next = Some(head);
linkage
} else {
// we are first - update the head and produce empty linkage
write_head::<_, _, F>(Some(key));
Linkage::default()
}
}
/// Read current head pointer.
pub(crate) fn read_head<K, F>() -> Option<K>
where
K: Decode,
F: KeyFormat,
{
unhashed::get(F::storage_linked_map_final_head_key().as_ref())
}
/// Overwrite current head pointer.
///
/// If `None` is given head is removed from storage.
pub(super) fn write_head<KeyArg, K, F>(head: Option<KeyArg>)
where
KeyArg: EncodeLike<K>,
K: FullCodec,
F: KeyFormat,
{
match head.as_ref() {
Some(head) => unhashed::put(F::storage_linked_map_final_head_key().as_ref(), head),
None => unhashed::kill(F::storage_linked_map_final_head_key().as_ref()),
}
}
impl<K, V, G> storage::StorageLinkedMap<K, V> for G
where
K: FullCodec,
V: FullCodec,
G: StorageLinkedMap<K, V>,
{
type Query = G::Query;
type Enumerator = Enumerator<K, V, G::KeyFormat>;
fn exists<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool {
unhashed::exists(Self::storage_linked_map_final_key(key).as_ref())
}
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
let val = unhashed::get(Self::storage_linked_map_final_key(key).as_ref());
G::from_optional_value_to_query(val)
}
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) {
let prefix = Self::prefix();
let final_key1 = Self::storage_linked_map_final_key(Ref::from(&key1));
let final_key2 = Self::storage_linked_map_final_key(Ref::from(&key2));
let full_value_1 = read_with_linkage::<K, V>(final_key1.as_ref());
let full_value_2 = read_with_linkage::<K, V>(final_key2.as_ref());
match (full_value_1, full_value_2) {
// Just keep linkage in order and only swap values.
(Some((value1, linkage1)), Some((value2, linkage2))) => {
unhashed::put(final_key1.as_ref(), &(value2, linkage1));
unhashed::put(final_key2.as_ref(), &(value1, linkage2));
}
// Remove key and insert the new one.
(Some((value, _linkage)), None) => {
Self::remove(key1);
let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key2, prefix);
unhashed::put(final_key2.as_ref(), &(value, linkage));
}
// Remove key and insert the new one.
(None, Some((value, _linkage))) => {
Self::remove(key2);
let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key1, prefix);
unhashed::put(final_key1.as_ref(), &(value, linkage));
}
// No-op.
(None, None) => (),
}
}
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg) {
let final_key = Self::storage_linked_map_final_key(Ref::from(&key));
let linkage = match read_with_linkage::<_, V>(final_key.as_ref()) {
// overwrite but reuse existing linkage
Some((_data, linkage)) => linkage,
// create new linkage
None => new_head_linkage::<_, _, V, G::KeyFormat>(key, Self::prefix()),
};
unhashed::put(final_key.as_ref(), &(val, linkage))
}
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg) {
G::take(key);
}
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R {
let final_key = Self::storage_linked_map_final_key(Ref::from(&key));
let (mut val, _linkage) = read_with_linkage::<K, V>(final_key.as_ref())
.map(|(data, linkage)| (G::from_optional_value_to_query(Some(data)), Some(linkage)))
.unwrap_or_else(|| (G::from_optional_value_to_query(None), None));
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => G::insert(key, val),
None => G::remove(key),
}
ret
}
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
let final_key = Self::storage_linked_map_final_key(key);
let full_value: Option<(V, Linkage<K>)> = unhashed::take(final_key.as_ref());
let value = full_value.map(|(data, linkage)| {
remove_linkage::<K, V, G::KeyFormat>(linkage, Self::prefix());
data
});
G::from_optional_value_to_query(value)
}
fn enumerate() -> Self::Enumerator {
Enumerator::<_, _, G::KeyFormat> {
next: read_head::<_, G::KeyFormat>(),
prefix: Self::prefix(),
_phantom: Default::default(),
}
}
fn head() -> Option<K> {
read_head::<_, G::KeyFormat>()
}
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len
{
let key = Self::storage_linked_map_final_key(key);
if let Some(v) = unhashed::get_raw(key.as_ref()) {
<V as codec::DecodeLength>::len(&v).map_err(|e| e.what())
} else {
let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None))
.map(|v| v.len())
.unwrap_or(0);
Ok(len)
}
}
fn translate<K2, V2, TK, TV>(translate_key: TK, translate_val: TV) -> Result<(), Option<K2>>
where K2: FullCodec + Clone, V2: Decode, TK: Fn(K2) -> K, TV: Fn(V2) -> V
{
let head_key = read_head::<K2, G::KeyFormat>().ok_or(None)?;
let prefix = G::prefix();
let mut last_key = None;
let mut current_key = head_key.clone();
write_head::<&K, K, G::KeyFormat>(Some(&translate_key(head_key)));
let translate_linkage = |old: Linkage<K2>| -> Linkage<K> {
Linkage {
previous: old.previous.map(&translate_key),
next: old.next.map(&translate_key),
}
};
loop {
let old_raw_key = G::KeyFormat::storage_linked_map_final_key(prefix, &current_key);
let x = unhashed::take(old_raw_key.as_ref());
let (val, linkage): (V2, Linkage<K2>) = match x {
Some(v) => v,
None => {
// we failed to read value and linkage. Update the last key's linkage
// to end the map early, since it's impossible to iterate further.
if let Some(last_key) = last_key {
let last_raw_key = G::storage_linked_map_final_key(&last_key);
if let Some((val, mut linkage))
= read_with_linkage::<K, V>(last_raw_key.as_ref())
{
// defensive: should always happen, since it was just written
// in the last iteration of the loop.
linkage.next = None;
unhashed::put(last_raw_key.as_ref(), &(&val, &linkage));
}
}
return Err(Some(current_key));
}
};
let next = linkage.next.clone();
let val = translate_val(val);
let linkage = translate_linkage(linkage);
// and write in the value and linkage under the new key.
let new_key = translate_key(current_key.clone());
let new_raw_key = G::storage_linked_map_final_key(&new_key);
unhashed::put(new_raw_key.as_ref(), &(&val, &linkage));
match next {
None => break,
Some(next) => {
last_key = Some(new_key);
current_key = next
},
}
}
Ok(())
}
}
@@ -0,0 +1,172 @@
// 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/>.
#[cfg(not(feature = "std"))]
use rstd::prelude::*;
use rstd::borrow::Borrow;
use codec::{FullCodec, FullEncode, Encode, EncodeLike, Ref, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::StorageHasher, traits::Len};
/// Generator for `StorageMap` used by `decl_storage`.
///
/// For each key value is stored at:
/// ```nocompile
/// Hasher(prefix ++ key)
/// ```
///
/// # Warning
///
/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
/// `blake2_256` must be used. Otherwise, other values in storage can be compromised.
pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// The type that get/take returns.
type Query;
/// Hasher used to insert into storage.
type Hasher: StorageHasher;
/// Prefix used to prepend each key.
fn prefix() -> &'static [u8];
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
/// Convert a query to an optional value into storage.
fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
/// Generate the full key used in top storage.
fn storage_map_final_key<KeyArg>(key: KeyArg) -> <Self::Hasher as StorageHasher>::Output
where
KeyArg: EncodeLike<K>,
{
let mut final_key = Self::prefix().to_vec();
key.borrow().encode_to(&mut final_key);
Self::Hasher::hash(&final_key)
}
}
impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V> for G {
type Query = G::Query;
fn hashed_key_for<KeyArg: EncodeLike<K>>(key: KeyArg) -> Vec<u8> {
Self::storage_map_final_key(key).as_ref().to_vec()
}
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) {
let k1 = Self::storage_map_final_key(key1);
let k2 = Self::storage_map_final_key(key2);
let v1 = unhashed::get_raw(k1.as_ref());
if let Some(val) = unhashed::get_raw(k2.as_ref()) {
unhashed::put_raw(k1.as_ref(), &val);
} else {
unhashed::kill(k1.as_ref())
}
if let Some(val) = v1 {
unhashed::put_raw(k2.as_ref(), &val);
} else {
unhashed::kill(k2.as_ref())
}
}
fn exists<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool {
unhashed::exists(Self::storage_map_final_key(key).as_ref())
}
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
G::from_optional_value_to_query(unhashed::get(Self::storage_map_final_key(key).as_ref()))
}
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg) {
unhashed::put(Self::storage_map_final_key(key).as_ref(), &val.borrow())
}
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg) {
unhashed::kill(Self::storage_map_final_key(key).as_ref())
}
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R {
let final_key = Self::storage_map_final_key(key);
let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref()));
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => unhashed::put(final_key.as_ref(), &val.borrow()),
None => unhashed::kill(final_key.as_ref()),
}
ret
}
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
let key = Self::storage_map_final_key(key);
let value = unhashed::take(key.as_ref());
G::from_optional_value_to_query(value)
}
fn append<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) -> Result<(), &'static str>
where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator,
{
let key = Self::storage_map_final_key(key);
let encoded_value = unhashed::get_raw(key.as_ref())
.unwrap_or_else(|| {
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
Some(value) => value.encode(),
None => vec![],
}
});
let new_val = V::append_or_new(
encoded_value,
items,
).map_err(|_| "Could not append given item")?;
unhashed::put_raw(key.as_ref(), &new_val);
Ok(())
}
fn append_or_insert<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items)
where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
Items::IntoIter: ExactSizeIterator,
{
Self::append(Ref::from(&key), items.clone())
.unwrap_or_else(|_| Self::insert(key, items));
}
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len
{
let key = Self::storage_map_final_key(key);
if let Some(v) = unhashed::get_raw(key.as_ref()) {
<V as codec::DecodeLength>::len(&v).map_err(|e| e.what())
} else {
let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None))
.map(|v| v.len())
.unwrap_or(0);
Ok(len)
}
}
}
@@ -0,0 +1,132 @@
// 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/>.
//! Generators are a set of trait on which storage traits are implemented.
//!
//! (i.e. implementing the generator for StorageValue on a type will automatically derive the
//! implementation of StorageValue for this type).
//!
//! They are used by `decl_storage`.
mod linked_map;
mod map;
mod double_map;
mod value;
pub use linked_map::{StorageLinkedMap, Enumerator, Linkage, KeyFormat as LinkedMapKeyFormat};
pub use map::StorageMap;
pub use double_map::StorageDoubleMap;
pub use value::StorageValue;
#[cfg(test)]
#[allow(dead_code)]
mod tests {
use runtime_io::TestExternalities;
use codec::{Encode, Decode};
use crate::storage::{unhashed, generator::{StorageValue, StorageLinkedMap}};
struct Runtime {}
pub trait Trait {
type Origin;
type BlockNumber;
}
impl Trait for Runtime {
type Origin = u32;
type BlockNumber = u32;
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {}
}
#[derive(Encode, Decode, Clone, Debug, Eq, PartialEq)]
struct NumberNumber {
a: u32,
b: u32,
}
crate::decl_storage! {
trait Store for Module<T: Trait> as Runtime {
Value get(fn value) config(): (u64, u64);
NumberMap: linked_map NumberNumber => u64;
}
}
#[test]
fn value_translate_works() {
let t = GenesisConfig::default().build_storage().unwrap();
TestExternalities::new(t).execute_with(|| {
// put the old value `1111u32` in the storage.
let key = Value::storage_value_final_key();
unhashed::put_raw(&key, &1111u32.encode());
// translate
let translate_fn = |old: Option<u32>| -> Option<(u64, u64)> {
old.map(|o| (o.into(), (o*2).into()))
};
let _ = Value::translate(translate_fn);
// new storage should be `(1111, 1111 * 2)`
assert_eq!(Value::get(), (1111, 2222));
})
}
#[test]
fn linked_map_translate_works() {
use super::linked_map::{self, Enumerator, KeyFormat};
type Format = <NumberMap as StorageLinkedMap<NumberNumber, u64>>::KeyFormat;
let t = GenesisConfig::default().build_storage().unwrap();
TestExternalities::new(t).execute_with(|| {
let prefix = NumberMap::prefix();
// start with a map of u32 -> u32.
for i in 0u32..100u32 {
let final_key = <Format as KeyFormat>::storage_linked_map_final_key(
prefix, &i,
);
let linkage = linked_map::new_head_linkage::<_, u32, u32, Format>(&i, prefix);
unhashed::put(final_key.as_ref(), &(&i, linkage));
}
let head = linked_map::read_head::<u32, Format>().unwrap();
assert_eq!(
Enumerator::<u32, u32, Format>::from_head(head, prefix).collect::<Vec<_>>(),
(0..100).rev().map(|x| (x, x)).collect::<Vec<_>>(),
);
// do translation.
NumberMap::translate(
|k: u32| NumberNumber { a: k, b: k },
|v: u32| (v as u64) << 32 | v as u64,
).unwrap();
assert!(linked_map::read_head::<NumberNumber, Format>().is_some());
assert_eq!(
NumberMap::enumerate().collect::<Vec<_>>(),
(0..100u32).rev().map(|x| (
NumberNumber { a: x, b: x },
(x as u64) << 32 | x as u64,
)).collect::<Vec<_>>(),
);
})
}
}
@@ -0,0 +1,171 @@
// 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/>.
#[cfg(not(feature = "std"))]
use rstd::prelude::*;
use codec::{FullCodec, Encode, EncodeAppend, EncodeLike, Decode};
use crate::{storage::{self, unhashed}, hash::{Twox128, StorageHasher}, traits::Len};
/// Generator for `StorageValue` used by `decl_storage`.
///
/// Value is stored at:
/// ```nocompile
/// Twox128(unhashed_key)
/// ```
pub trait StorageValue<T: FullCodec> {
/// The type that get/take returns.
type Query;
/// Unhashed key used in storage
fn unhashed_key() -> &'static [u8];
/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<T>) -> Self::Query;
/// Convert a query to an optional value into storage.
fn from_query_to_optional_value(v: Self::Query) -> Option<T>;
/// Generate the full key used in top storage.
fn storage_value_final_key() -> [u8; 16] {
Twox128::hash(Self::unhashed_key())
}
}
impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G {
type Query = G::Query;
fn hashed_key() -> [u8; 16] {
Self::storage_value_final_key()
}
fn exists() -> bool {
unhashed::exists(&Self::storage_value_final_key())
}
fn get() -> Self::Query {
let value = unhashed::get(&Self::storage_value_final_key());
G::from_optional_value_to_query(value)
}
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()> {
let key = Self::storage_value_final_key();
// attempt to get the length directly.
let maybe_old = match unhashed::get_raw(&key) {
Some(old_data) => Some(O::decode(&mut &old_data[..]).map_err(|_| ())?),
None => None,
};
let maybe_new = f(maybe_old);
if let Some(new) = maybe_new.as_ref() {
new.using_encoded(|d| unhashed::put_raw(&key, d));
} else {
unhashed::kill(&key);
}
Ok(maybe_new)
}
fn put<Arg: EncodeLike<T>>(val: Arg) {
unhashed::put(&Self::storage_value_final_key(), &val)
}
fn kill() {
unhashed::kill(&Self::storage_value_final_key())
}
fn mutate<R, F: FnOnce(&mut G::Query) -> R>(f: F) -> R {
let mut val = G::get();
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => G::put(val),
None => G::kill(),
}
ret
}
fn take() -> G::Query {
let key = Self::storage_value_final_key();
let value = unhashed::get(&key);
if value.is_some() {
unhashed::kill(&key)
}
G::from_optional_value_to_query(value)
}
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<Items, Item, EncodeLikeItem>(items: Items) -> Result<(), &'static str>
where
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
T: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator,
{
let key = Self::storage_value_final_key();
let encoded_value = unhashed::get_raw(&key)
.unwrap_or_else(|| {
match G::from_query_to_optional_value(G::from_optional_value_to_query(None)) {
Some(value) => value.encode(),
None => vec![],
}
});
let new_val = T::append_or_new(
encoded_value,
items,
).map_err(|_| "Could not append given item")?;
unhashed::put_raw(&key, &new_val);
Ok(())
}
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
/// old (presumably corrupt) value is replaced with the given `items`.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append_or_put<Items, Item, EncodeLikeItem>(items: Items) where
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
T: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<T>,
Items::IntoIter: ExactSizeIterator
{
Self::append(items.clone()).unwrap_or_else(|_| Self::put(items));
}
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
///
/// Note that `0` is returned as the default value if no encoded value exists at the given key.
/// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()`
/// function for this purpose.
fn decode_len() -> Result<usize, &'static str> where T: codec::DecodeLength, T: Len {
let key = Self::storage_value_final_key();
// attempt to get the length directly.
if let Some(k) = unhashed::get_raw(&key) {
<T as codec::DecodeLength>::len(&k).map_err(|e| e.what())
} else {
let len = G::from_query_to_optional_value(G::from_optional_value_to_query(None))
.map(|v| v.len())
.unwrap_or(0);
Ok(len)
}
}
}
@@ -0,0 +1,155 @@
// 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.
use super::unhashed;
use rstd::prelude::*;
use codec::{Encode, Decode};
/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
pub fn get<T, HashFn, R>(hash: &HashFn, key: &[u8]) -> Option<T>
where
T: Decode + Sized,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, HashFn, R>(hash: &HashFn, key: &[u8]) -> T
where
T: Decode + Sized + Default,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, HashFn, R>(hash: &HashFn, key: &[u8], default_value: T) -> T
where
T: Decode + Sized,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, F, HashFn, R>(hash: &HashFn, key: &[u8], default_value: F) -> T
where
T: Decode + Sized,
F: FnOnce() -> T,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
unhashed::get_or_else(&hash(key).as_ref(), default_value)
}
/// Put `value` in storage under `key`.
pub fn put<T, HashFn, R>(hash: &HashFn, key: &[u8], value: &T)
where
T: Encode,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, HashFn, R>(hash: &HashFn, key: &[u8]) -> Option<T>
where
T: Decode + Sized,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, HashFn, R>(hash: &HashFn, key: &[u8]) -> T
where
T: Decode + Sized + Default,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, HashFn, R>(hash: &HashFn, key: &[u8], default_value: T) -> T
where
T: Decode + Sized,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, F, HashFn, R>(hash: &HashFn, key: &[u8], default_value: F) -> T
where
T: Decode + Sized,
F: FnOnce() -> T,
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
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, R>(hash: &HashFn, key: &[u8]) -> bool
where
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
unhashed::exists(&hash(key).as_ref())
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill<HashFn, R>(hash: &HashFn, key: &[u8])
where
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
unhashed::kill(&hash(key).as_ref())
}
/// Get a Vec of bytes from storage.
pub fn get_raw<HashFn, R>(hash: &HashFn, key: &[u8]) -> Option<Vec<u8>>
where
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
unhashed::get_raw(&hash(key).as_ref())
}
/// Put a raw byte slice into storage.
pub fn put_raw<HashFn, R>(hash: &HashFn, key: &[u8], value: &[u8])
where
HashFn: Fn(&[u8]) -> R,
R: AsRef<[u8]>,
{
unhashed::put_raw(&hash(key).as_ref(), value)
}
+333
View File
@@ -0,0 +1,333 @@
// Copyright 2017-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/>.
//! Stuff to do with the runtime's storage.
use rstd::prelude::*;
use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode};
use crate::traits::Len;
pub mod unhashed;
pub mod hashed;
pub mod child;
pub mod generator;
/// A trait for working with macro-generated storage values under the substrate storage API.
///
/// Details on implementation can be found at
/// [`generator::StorageValue`]
pub trait StorageValue<T: FullCodec> {
/// The type that get/take return.
type Query;
/// Get the storage key.
fn hashed_key() -> [u8; 16];
/// Does the value (explicitly) exist in storage?
fn exists() -> bool;
/// Load the value from the provided storage instance.
fn get() -> Self::Query;
/// Translate a value from some previous type (`O`) to the current type.
///
/// `f: F` is the translation function.
///
/// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along
/// with the new value if it could.
///
/// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default
/// value of the original type.
///
/// # Warning
///
/// This function must be used with care, before being updated the storage still contains the
/// old type, thus other calls (such as `get`) will fail at decoding it.
///
/// # Usage
///
/// This would typically be called inside the module implementation of on_initialize, while
/// ensuring **no usage of this storage are made before the call to `on_initialize`**. (More
/// precisely prior initialized modules doesn't make use of this storage).
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()>;
/// Store a value under this key into the provided storage instance.
fn put<Arg: EncodeLike<T>>(val: Arg);
/// Mutate the value
fn mutate<R, F: FnOnce(&mut Self::Query) -> R>(f: F) -> R;
/// Clear the storage value.
fn kill();
/// Take a value from storage, removing it afterwards.
fn take() -> Self::Query;
/// Append the given item to the value in the storage.
///
/// `T` is required to implement `codec::EncodeAppend`.
fn append<Items, Item, EncodeLikeItem>(items: Items) -> Result<(), &'static str>
where
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
T: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator;
/// Append the given items to the value in the storage.
///
/// `T` is required to implement `Codec::EncodeAppend`.
///
/// Upon any failure, it replaces `items` as the new value (assuming that the previous stored
/// data is simply corrupt and no longer usable).
///
/// ### WARNING
///
/// use with care; if your use-case is not _exactly_ as what this function is doing,
/// you should use append and sensibly handle failure within the runtime code if it happens.
fn append_or_put<Items, Item, EncodeLikeItem>(items: Items) where
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
T: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<T>,
Items::IntoIter: ExactSizeIterator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
fn decode_len() -> Result<usize, &'static str>
where T: codec::DecodeLength + Len;
}
/// A strongly-typed map in storage.
///
/// Details on implementation can be found at
/// [`generator::StorageMap`]
pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// The type that get/take return.
type Query;
/// Get the storage key used to fetch a value corresponding to a specific key.
fn hashed_key_for<KeyArg: EncodeLike<K>>(key: KeyArg) -> Vec<u8>;
/// Does the value (explicitly) exist in storage?
fn exists<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool;
/// Load the value associated with the given key from the map.
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Swap the values of two keys.
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2);
/// Store a value to be associated with the given key from the map.
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg);
/// Remove the value under a key.
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg);
/// Mutate the value under a key.
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R;
/// Take the value under a key.
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Append the given items to the value in the storage.
///
/// `V` is required to implement `codec::EncodeAppend`.
fn append<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) -> Result<(), &'static str>
where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator;
/// Safely append the given items to the value in the storage. If a codec error occurs, then the
/// old (presumably corrupt) value is replaced with the given `items`.
///
/// `V` is required to implement `codec::EncodeAppend`.
fn append_or_insert<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items)
where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
Items::IntoIter: ExactSizeIterator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
///
/// Note that `0` is returned as the default value if no encoded value exists at the given key.
/// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()`
/// function for this purpose.
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len;
}
/// A strongly-typed linked map in storage.
///
/// Similar to `StorageMap` but allows to enumerate other elements and doesn't implement append.
///
/// Details on implementation can be found at
/// [`generator::StorageLinkedMap`]
pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> {
/// The type that get/take return.
type Query;
/// The type that iterates over all `(key, value)`.
type Enumerator: Iterator<Item = (K, V)>;
/// Does the value (explicitly) exist in storage?
fn exists<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool;
/// Load the value associated with the given key from the map.
fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Swap the values of two keys.
fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2);
/// Store a value to be associated with the given key from the map.
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg);
/// Remove the value under a key.
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg);
/// Mutate the value under a key.
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R;
/// Take the value under a key.
fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query;
/// Return current head element.
fn head() -> Option<K>;
/// Enumerate all elements in the map.
fn enumerate() -> Self::Enumerator;
/// Read the length of the value in a fast way, without decoding the entire value.
///
/// `T` is required to implement `Codec::DecodeLength`.
///
/// Note that `0` is returned as the default value if no encoded value exists at the given key.
/// Therefore, this function cannot be used as a sign of _existence_. use the `::exists()`
/// function for this purpose.
fn decode_len<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<usize, &'static str>
where V: codec::DecodeLength + Len;
/// Translate the keys and values from some previous `(K2, V2)` to the current type.
///
/// `TK` translates keys from the old type, and `TV` translates values.
///
/// Returns `Err` if the map could not be interpreted as the old type, and Ok if it could.
/// The `Err` contains the first key which could not be migrated, or `None` if the
/// head of the list could not be read.
///
/// # Warning
///
/// This function must be used with care, before being updated the storage still contains the
/// old type, thus other calls (such as `get`) will fail at decoding it.
///
/// # Usage
///
/// This would typically be called inside the module implementation of on_initialize, while
/// ensuring **no usage of this storage are made before the call to `on_initialize`**. (More
/// precisely prior initialized modules doesn't make use of this storage).
fn translate<K2, V2, TK, TV>(translate_key: TK, translate_val: TV) -> Result<(), Option<K2>>
where K2: FullCodec + Clone, V2: Decode, TK: Fn(K2) -> K, TV: Fn(V2) -> V;
}
/// An implementation of a map with a two keys.
///
/// It provides an important ability to efficiently remove all entries
/// that have a common first key.
///
/// Details on implementation can be found at
/// [`generator::StorageDoubleMap`]
pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// The type that get/take returns.
type Query;
fn hashed_key_for<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Vec<u8>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
fn exists<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> bool
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
fn get<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
fn take<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> Self::Query
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
fn insert<KArg1, KArg2, VArg>(k1: KArg1, k2: KArg2, val: VArg)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
VArg: EncodeLike<V>;
fn remove<KArg1, KArg2>(k1: KArg1, k2: KArg2)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>;
fn remove_prefix<KArg1>(k1: KArg1) where KArg1: ?Sized + EncodeLike<K1>;
fn mutate<KArg1, KArg2, R, F>(k1: KArg1, k2: KArg2, f: F) -> R
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
F: FnOnce(&mut Self::Query) -> R;
fn append<Items, Item, EncodeLikeItem, KArg1, KArg2>(
k1: KArg1,
k2: KArg2,
items: Items,
) -> Result<(), &'static str>
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem>,
Items::IntoIter: ExactSizeIterator;
fn append_or_insert<Items, Item, EncodeLikeItem, KArg1, KArg2>(
k1: KArg1,
k2: KArg2,
items: Items,
)
where
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
V: EncodeAppend<Item=Item>,
Items: IntoIterator<Item=EncodeLikeItem> + Clone + EncodeLike<V>,
Items::IntoIter: ExactSizeIterator;
}
@@ -0,0 +1,106 @@
// Copyright 2019 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
//! Operation on unhashed runtime storage.
use rstd::prelude::*;
use codec::{Encode, Decode};
/// 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> {
runtime_io::storage::get(key).and_then(|val| {
Decode::decode(&mut &val[..]).map(Some).unwrap_or_else(|_| {
// TODO #3700: error should be handleable.
runtime_print!("ERROR: Corrupted state at {:?}", key);
None
})
})
}
/// 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 {
get(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry.
pub fn get_or<T: Decode + Sized>(key: &[u8], default_value: T) -> T {
get(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry.
pub fn get_or_else<T: Decode + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
get(key).unwrap_or_else(default_value)
}
/// Put `value` in storage under `key`.
pub fn put<T: Encode + ?Sized>(key: &[u8], value: &T) {
value.using_encoded(|slice| runtime_io::storage::set(key, slice));
}
/// 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> {
let r = get(key);
if r.is_some() {
kill(key);
}
r
}
/// Remove `key` from storage, returning its value, or, if there was no explicit entry in storage,
/// the default for its type.
pub fn take_or_default<T: Decode + Sized + Default>(key: &[u8]) -> T {
take(key).unwrap_or_else(Default::default)
}
/// Return the value of the item in storage under `key`, or `default_value` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or<T: Decode + Sized>(key: &[u8], default_value: T) -> T {
take(key).unwrap_or(default_value)
}
/// Return the value of the item in storage under `key`, or `default_value()` if there is no
/// explicit entry. Ensure there is no explicit entry on return.
pub fn take_or_else<T: Decode + Sized, F: FnOnce() -> T>(key: &[u8], default_value: F) -> T {
take(key).unwrap_or_else(default_value)
}
/// Check to see if `key` has an explicit entry in storage.
pub fn exists(key: &[u8]) -> bool {
runtime_io::storage::read(key, &mut [0;0][..], 0).is_some()
}
/// Ensure `key` has no explicit entry in storage.
pub fn kill(key: &[u8]) {
runtime_io::storage::clear(key);
}
/// Ensure keys with the given `prefix` have no entries in storage.
pub fn kill_prefix(prefix: &[u8]) {
runtime_io::storage::clear_prefix(prefix);
}
/// Get a Vec of bytes from storage.
pub fn get_raw(key: &[u8]) -> Option<Vec<u8>> {
runtime_io::storage::get(key)
}
/// Put a raw byte slice into storage.
pub fn put_raw(key: &[u8], value: &[u8]) {
runtime_io::storage::set(key, value)
}