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
+7 -40
View File
@@ -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,
+1
View File
@@ -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);
}
+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>,
+142 -22
View File
@@ -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>;
}