mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 02:17:58 +00:00
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:
@@ -337,30 +337,14 @@ macro_rules! impl_outer_event {
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
pub enum $name:ident for $runtime:ident {
|
||||
$( $rest_event_without_system:tt )*
|
||||
$( $rest_events:tt )*
|
||||
}
|
||||
) => {
|
||||
$crate::impl_outer_event!(
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
system;
|
||||
Modules { $( $rest_event_without_system )* };
|
||||
;
|
||||
);
|
||||
};
|
||||
(
|
||||
$(#[$attr:meta])*
|
||||
pub enum $name:ident for $runtime:ident where system = $system:ident {
|
||||
$( $rest_event_with_system:tt )*
|
||||
}
|
||||
) => {
|
||||
$crate::impl_outer_event!(
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
$system;
|
||||
Modules { $( $rest_event_with_system )* };
|
||||
Modules { $( $rest_events )* };
|
||||
;
|
||||
);
|
||||
};
|
||||
@@ -369,7 +353,6 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr:meta])*;
|
||||
$name:ident;
|
||||
$runtime:ident;
|
||||
$system:ident;
|
||||
Modules {
|
||||
$module:ident $instance:ident<T>,
|
||||
$( $rest_event_generic_instance:tt )*
|
||||
@@ -380,7 +363,6 @@ macro_rules! impl_outer_event {
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
$system;
|
||||
Modules { $( $rest_event_generic_instance )* };
|
||||
$( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>{ $instance },;
|
||||
);
|
||||
@@ -390,7 +372,6 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr:meta])*;
|
||||
$name:ident;
|
||||
$runtime:ident;
|
||||
$system:ident;
|
||||
Modules {
|
||||
$module:ident $instance:ident,
|
||||
$( $rest_event_instance:tt )*
|
||||
@@ -401,7 +382,6 @@ macro_rules! impl_outer_event {
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
$system;
|
||||
Modules { $( $rest_event_instance )* };
|
||||
$( $module_name::Event $( <$generic_param> )* $( { $generic_instance } )?, )* $module::Event { $instance },;
|
||||
);
|
||||
@@ -411,7 +391,6 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr:meta])*;
|
||||
$name:ident;
|
||||
$runtime:ident;
|
||||
$system:ident;
|
||||
Modules {
|
||||
$module:ident<T>,
|
||||
$( $rest_event_generic:tt )*
|
||||
@@ -422,7 +401,6 @@ macro_rules! impl_outer_event {
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
$system;
|
||||
Modules { $( $rest_event_generic )* };
|
||||
$( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event<$runtime>,;
|
||||
);
|
||||
@@ -432,7 +410,6 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr:meta])*;
|
||||
$name:ident;
|
||||
$runtime:ident;
|
||||
$system:ident;
|
||||
Modules {
|
||||
$module:ident,
|
||||
$( $rest_event_no_generic_no_instance:tt )*
|
||||
@@ -443,7 +420,6 @@ macro_rules! impl_outer_event {
|
||||
$( #[$attr] )*;
|
||||
$name;
|
||||
$runtime;
|
||||
$system;
|
||||
Modules { $( $rest_event_no_generic_no_instance )* };
|
||||
$( $module_name::Event $( <$generic_param> )? $( { $generic_instance } )?, )* $module::Event,;
|
||||
);
|
||||
@@ -454,7 +430,6 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr:meta])*;
|
||||
$name:ident;
|
||||
$runtime:ident;
|
||||
$system:ident;
|
||||
Modules {};
|
||||
$( $module_name:ident::Event $( <$generic_param:ident> )? $( { $generic_instance:ident } )?, )*;
|
||||
) => {
|
||||
@@ -468,18 +443,12 @@ macro_rules! impl_outer_event {
|
||||
$(#[$attr])*
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum $name {
|
||||
system($system::Event),
|
||||
$(
|
||||
[< $module_name $(_ $generic_instance )? >](
|
||||
$module_name::Event < $( $generic_param )? $(, $module_name::$generic_instance )? >
|
||||
),
|
||||
)*
|
||||
}
|
||||
impl From<$system::Event> for $name {
|
||||
fn from(x: $system::Event) -> Self {
|
||||
$name::system(x)
|
||||
}
|
||||
}
|
||||
$(
|
||||
impl From<$module_name::Event < $( $generic_param, )? $( $module_name::$generic_instance )? >> for $name {
|
||||
fn from(x: $module_name::Event < $( $generic_param, )? $( $module_name::$generic_instance )? >) -> Self {
|
||||
@@ -505,7 +474,6 @@ macro_rules! impl_outer_event {
|
||||
$crate::__impl_outer_event_json_metadata!(
|
||||
$runtime;
|
||||
$name;
|
||||
$system;
|
||||
$(
|
||||
$module_name::Event
|
||||
< $( $generic_param )? $(, $module_name::$generic_instance )? >
|
||||
@@ -521,7 +489,6 @@ macro_rules! __impl_outer_event_json_metadata {
|
||||
(
|
||||
$runtime:ident;
|
||||
$event_name:ident;
|
||||
$system:ident;
|
||||
$( $module_name:ident::Event < $( $generic_params:path ),* > $( $instance:ident )?, )*;
|
||||
) => {
|
||||
impl $runtime {
|
||||
@@ -530,22 +497,20 @@ macro_rules! __impl_outer_event_json_metadata {
|
||||
$crate::event::OuterEventMetadata {
|
||||
name: $crate::event::DecodeDifferent::Encode(stringify!($event_name)),
|
||||
events: $crate::event::DecodeDifferent::Encode(&[
|
||||
("system", $crate::event::FnEncode($system::Event::metadata))
|
||||
$(
|
||||
, (
|
||||
(
|
||||
stringify!($module_name),
|
||||
$crate::event::FnEncode(
|
||||
$module_name::Event ::< $( $generic_params ),* > ::metadata
|
||||
)
|
||||
)
|
||||
)*
|
||||
),*
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
$crate::__impl_outer_event_json_metadata! {
|
||||
@DECL_MODULE_EVENT_FNS
|
||||
$system <> ;
|
||||
$( $module_name < $( $generic_params ),* > $( $instance )? ; )*
|
||||
}
|
||||
}
|
||||
@@ -717,6 +682,7 @@ mod tests {
|
||||
|
||||
impl_outer_event! {
|
||||
pub enum TestEvent for TestRuntime {
|
||||
system,
|
||||
event_module<T>,
|
||||
event_module2<T>,
|
||||
event_module3,
|
||||
@@ -727,7 +693,8 @@ mod tests {
|
||||
pub struct TestRuntime2;
|
||||
|
||||
impl_outer_event! {
|
||||
pub enum TestEventSystemRenamed for TestRuntime2 where system = system_renamed {
|
||||
pub enum TestEventSystemRenamed for TestRuntime2 {
|
||||
system_renamed,
|
||||
event_module<T>,
|
||||
event_module2<T>,
|
||||
event_module3,
|
||||
|
||||
@@ -404,6 +404,7 @@ mod tests {
|
||||
|
||||
impl_outer_event! {
|
||||
pub enum TestEvent for TestRuntime {
|
||||
system,
|
||||
event_module<T>,
|
||||
event_module2<T>,
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>,
|
||||
|
||||
@@ -28,6 +28,115 @@ use sp_runtime::{
|
||||
};
|
||||
|
||||
use crate::dispatch::Parameter;
|
||||
use crate::storage::StorageMap;
|
||||
|
||||
/// An abstraction of a value stored within storage, but possibly as part of a larger composite
|
||||
/// item.
|
||||
pub trait StoredMap<K, T> {
|
||||
/// Get the item, or its default if it doesn't yet exist; we make no distinction between the
|
||||
/// two.
|
||||
fn get(k: &K) -> T;
|
||||
/// Get whether the item takes up any storage. If this is `false`, then `get` will certainly
|
||||
/// return the `T::default()`. If `true`, then there is no implication for `get` (i.e. it
|
||||
/// may return any value, including the default).
|
||||
///
|
||||
/// NOTE: This may still be `true`, even after `remove` is called. This is the case where
|
||||
/// a single storage entry is shared between multiple `StoredMap` items single, without
|
||||
/// additional logic to enforce it, deletion of any one them doesn't automatically imply
|
||||
/// deletion of them all.
|
||||
fn is_explicit(k: &K) -> bool;
|
||||
/// Mutate the item.
|
||||
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> R;
|
||||
/// Mutate the item, removing or resetting to default value if it has been mutated to `None`.
|
||||
fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> R;
|
||||
/// Maybe mutate the item only if an `Ok` value is returned from `f`. Do nothing if an `Err` is
|
||||
/// returned. It is removed or reset to default value if it has been mutated to `None`
|
||||
fn try_mutate_exists<R, E>(k: &K, f: impl FnOnce(&mut Option<T>) -> Result<R, E>) -> Result<R, E>;
|
||||
/// Set the item to something new.
|
||||
fn insert(k: &K, t: T) { Self::mutate(k, |i| *i = t); }
|
||||
/// Remove the item or otherwise replace it with its default value; we don't care which.
|
||||
fn remove(k: &K);
|
||||
}
|
||||
|
||||
/// A simple, generic one-parameter event notifier/handler.
|
||||
pub trait Happened<T> {
|
||||
/// The thing happened.
|
||||
fn happened(t: &T);
|
||||
}
|
||||
|
||||
/// A shim for placing around a storage item in order to use it as a `StoredValue`. Ideally this
|
||||
/// wouldn't be needed as `StorageValue`s should blanket implement `StoredValue`s, however this
|
||||
/// would break the ability to have custom impls of `StoredValue`. The other workaround is to
|
||||
/// implement it directly in the macro.
|
||||
///
|
||||
/// This form has the advantage that two additional types are provides, `Created` and `Removed`,
|
||||
/// which are both generic events that can be tied to handlers to do something in the case of being
|
||||
/// about to create an account where one didn't previously exist (at all; not just where it used to
|
||||
/// be the default value), or where the account is being removed or reset back to the default value
|
||||
/// where previously it did exist (though may have been in a default state). This works well with
|
||||
/// system module's `CallOnCreatedAccount` and `CallKillAccount`.
|
||||
pub struct StorageMapShim<
|
||||
S,
|
||||
Created,
|
||||
Removed,
|
||||
K,
|
||||
T
|
||||
>(sp_std::marker::PhantomData<(S, Created, Removed, K, T)>);
|
||||
impl<
|
||||
S: StorageMap<K, T, Query=T>,
|
||||
Created: Happened<K>,
|
||||
Removed: Happened<K>,
|
||||
K: FullCodec,
|
||||
T: FullCodec
|
||||
> StoredMap<K, T> for StorageMapShim<S, Created, Removed, K, T> {
|
||||
fn get(k: &K) -> T { S::get(k) }
|
||||
fn is_explicit(k: &K) -> bool { S::contains_key(k) }
|
||||
fn insert(k: &K, t: T) {
|
||||
S::insert(k, t);
|
||||
if !S::contains_key(&k) {
|
||||
Created::happened(k);
|
||||
}
|
||||
}
|
||||
fn remove(k: &K) {
|
||||
if S::contains_key(&k) {
|
||||
Removed::happened(&k);
|
||||
}
|
||||
S::remove(k);
|
||||
}
|
||||
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> R {
|
||||
let r = S::mutate(k, f);
|
||||
if !S::contains_key(&k) {
|
||||
Created::happened(k);
|
||||
}
|
||||
r
|
||||
}
|
||||
fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> R {
|
||||
let (existed, exists, r) = S::mutate_exists(k, |maybe_value| {
|
||||
let existed = maybe_value.is_some();
|
||||
let r = f(maybe_value);
|
||||
(existed, maybe_value.is_some(), r)
|
||||
});
|
||||
if !existed && exists {
|
||||
Created::happened(k);
|
||||
} else if existed && !exists {
|
||||
Removed::happened(k);
|
||||
}
|
||||
r
|
||||
}
|
||||
fn try_mutate_exists<R, E>(k: &K, f: impl FnOnce(&mut Option<T>) -> Result<R, E>) -> Result<R, E> {
|
||||
S::try_mutate_exists(k, |maybe_value| {
|
||||
let existed = maybe_value.is_some();
|
||||
f(maybe_value).map(|v| (existed, maybe_value.is_some(), v))
|
||||
}).map(|(existed, exists, v)| {
|
||||
if !existed && exists {
|
||||
Created::happened(k);
|
||||
} else if existed && !exists {
|
||||
Removed::happened(k);
|
||||
}
|
||||
v
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Anything that can have a `::len()` method.
|
||||
pub trait Len {
|
||||
@@ -65,6 +174,25 @@ pub trait Contains<T: Ord> {
|
||||
fn count() -> usize { Self::sorted_members().len() }
|
||||
}
|
||||
|
||||
/// Determiner to say whether a given account is unused.
|
||||
pub trait IsDeadAccount<AccountId> {
|
||||
/// Is the given account dead?
|
||||
fn is_dead_account(who: &AccountId) -> bool;
|
||||
}
|
||||
|
||||
impl<AccountId> IsDeadAccount<AccountId> for () {
|
||||
fn is_dead_account(_who: &AccountId) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// Handler for when a new account has been created.
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
pub trait OnNewAccount<AccountId> {
|
||||
/// A new account `who` has been registered.
|
||||
fn on_new_account(who: &AccountId);
|
||||
}
|
||||
|
||||
/// The account with the given id was reaped.
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
pub trait OnReapAccount<AccountId> {
|
||||
@@ -72,20 +200,6 @@ pub trait OnReapAccount<AccountId> {
|
||||
fn on_reap_account(who: &AccountId);
|
||||
}
|
||||
|
||||
/// Outcome of a balance update.
|
||||
pub enum UpdateBalanceOutcome {
|
||||
/// Account balance was simply updated.
|
||||
Updated,
|
||||
/// The update led to killing the account.
|
||||
AccountKilled,
|
||||
/// Free balance became zero as a result of this update.
|
||||
FreeBalanceZero,
|
||||
/// Reserved balance became zero as a result of this update.
|
||||
ReservedBalanceZero,
|
||||
/// The account started and ended non-existent.
|
||||
StillDead,
|
||||
}
|
||||
|
||||
/// A trait for finding the author of a block header based on the `PreRuntime` digests contained
|
||||
/// within it.
|
||||
pub trait FindAuthor<Author> {
|
||||
@@ -494,10 +608,15 @@ pub trait Currency<AccountId> {
|
||||
fn make_free_balance_be(
|
||||
who: &AccountId,
|
||||
balance: Self::Balance,
|
||||
) -> (
|
||||
SignedImbalance<Self::Balance, Self::PositiveImbalance>,
|
||||
UpdateBalanceOutcome,
|
||||
);
|
||||
) -> SignedImbalance<Self::Balance, Self::PositiveImbalance>;
|
||||
}
|
||||
|
||||
/// Status of funds.
|
||||
pub enum BalanceStatus {
|
||||
/// Funds are free, as corresponding to `free` item in Balances.
|
||||
Free,
|
||||
/// Funds are reserved, as corresponding to `reserved` item in Balances.
|
||||
Reserved,
|
||||
}
|
||||
|
||||
/// A currency where funds can be reserved from the user.
|
||||
@@ -528,7 +647,6 @@ pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
|
||||
/// collapsed to zero if it ever becomes less than `ExistentialDeposit`.
|
||||
fn reserved_balance(who: &AccountId) -> Self::Balance;
|
||||
|
||||
|
||||
/// Moves `value` from balance to reserved balance.
|
||||
///
|
||||
/// If the free balance is lower than `value`, then no funds will be moved and an `Err` will
|
||||
@@ -547,16 +665,18 @@ pub trait ReservableCurrency<AccountId>: Currency<AccountId> {
|
||||
/// invoke `on_reserved_too_low` and could reap the account.
|
||||
fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance;
|
||||
|
||||
/// Moves up to `value` from reserved balance of account `slashed` to free balance of account
|
||||
/// Moves up to `value` from reserved balance of account `slashed` to balance of account
|
||||
/// `beneficiary`. `beneficiary` must exist for this to succeed. If it does not, `Err` will be
|
||||
/// returned.
|
||||
/// returned. Funds will be placed in either the `free` balance or the `reserved` balance,
|
||||
/// depending on the `status`.
|
||||
///
|
||||
/// As much funds up to `value` will be deducted as possible. If this is less than `value`,
|
||||
/// then `Ok(non_zero)` will be returned.
|
||||
fn repatriate_reserved(
|
||||
slashed: &AccountId,
|
||||
beneficiary: &AccountId,
|
||||
value: Self::Balance
|
||||
value: Self::Balance,
|
||||
status: BalanceStatus,
|
||||
) -> result::Result<Self::Balance, DispatchError>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user