Composite accounts (#4820)

* Basic account composition.

* Add try_mutate_exists

* De-duplicate

* Refactor away the UpdateBalanceOutcome

* Expunge final UpdateBalanceOutcome refs

* Refactor transfer

* Refactor reservable currency stuff.

* Test with the alternative setup.

* Fixes

* Test with both setups.

* Fixes

* Fix

* Fix macros

* Make indices opt-in

* Remove CreationFee, and make indices opt-in.

* Fix construct_runtime

* Fix last few bits

* Fix tests

* Update trait impls

* Don't hardcode the system event

* Make tests build and fix some stuff.

* Pointlessly bump runtime version

* Fix benchmark

* Another fix

* Whitespace

* Make indices module economically safe

* Migrations for indices.

* Fix

* Whilespace

* Trim defunct migrations

* Remove unused storage item

* More contains_key fixes

* Docs.

* Bump runtime

* Remove unneeded code

* Fix test

* Fix test

* Update frame/balances/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Fix ED logic

* Repatriate reserved logic

* Typo

* Fix typo

* Update frame/system/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update frame/system/src/lib.rs

Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Last few fixes

* Another fix

* Build fix

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Jaco Greeff <jacogr@gmail.com>
Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
This commit is contained in:
Gavin Wood
2020-02-14 00:47:51 +00:00
committed by GitHub
parent d3fa8c91af
commit 5b7512e2e4
79 changed files with 2459 additions and 2100 deletions
@@ -104,7 +104,7 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V>
}
fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg) {
unhashed::put(Self::storage_map_final_key(key).as_ref(), &val.borrow())
unhashed::put(Self::storage_map_final_key(key).as_ref(), &val)
}
fn remove<KeyArg: EncodeLike<K>>(key: KeyArg) {
@@ -117,12 +117,58 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V>
let ret = f(&mut val);
match G::from_query_to_optional_value(val) {
Some(ref val) => unhashed::put(final_key.as_ref(), &val.borrow()),
Some(ref val) => unhashed::put(final_key.as_ref(), &val),
None => unhashed::kill(final_key.as_ref()),
}
ret
}
fn mutate_exists<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Option<V>) -> R>(key: KeyArg, f: F) -> R {
let final_key = Self::storage_map_final_key(key);
let mut val = unhashed::get(final_key.as_ref());
let ret = f(&mut val);
match val {
Some(ref val) => unhashed::put(final_key.as_ref(), &val),
None => unhashed::kill(final_key.as_ref()),
}
ret
}
fn try_mutate<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Self::Query) -> Result<R, E>>(
key: KeyArg,
f: F
) -> Result<R, E> {
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);
if ret.is_ok() {
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 try_mutate_exists<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Option<V>) -> Result<R, E>>(
key: KeyArg,
f: F
) -> Result<R, E> {
let final_key = Self::storage_map_final_key(key);
let mut val = unhashed::get(final_key.as_ref());
let ret = f(&mut val);
if ret.is_ok() {
match 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());
@@ -66,6 +66,10 @@ impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G {
G::from_optional_value_to_query(value)
}
fn try_get() -> Result<T, ()> {
unhashed::get(&Self::storage_value_final_key()).ok_or(())
}
fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<T>>(f: F) -> Result<Option<T>, ()> {
let key = Self::storage_value_final_key();
@@ -0,0 +1,98 @@
// Copyright 2017-2020 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/>.
//! Some utilities for helping access storage with arbitrary key types.
use sp_std::prelude::*;
use codec::{Encode, Decode};
use crate::{StorageHasher, Twox128};
/// Utility to iterate through raw items in storage.
pub struct StorageIterator<T> {
prefix: [u8; 32],
previous_key: Vec<u8>,
drain: bool,
_phantom: ::sp_std::marker::PhantomData<T>,
}
impl<T> StorageIterator<T> {
/// Construct iterator to iterate over map items in `module` for the map called `item`.
pub fn new(module: &[u8], item: &[u8]) -> Self {
let mut prefix = [0u8; 32];
prefix[0..16].copy_from_slice(&Twox128::hash(module));
prefix[16..32].copy_from_slice(&Twox128::hash(item));
Self { prefix, previous_key: prefix[..].to_vec(), drain: false, _phantom: Default::default() }
}
/// Mutate this iterator into a draining iterator; items iterated are removed from storage.
pub fn drain(mut self) -> Self {
self.drain = true;
self
}
}
impl<T: Decode + Sized> Iterator for StorageIterator<T> {
type Item = (Vec<u8>, T);
fn next(&mut self) -> Option<(Vec<u8>, T)> {
loop {
let maybe_next = sp_io::storage::next_key(&self.previous_key)
.filter(|n| n.starts_with(&self.prefix));
break match maybe_next {
Some(next) => {
self.previous_key = next.clone();
let maybe_value = frame_support::storage::unhashed::get::<T>(&next);
match maybe_value {
Some(value) => {
if self.drain {
frame_support::storage::unhashed::kill(&next);
}
Some((self.previous_key[32..].to_vec(), value))
}
None => continue,
}
}
None => None,
}
}
}
}
/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
let mut key = vec![0u8; 32 + hash.len()];
key[0..16].copy_from_slice(&Twox128::hash(module));
key[16..32].copy_from_slice(&Twox128::hash(item));
key[32..].copy_from_slice(hash);
frame_support::storage::unhashed::get::<T>(&key)
}
/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
pub fn take_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
let mut key = vec![0u8; 32 + hash.len()];
key[0..16].copy_from_slice(&Twox128::hash(module));
key[16..32].copy_from_slice(&Twox128::hash(item));
key[32..].copy_from_slice(hash);
frame_support::storage::unhashed::take::<T>(&key)
}
/// Put a particular value into storage by the `module`, the map's `item` name and the key `hash`.
pub fn put_storage_value<T: Encode>(module: &[u8], item: &[u8], hash: &[u8], value: T) {
let mut key = vec![0u8; 32 + hash.len()];
key[0..16].copy_from_slice(&Twox128::hash(module));
key[16..32].copy_from_slice(&Twox128::hash(item));
key[32..].copy_from_slice(hash);
frame_support::storage::unhashed::put(&key, &value);
}
+22 -4
View File
@@ -25,6 +25,7 @@ pub mod hashed;
pub mod child;
#[doc(hidden)]
pub mod generator;
pub mod migration;
/// A trait for working with macro-generated storage values under the substrate storage API.
///
@@ -43,6 +44,10 @@ pub trait StorageValue<T: FullCodec> {
/// Load the value from the provided storage instance.
fn get() -> Self::Query;
/// Try to get the underlying value from the provided storage instance; `Ok` if it exists,
/// `Err` if not.
fn try_get() -> Result<T, ()>;
/// Translate a value from some previous type (`O`) to the current type.
///
/// `f: F` is the translation function.
@@ -143,14 +148,28 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// Mutate the value under a key.
fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R;
/// Mutate the item, only if an `Ok` value is returned.
fn try_mutate<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Self::Query) -> Result<R, E>>(
key: KeyArg,
f: F,
) -> Result<R, E>;
/// Mutate the value under a key. Deletes the item if mutated to a `None`.
fn mutate_exists<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Option<V>) -> R>(key: KeyArg, f: F) -> R;
/// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`.
fn try_mutate_exists<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Option<V>) -> Result<R, E>>(
key: KeyArg,
f: F,
) -> Result<R, E>;
/// 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
fn append<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) -> Result<(), &'static str> where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,
@@ -162,8 +181,7 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// 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
fn append_or_insert<Items, Item, EncodeLikeItem, KeyArg>(key: KeyArg, items: Items) where
KeyArg: EncodeLike<K>,
Item: Encode,
EncodeLikeItem: EncodeLike<Item>,