mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 07:41:08 +00:00
add mutate api (#695)
* runtime-storage: add 'mutate' api * support mutate for StorageValue * try adding 'mutate' for map * dispatch on Option<> type * add check for prev_some * consolidate the wrap type * unify wrap type handling * add sample for StorageValue
This commit is contained in:
@@ -108,11 +108,14 @@ pub trait StorageValue<T: codec::Codec> {
|
||||
/// Take a value from storage, removing it afterwards.
|
||||
fn take<S: Storage>(storage: &S) -> Self::Query;
|
||||
|
||||
/// Store a value under this key into the provded storage instance.
|
||||
/// Store a value under this key into the provided storage instance.
|
||||
fn put<S: Storage>(val: &T, storage: &S) {
|
||||
storage.put(Self::key(), val)
|
||||
}
|
||||
|
||||
/// Mutate this value
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(f: F, storage: &S);
|
||||
|
||||
/// Clear the storage value.
|
||||
fn kill<S: Storage>(storage: &S) {
|
||||
storage.kill(Self::key())
|
||||
@@ -180,6 +183,9 @@ pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
|
||||
fn remove<S: Storage>(key: &K, storage: &S) {
|
||||
storage.kill(&Self::key_for(key)[..]);
|
||||
}
|
||||
|
||||
/// Mutate the value under a key.
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: Storage>(key: &K, f: F, storage: &S);
|
||||
}
|
||||
|
||||
// TODO: Remove this in favour of `decl_storage` macro.
|
||||
@@ -188,103 +194,103 @@ pub trait StorageMap<K: codec::Codec, V: codec::Codec> {
|
||||
macro_rules! storage_items {
|
||||
// simple values
|
||||
($name:ident : $key:expr => $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $key:expr => $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident : $key:expr => default $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
__storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $key:expr => default $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident : $key:expr => required $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
__storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $key:expr => required $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
|
||||
($name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $key:expr => $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $key:expr => default $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $key:expr => required $ty:ty; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $key => $ty);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
|
||||
// maps
|
||||
($name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) () (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) () ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) () (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
|
||||
($name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $prefix:expr => map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) (Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $prefix:expr => default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) ($ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
($name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!(() ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!(() ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
(pub $name:ident get($getfn:ident) : $prefix:expr => required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__storage_items_internal!((pub) ($getfn) ($ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
__storage_items_internal!((pub) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $name: $prefix => map [$kty => $ty]);
|
||||
storage_items!($($t)*);
|
||||
};
|
||||
|
||||
@@ -301,15 +307,26 @@ macro_rules! storage_items {
|
||||
() => ()
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __handle_wrap_internal {
|
||||
(RAW_TYPE { $($raw:tt)* } { $($option:tt)* }) => {
|
||||
$($raw)*;
|
||||
};
|
||||
(OPTION_TYPE { $($raw:tt)* } { $($option:tt)* }) => {
|
||||
$($option)*;
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __storage_items_internal {
|
||||
// generator for values.
|
||||
(($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
|
||||
__storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $key => $ty }
|
||||
(($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
|
||||
__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $key => $ty }
|
||||
pub fn $get_fn() -> $gettype { <$name as $crate::storage::generator::StorageValue<$ty>> :: get(&$crate::storage::RuntimeStorage) }
|
||||
};
|
||||
(($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
|
||||
(($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => {
|
||||
$($vis)* struct $name;
|
||||
|
||||
impl $crate::storage::generator::StorageValue<$ty> for $name {
|
||||
@@ -329,16 +346,34 @@ macro_rules! __storage_items_internal {
|
||||
fn take<S: $crate::GenericStorage>(storage: &S) -> Self::Query {
|
||||
storage.$taker($key)
|
||||
}
|
||||
|
||||
/// Mutate this value.
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) {
|
||||
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage);
|
||||
|
||||
f(&mut val);
|
||||
|
||||
__handle_wrap_internal!($wraptype {
|
||||
// raw type case
|
||||
<Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage)
|
||||
} {
|
||||
// Option<> type case
|
||||
match val {
|
||||
Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage),
|
||||
None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
// generator for maps.
|
||||
(($($vis:tt)*) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => {
|
||||
__storage_items_internal!{ ($($vis)*) () ($gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] }
|
||||
(($($vis:tt)*) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => {
|
||||
__storage_items_internal!{ ($($vis)*) () ($wraptype $gettype) ($getter) ($taker) $name : $prefix => map [$kty => $ty] }
|
||||
pub fn $get_fn<K: $crate::storage::generator::Borrow<$kty>>(key: K) -> $gettype {
|
||||
<$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage)
|
||||
}
|
||||
};
|
||||
(($($vis:tt)*) () ($gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => {
|
||||
(($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => {
|
||||
$($vis)* struct $name;
|
||||
|
||||
impl $crate::storage::generator::StorageMap<$kty, $ty> for $name {
|
||||
@@ -367,6 +402,24 @@ macro_rules! __storage_items_internal {
|
||||
let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key);
|
||||
storage.$taker(&key[..])
|
||||
}
|
||||
|
||||
/// Mutate the value under a key.
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) {
|
||||
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage);
|
||||
|
||||
f(&mut val);
|
||||
|
||||
__handle_wrap_internal!($wraptype {
|
||||
// raw type case
|
||||
<Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage)
|
||||
} {
|
||||
// Option<> type case
|
||||
match val {
|
||||
Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
|
||||
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
// generator for lists.
|
||||
@@ -503,103 +556,103 @@ macro_rules! decl_storage {
|
||||
macro_rules! __decl_storage_items {
|
||||
// simple values
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : default $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : default $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : required $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : required $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : default $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : default $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : required $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : required $ty:ty; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: $ty);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
|
||||
// maps
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident : required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident : required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) () (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (OPTION_TYPE Option<$ty>) (get) (take) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : default map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (get_or_default) (take_or_default) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* $name:ident get($getfn:ident) : required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!(() ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
($cratename:ident $traittype:ident $traitinstance:ident $(#[$doc:meta])* pub $name:ident get($getfn:ident) : required map [$kty:ty => $ty:ty]; $($t:tt)*) => {
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) ($ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_item!((pub) ($traittype as $traitinstance) ($getfn) (RAW_TYPE $ty) (require) (take_or_panic) $cratename $name: map [$kty => $ty]);
|
||||
__decl_storage_items!($cratename $traittype $traitinstance $($t)*);
|
||||
};
|
||||
|
||||
@@ -611,10 +664,10 @@ macro_rules! __decl_storage_items {
|
||||
#[doc(hidden)]
|
||||
macro_rules! __decl_storage_item {
|
||||
// generator for values.
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => {
|
||||
__decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($gettype) ($getter) ($taker) $cratename $name : $ty }
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => {
|
||||
__decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($wraptype $gettype) ($getter) ($taker) $cratename $name : $ty }
|
||||
};
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => {
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : $ty:ty) => {
|
||||
$($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>);
|
||||
|
||||
impl<$traitinstance: $traittype> $crate::storage::generator::StorageValue<$ty> for $name<$traitinstance> {
|
||||
@@ -634,13 +687,31 @@ macro_rules! __decl_storage_item {
|
||||
fn take<S: $crate::GenericStorage>(storage: &S) -> Self::Query {
|
||||
storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key())
|
||||
}
|
||||
|
||||
/// Mutate the value under a key.
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(f: F, storage: &S) {
|
||||
let mut val = <Self as $crate::storage::generator::StorageValue<$ty>>::get(storage);
|
||||
|
||||
f(&mut val);
|
||||
|
||||
__handle_wrap_internal!($wraptype {
|
||||
// raw type case
|
||||
<Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage)
|
||||
} {
|
||||
// Option<> type case
|
||||
match val {
|
||||
Some(val) => <Self as $crate::storage::generator::StorageValue<$ty>>::put(&val, storage),
|
||||
None => <Self as $crate::storage::generator::StorageValue<$ty>>::kill(storage),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
// generator for maps.
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => {
|
||||
__decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($gettype) ($getter) ($taker) $cratename $name : map [$kty => $ty] }
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) ($get_fn:ident) ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => {
|
||||
__decl_storage_item!{ ($($vis)*) ($traittype as $traitinstance) () ($wraptype $gettype) ($getter) ($taker) $cratename $name : map [$kty => $ty] }
|
||||
};
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => {
|
||||
(($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $cratename:ident $name:ident : map [$kty:ty => $ty:ty]) => {
|
||||
$($vis)* struct $name<$traitinstance: $traittype>($crate::storage::generator::PhantomData<$traitinstance>);
|
||||
|
||||
impl<$traitinstance: $traittype> $crate::storage::generator::StorageMap<$kty, $ty> for $name<$traitinstance> {
|
||||
@@ -669,6 +740,22 @@ macro_rules! __decl_storage_item {
|
||||
let key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key);
|
||||
storage.$taker(&key[..])
|
||||
}
|
||||
|
||||
/// Mutate the value under a key
|
||||
fn mutate<F: FnOnce(&mut Self::Query), S: $crate::GenericStorage>(key: &$kty, f: F, storage: &S) {
|
||||
let mut val = <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::take(key, storage);
|
||||
|
||||
f(&mut val);
|
||||
|
||||
__handle_wrap_internal!($wraptype {
|
||||
<Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage);
|
||||
} {
|
||||
match val {
|
||||
Some(val) => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::insert(key, &val, storage),
|
||||
None => <Self as $crate::storage::generator::StorageMap<$kty, $ty>>::remove(key, storage),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -180,9 +180,12 @@ pub trait StorageValue<T: Codec> {
|
||||
/// Load the value from the provided storage instance.
|
||||
fn get() -> Self::Query;
|
||||
|
||||
/// Store a value under this key into the provded storage instance.
|
||||
/// Store a value under this key into the provided storage instance.
|
||||
fn put<Arg: Borrow<T>>(val: Arg);
|
||||
|
||||
/// Mutate the value
|
||||
fn mutate<F: FnOnce(&mut Self::Query)>(f: F);
|
||||
|
||||
/// Clear the storage value.
|
||||
fn kill();
|
||||
|
||||
@@ -205,6 +208,9 @@ impl<T: Codec, U> StorageValue<T> for U where U: generator::StorageValue<T> {
|
||||
fn put<Arg: Borrow<T>>(val: Arg) {
|
||||
U::put(val.borrow(), &RuntimeStorage)
|
||||
}
|
||||
fn mutate<F: FnOnce(&mut Self::Query)>(f: F) {
|
||||
U::mutate(f, &RuntimeStorage)
|
||||
}
|
||||
fn kill() {
|
||||
U::kill(&RuntimeStorage)
|
||||
}
|
||||
@@ -304,6 +310,9 @@ pub trait StorageMap<K: Codec, V: Codec> {
|
||||
/// Remove the value under a key.
|
||||
fn remove<KeyArg: Borrow<K>>(key: KeyArg);
|
||||
|
||||
/// Mutate the value under a key.
|
||||
fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F);
|
||||
|
||||
/// Take the value under a key.
|
||||
fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query;
|
||||
}
|
||||
@@ -335,6 +344,10 @@ impl<K: Codec, V: Codec, U> StorageMap<K, V> for U where U: generator::StorageMa
|
||||
U::remove(key.borrow(), &RuntimeStorage)
|
||||
}
|
||||
|
||||
fn mutate<KeyArg: Borrow<K>, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F) {
|
||||
U::mutate(key.borrow(), f, &RuntimeStorage)
|
||||
}
|
||||
|
||||
fn take<KeyArg: Borrow<K>>(key: KeyArg) -> Self::Query {
|
||||
U::take(key.borrow(), &RuntimeStorage)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ extern crate substrate_runtime_std;
|
||||
#[cfg(test)]
|
||||
extern crate substrate_runtime_io as runtime_io;
|
||||
|
||||
// Needed for the set of mock primatives used in our tests.
|
||||
// Needed for the set of mock primitives used in our tests.
|
||||
#[cfg(test)]
|
||||
extern crate substrate_primitives;
|
||||
|
||||
@@ -110,7 +110,9 @@ decl_module! {
|
||||
/// world.
|
||||
fn accumulate_dummy(origin, increase_by: T::Balance) -> Result;
|
||||
|
||||
/// A priviledged call; in this case it resets our dummy value to something new.
|
||||
fn accumulate_foo(origin, increase_by: T::Balance) -> Result;
|
||||
|
||||
/// A privileged call; in this case it resets our dummy value to something new.
|
||||
fn set_dummy(origin, new_dummy: T::Balance) -> Result;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +135,7 @@ pub enum RawEvent<B> {
|
||||
Dummy(B),
|
||||
}
|
||||
|
||||
// By convention we implement any trait for which a "null implemntation" makes sense
|
||||
// By convention we implement any trait for which a "null implementation" makes sense
|
||||
// for `()`. This is the case for conversion of module `Event` types and hook traits. It
|
||||
// is helpful for test code and production configurations where no eventing is necessary
|
||||
// or the hook is unused.
|
||||
@@ -170,9 +172,12 @@ decl_storage! {
|
||||
// implements `runtime_support::StorageMap`.
|
||||
//
|
||||
// If they have a getter (`get(getter_name)`), then your module will come
|
||||
// equiped with `fn getter_name() -> Type` for basic value items or
|
||||
// equipped with `fn getter_name() -> Type` for basic value items or
|
||||
// `fn getter_name(key: KeyType) -> ValueType` for map items.
|
||||
Dummy get(dummy): T::Balance;
|
||||
|
||||
// this one uses the default, we'll demonstrate the usage of 'mutate' API.
|
||||
Foo get(foo): default T::Balance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,18 +237,24 @@ impl<T: Trait> Module<T> {
|
||||
let _sender = ensure_signed(origin)?;
|
||||
|
||||
// Read the value of dummy from storage.
|
||||
let dummy = Self::dummy();
|
||||
// Will also work using the `::get` on the storage item type iself:
|
||||
// let dummy = Self::dummy();
|
||||
// Will also work using the `::get` on the storage item type itself:
|
||||
// let dummy = <Dummy<T>>::get();
|
||||
|
||||
// Calculate the new value.
|
||||
let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by);
|
||||
// let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by);
|
||||
|
||||
// Put the new value into storage.
|
||||
<Dummy<T>>::put(new_dummy);
|
||||
// <Dummy<T>>::put(new_dummy);
|
||||
// Will also work with a reference:
|
||||
// <Dummy<T>>::put(&new_dummy);
|
||||
|
||||
// Here's the new one of read and then modify the value.
|
||||
<Dummy<T>>::mutate(|dummy| {
|
||||
let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by);
|
||||
*dummy = Some(new_dummy);
|
||||
});
|
||||
|
||||
// Let's deposit an event to let the outside world know this happened.
|
||||
Self::deposit_event(RawEvent::Dummy(increase_by));
|
||||
|
||||
@@ -251,10 +262,19 @@ impl<T: Trait> Module<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Implementation of a priviledged call. This doesn't have an `origin` parameter because
|
||||
fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> Result {
|
||||
let _sender = ensure_signed(origin)?;
|
||||
|
||||
// Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an Option<> type.
|
||||
<Foo<T>>::mutate(|foo| *foo = *foo + increase_by);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Implementation of a privileged call. This doesn't have an `origin` parameter because
|
||||
// it's not (directly) from an extrinsic, but rather the system as a whole has decided
|
||||
// to execute it. Different runtimes have different reasons for allow priviledged
|
||||
// calls to be executed - we don't need to care why. Because it's priviledged, we can
|
||||
// to execute it. Different runtimes have different reasons for allow privileged
|
||||
// calls to be executed - we don't need to care why. Because it's privileged, we can
|
||||
// assume it's a one-off operation and substantial processing/storage/memory can be used
|
||||
// without worrying about gameability or attack scenarios.
|
||||
fn set_dummy(origin: T::Origin, new_value: T::Balance) -> Result {
|
||||
@@ -287,6 +307,7 @@ impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> {
|
||||
pub struct GenesisConfig<T: Trait> {
|
||||
/// A value with which to initialise the Dummy storage item.
|
||||
pub dummy: T::Balance,
|
||||
pub foo: T::Balance,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -294,6 +315,7 @@ impl<T: Trait> Default for GenesisConfig<T> {
|
||||
fn default() -> Self {
|
||||
GenesisConfig {
|
||||
dummy: Default::default(),
|
||||
foo: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,7 +333,8 @@ impl<T: Trait> runtime_primitives::BuildStorage for GenesisConfig<T>
|
||||
fn build_storage(self) -> ::std::result::Result<runtime_primitives::StorageMap, String> {
|
||||
use codec::Encode;
|
||||
Ok(map![
|
||||
Self::hash(<Dummy<T>>::key()).to_vec() => self.dummy.encode()
|
||||
Self::hash(<Dummy<T>>::key()).to_vec() => self.dummy.encode(),
|
||||
Self::hash(<Foo<T>>::key()).to_vec() => self.foo.encode()
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -369,12 +392,13 @@ mod tests {
|
||||
t.extend(balances::GenesisConfig::<Test>::default().build_storage().unwrap());
|
||||
t.extend(GenesisConfig::<Test>{
|
||||
dummy: 42,
|
||||
foo: 24,
|
||||
}.build_storage().unwrap());
|
||||
t.into()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
fn it_works_for_optional_value() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
// Check that GenesisBuilder works properly.
|
||||
assert_eq!(Example::dummy(), Some(42));
|
||||
@@ -382,7 +406,7 @@ mod tests {
|
||||
// Check that accumulate works when we have Some value in Dummy already.
|
||||
assert_ok!(Example::accumulate_dummy(Origin::signed(1), 27));
|
||||
assert_eq!(Example::dummy(), Some(69));
|
||||
|
||||
|
||||
// Check that finalising the block removes Dummy from storage.
|
||||
<Example as OnFinalise<u64>>::on_finalise(1);
|
||||
assert_eq!(Example::dummy(), None);
|
||||
@@ -392,4 +416,13 @@ mod tests {
|
||||
assert_eq!(Example::dummy(), Some(42));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works_for_default_value() {
|
||||
with_externalities(&mut new_test_ext(), || {
|
||||
assert_eq!(Example::foo(), 24);
|
||||
assert_ok!(Example::accumulate_foo(Origin::signed(1), 1));
|
||||
assert_eq!(Example::foo(), 25);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,13 +205,7 @@ impl<T: Trait> Module<T> {
|
||||
ensure_root(origin)?;
|
||||
ensure!(<Proposals<T>>::exists(proposal_id), "No proposal at that index");
|
||||
|
||||
{
|
||||
let mut v = <Approvals<T>>::get();
|
||||
v.push(proposal_id);
|
||||
<Approvals<T>>::put(v);
|
||||
}
|
||||
//TODO gav: make work:
|
||||
//<Approvals<T>>::mutate(|a| a.push(proposal_id));
|
||||
<Approvals<T>>::mutate(|v| v.push(proposal_id));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user