Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
17d7f63
Basic account composition.
gavofyork Feb 3, 2020
ae6f092
Add try_mutate_exists
gavofyork Feb 4, 2020
21e1565
De-duplicate
gavofyork Feb 4, 2020
c202dda
Refactor away the UpdateBalanceOutcome
gavofyork Feb 4, 2020
7aa6647
Expunge final UpdateBalanceOutcome refs
gavofyork Feb 4, 2020
b03d937
Refactor transfer
gavofyork Feb 4, 2020
1b74a2c
Refactor reservable currency stuff.
gavofyork Feb 4, 2020
74db69f
Test with the alternative setup.
gavofyork Feb 4, 2020
02d039d
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 4, 2020
d153672
Fixes
gavofyork Feb 4, 2020
459c30b
Test with both setups.
gavofyork Feb 5, 2020
f4ab417
Fixes
gavofyork Feb 5, 2020
35fcb32
Fix
gavofyork Feb 5, 2020
158863b
Fix macros
bkchr Feb 5, 2020
d7ce210
Make indices opt-in
gavofyork Feb 5, 2020
51ea88b
Remove CreationFee, and make indices opt-in.
gavofyork Feb 5, 2020
9c5539a
Fix construct_runtime
bkchr Feb 5, 2020
aed4da9
Fix last few bits
gavofyork Feb 6, 2020
21254ed
Fix tests
bkchr Feb 6, 2020
f929007
Update trait impls
gavofyork Feb 6, 2020
234ca8a
Don't hardcode the system event
bkchr Feb 6, 2020
c12175d
Make tests build and fix some stuff.
gavofyork Feb 6, 2020
ae0a7c6
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 6, 2020
133c060
Pointlessly bump runtime version
gavofyork Feb 6, 2020
5870f62
Fix benchmark
gavofyork Feb 6, 2020
2579ff7
Another fix
gavofyork Feb 6, 2020
571e209
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 6, 2020
f9adced
Whitespace
gavofyork Feb 6, 2020
2cc84bd
Make indices module economically safe
gavofyork Feb 7, 2020
06cd3a0
Migrations for indices.
gavofyork Feb 7, 2020
b656032
Fix
gavofyork Feb 7, 2020
6d02d1d
Whilespace
gavofyork Feb 7, 2020
091bf0e
Trim defunct migrations
gavofyork Feb 8, 2020
48a3450
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 8, 2020
ae75d69
Remove unused storage item
gavofyork Feb 8, 2020
10d28d2
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 9, 2020
02e67b7
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 9, 2020
e4a398a
More contains_key fixes
gavofyork Feb 9, 2020
9f01bf0
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 10, 2020
1a59997
Docs.
gavofyork Feb 10, 2020
fd6adae
Bump runtime
gavofyork Feb 10, 2020
29cefa1
Merge branch 'master' into gav-composite-account
gavofyork Feb 10, 2020
740e8a3
Merge branch 'master' into gav-composite-account
jacogr Feb 11, 2020
30cee70
Remove unneeded code
gavofyork Feb 11, 2020
6afee76
Merge branch 'gav-composite-account' of github.com:paritytech/substra…
gavofyork Feb 11, 2020
6444cc1
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 12, 2020
5890e24
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 12, 2020
411595d
Fix test
gavofyork Feb 12, 2020
a26c44d
Fix test
gavofyork Feb 12, 2020
bbacb94
Merge branch 'master' into gav-composite-account
gavofyork Feb 12, 2020
2f07990
Update frame/balances/src/lib.rs
gavofyork Feb 13, 2020
680c1f7
Fix ED logic
gavofyork Feb 13, 2020
446ace0
Merge branch 'gav-composite-account' of github.com:paritytech/substra…
gavofyork Feb 13, 2020
3c29022
Repatriate reserved logic
gavofyork Feb 13, 2020
cc6edb8
Typo
gavofyork Feb 13, 2020
df85e74
Fix typo
shawntabrizi Feb 13, 2020
db5c064
Merge branch 'gav-composite-account' of github.com:paritytech/substra…
gavofyork Feb 13, 2020
a7d2980
Update frame/system/src/lib.rs
gavofyork Feb 13, 2020
49bc2e0
Update frame/system/src/lib.rs
gavofyork Feb 13, 2020
c9e852c
Last few fixes
gavofyork Feb 13, 2020
86b132e
Merge branch 'gav-composite-account' of github.com:paritytech/substra…
gavofyork Feb 13, 2020
c472b53
Another fix
gavofyork Feb 13, 2020
dedc512
Merge remote-tracking branch 'origin/master' into gav-composite-account
gavofyork Feb 13, 2020
e424b22
Build fix
gavofyork Feb 13, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add try_mutate_exists
  • Loading branch information
gavofyork committed Feb 4, 2020
commit ae6f092d31eae276504029cadae76d700a3c79ad
340 changes: 213 additions & 127 deletions frame/balances/src/lib.rs

Large diffs are not rendered by default.

17 changes: 12 additions & 5 deletions frame/balances/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use sp_runtime::{Perbill, traits::{ConvertInto, IdentityLookup}, testing::Header
use sp_core::H256;
use sp_io;
use frame_support::{impl_outer_origin, parameter_types};
use frame_support::traits::Get;
use frame_support::traits::{Get, StorageMapShim};
use frame_support::weights::{Weight, DispatchInfo};
use std::cell::RefCell;
use crate::{GenesisConfig, Module, Trait};
Expand Down Expand Up @@ -71,6 +71,9 @@ impl frame_system::Trait for Test {
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type OnReapAccount = Balances;
}
parameter_types! {
pub const TransactionBaseFee: u64 = 0;
Expand All @@ -86,13 +89,17 @@ impl pallet_transaction_payment::Trait for Test {
}
impl Trait for Test {
type Balance = u64;
type OnReapAccount = System;
type OnNewAccount = ();
type Event = ();
type DustRemoval = ();
type TransferPayment = ();
type DustRemoval = ();
type Event = ();
type ExistentialDeposit = ExistentialDeposit;
type CreationFee = CreationFee;
type AccountStore = StorageMapShim<
super::Account<Test>,
system::CallOnCreatedAccount<Test>,
system::CallKillAccount<Test>,
u64, super::AccountData<u64>
>;
}

pub struct ExtBuilder {
Expand Down
29 changes: 29 additions & 0 deletions frame/support/src/storage/generator/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,35 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V>
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.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());
Expand Down
9 changes: 9 additions & 0 deletions frame/support/src/storage/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], 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()];
Expand Down
15 changes: 11 additions & 4 deletions frame/support/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,22 @@ 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 value under a key.
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.
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>,
Expand All @@ -167,8 +175,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>,
Expand Down
100 changes: 88 additions & 12 deletions frame/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,104 @@ use sp_runtime::{
};

use crate::dispatch::Parameter;
use crate::storage::StorageValue;
use crate::storage::StorageMap;

/// An abstraction of a value stored within storage, but possibly as part of a larger composite
/// item.
pub trait StoredValue<T> {
/// Get the item.
fn get() -> T;
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;
/// Mutate the item.
fn mutate<R>(f: impl FnOnce(&mut T) -> R) -> R;
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 put(t: T) { Self::mutate(|i| *i = t); }
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, but that's left for later.
pub struct StorageValueShim<S>(S);
impl<S: StorageValue<T, Query=T>, T: FullCodec> StoredValue<T> for StorageValueShim<S> {
fn get() -> T { S::get() }
fn mutate<R>(f: impl FnOnce(&mut T) -> R) -> R { S::mutate(f) }
fn put(t: T) { S::put(t) }
/// 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 insert(k: &K, t: T) {
S::insert(k, t);
if !S::exists(&k) {
Created::happened(k);
}
}
fn remove(k: &K) {
if S::exists(&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::exists(&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.
Expand Down
Loading