mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 17:28:00 +00:00
Introduces account existence providers reference counting (#7363)
* Initial draft * Latest changes * Final bits. * Fixes * Fixes * Test fixes * Fix tests * Fix babe tests * Fix * Fix * Fix * Fix * Fix * fix warnings in assets * Fix UI tests * fix line width * Fix * Update frame/system/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Update frame/system/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * Fix * fix unused warnings * Fix * Update frame/system/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Update frame/system/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Fix * fix slash and comprehensive slash test * fix reserved slash and comprehensive tests * check slash on non-existent account * Revert "Fix UI tests" This reverts commit e0002c0f13442f7d0c95a054a6c515536328a4a0. * Fix * Fix utility tests * keep dispatch error backwards compatible * Fix * Fix * fix ui test * Companion checker shouldn't be so anal. * Fix * Fix * Fix * Apply suggestions from code review Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * Update frame/balances/src/lib.rs Co-authored-by: Alexander Popiak <alexander.popiak@parity.io> * return correct slash info when failing gracefully * fix missing import * Update frame/system/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Fix * Update frame/balances/src/tests_local.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Fixes Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
This commit is contained in:
@@ -27,7 +27,7 @@ use sp_runtime::{
|
||||
traits::{
|
||||
MaybeSerializeDeserialize, AtLeast32Bit, Saturating, TrailingZeroInput, Bounded, Zero,
|
||||
BadOrigin, AtLeast32BitUnsigned, UniqueSaturatedFrom, UniqueSaturatedInto,
|
||||
SaturatedConversion,
|
||||
SaturatedConversion, StoredMapError,
|
||||
},
|
||||
};
|
||||
use crate::dispatch::Parameter;
|
||||
@@ -300,41 +300,60 @@ mod test_impl_filter_stack {
|
||||
|
||||
/// An abstraction of a value stored within storage, but possibly as part of a larger composite
|
||||
/// item.
|
||||
pub trait StoredMap<K, T> {
|
||||
pub trait StoredMap<K, T: Default> {
|
||||
/// 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>;
|
||||
fn try_mutate_exists<R, E: From<StoredMapError>>(
|
||||
k: &K,
|
||||
f: impl FnOnce(&mut Option<T>) -> Result<R, E>,
|
||||
) -> Result<R, E>;
|
||||
|
||||
// Everything past here has a default implementation.
|
||||
|
||||
/// Mutate the item.
|
||||
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> Result<R, StoredMapError> {
|
||||
Self::mutate_exists(k, |maybe_account| match maybe_account {
|
||||
Some(ref mut account) => f(account),
|
||||
x @ None => {
|
||||
let mut account = Default::default();
|
||||
let r = f(&mut account);
|
||||
*x = Some(account);
|
||||
r
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Mutate the item, removing or resetting to default value if it has been mutated to `None`.
|
||||
///
|
||||
/// This is infallible as long as the value does not get destroyed.
|
||||
fn mutate_exists<R>(
|
||||
k: &K,
|
||||
f: impl FnOnce(&mut Option<T>) -> R,
|
||||
) -> Result<R, StoredMapError> {
|
||||
Self::try_mutate_exists(k, |x| -> Result<R, StoredMapError> { Ok(f(x)) })
|
||||
}
|
||||
|
||||
/// Set the item to something new.
|
||||
fn insert(k: &K, t: T) { Self::mutate(k, |i| *i = t); }
|
||||
fn insert(k: &K, t: T) -> Result<(), StoredMapError> { 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);
|
||||
fn remove(k: &K) -> Result<(), StoredMapError> { Self::mutate_exists(k, |x| *x = None) }
|
||||
}
|
||||
|
||||
/// A simple, generic one-parameter event notifier/handler.
|
||||
pub trait Happened<T> {
|
||||
/// The thing happened.
|
||||
fn happened(t: &T);
|
||||
pub trait HandleLifetime<T> {
|
||||
/// An account was created.
|
||||
fn created(_t: &T) -> Result<(), StoredMapError> { Ok(()) }
|
||||
|
||||
/// An account was killed.
|
||||
fn killed(_t: &T) -> Result<(), StoredMapError> { Ok(()) }
|
||||
}
|
||||
|
||||
impl<T> Happened<T> for () {
|
||||
fn happened(_: &T) {}
|
||||
}
|
||||
impl<T> HandleLifetime<T> for () {}
|
||||
|
||||
/// 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
|
||||
@@ -347,68 +366,63 @@ impl<T> Happened<T> for () {
|
||||
/// 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)>);
|
||||
pub struct StorageMapShim<S, L, K, T>(sp_std::marker::PhantomData<(S, L, K, T)>);
|
||||
impl<
|
||||
S: StorageMap<K, T, Query=T>,
|
||||
Created: Happened<K>,
|
||||
Removed: Happened<K>,
|
||||
L: HandleLifetime<K>,
|
||||
K: FullCodec,
|
||||
T: FullCodec,
|
||||
> StoredMap<K, T> for StorageMapShim<S, Created, Removed, K, T> {
|
||||
T: FullCodec + Default,
|
||||
> StoredMap<K, T> for StorageMapShim<S, L, 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) {
|
||||
let existed = S::contains_key(&k);
|
||||
fn insert(k: &K, t: T) -> Result<(), StoredMapError> {
|
||||
if !S::contains_key(&k) {
|
||||
L::created(k)?;
|
||||
}
|
||||
S::insert(k, t);
|
||||
if !existed {
|
||||
Created::happened(k);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn remove(k: &K) {
|
||||
let existed = S::contains_key(&k);
|
||||
S::remove(k);
|
||||
if existed {
|
||||
Removed::happened(&k);
|
||||
fn remove(k: &K) -> Result<(), StoredMapError> {
|
||||
if S::contains_key(&k) {
|
||||
L::killed(&k)?;
|
||||
S::remove(k);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> R {
|
||||
let existed = S::contains_key(&k);
|
||||
let r = S::mutate(k, f);
|
||||
if !existed {
|
||||
Created::happened(k);
|
||||
fn mutate<R>(k: &K, f: impl FnOnce(&mut T) -> R) -> Result<R, StoredMapError> {
|
||||
if !S::contains_key(&k) {
|
||||
L::created(k)?;
|
||||
}
|
||||
r
|
||||
Ok(S::mutate(k, f))
|
||||
}
|
||||
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> {
|
||||
fn mutate_exists<R>(k: &K, f: impl FnOnce(&mut Option<T>) -> R) -> Result<R, StoredMapError> {
|
||||
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)| {
|
||||
let r = f(maybe_value);
|
||||
let exists = maybe_value.is_some();
|
||||
|
||||
if !existed && exists {
|
||||
Created::happened(k);
|
||||
L::created(k)?;
|
||||
} else if existed && !exists {
|
||||
Removed::happened(k);
|
||||
L::killed(k)?;
|
||||
}
|
||||
v
|
||||
Ok(r)
|
||||
})
|
||||
}
|
||||
fn try_mutate_exists<R, E: From<StoredMapError>>(
|
||||
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();
|
||||
let r = f(maybe_value)?;
|
||||
let exists = maybe_value.is_some();
|
||||
|
||||
if !existed && exists {
|
||||
L::created(k).map_err(E::from)?;
|
||||
} else if existed && !exists {
|
||||
L::killed(k).map_err(E::from)?;
|
||||
}
|
||||
Ok(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -507,18 +521,6 @@ pub trait ContainsLengthBound {
|
||||
fn max_len() -> usize;
|
||||
}
|
||||
|
||||
/// 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_for_tuples(30)]
|
||||
pub trait OnNewAccount<AccountId> {
|
||||
|
||||
Reference in New Issue
Block a user