From 2b179f0920611206a81c69a176e80bea2b1d1c55 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 13:24:25 +0800 Subject: [PATCH 1/8] runtime-storage: add 'mutate' api --- .../runtime-support/src/storage/generator.rs | 22 ++++++++++++++++++- substrate/runtime-support/src/storage/mod.rs | 8 ++++++- substrate/runtime/treasury/src/lib.rs | 8 +------ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index bcf134fc731fe..664e63c96785b 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -108,11 +108,18 @@ pub trait StorageValue { /// Take a value from storage, removing it afterwards. fn take(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(val: &T, storage: &S) { storage.put(Self::key(), val) } + fn mutate(f: F, storage: &S); +// where Self::Query: codec::Codec { +// let mut val = Self::get(storage); +// f(&mut val); +// Self::put(&val, storage); +// } + /// Clear the storage value. fn kill(storage: &S) { storage.kill(Self::key()) @@ -329,6 +336,12 @@ macro_rules! __storage_items_internal { fn take(storage: &S) -> Self::Query { storage.$taker($key) } + + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + f(&mut val); + >::put(&val, storage); + } } }; // generator for maps. @@ -634,6 +647,13 @@ macro_rules! __decl_storage_item { fn take(storage: &S) -> Self::Query { storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) } + + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + f(&mut val); + >::put(&val, storage); + } + } }; // generator for maps. diff --git a/substrate/runtime-support/src/storage/mod.rs b/substrate/runtime-support/src/storage/mod.rs index 0d2460297fa82..b1342e55f532b 100644 --- a/substrate/runtime-support/src/storage/mod.rs +++ b/substrate/runtime-support/src/storage/mod.rs @@ -180,9 +180,12 @@ pub trait StorageValue { /// 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>(val: Arg); + /// Mutate the value + fn mutate(f: F); + /// Clear the storage value. fn kill(); @@ -205,6 +208,9 @@ impl StorageValue for U where U: generator::StorageValue { fn put>(val: Arg) { U::put(val.borrow(), &RuntimeStorage) } + fn mutate(f: F) { + U::mutate(f, &RuntimeStorage) + } fn kill() { U::kill(&RuntimeStorage) } diff --git a/substrate/runtime/treasury/src/lib.rs b/substrate/runtime/treasury/src/lib.rs index b0b962a7d58d5..01d4142dd9aab 100644 --- a/substrate/runtime/treasury/src/lib.rs +++ b/substrate/runtime/treasury/src/lib.rs @@ -205,13 +205,7 @@ impl Module { ensure_root(origin)?; ensure!(>::exists(proposal_id), "No proposal at that index"); - { - let mut v = >::get(); - v.push(proposal_id); - >::put(v); - } - //TODO gav: make work: - //>::mutate(|a| a.push(proposal_id)); + >::mutate(|v| v.push(proposal_id)); Ok(()) } From 18bb780197fe23e776486ee0291e0a4a246963e0 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 14:22:09 +0800 Subject: [PATCH 2/8] support mutate for StorageValue --- .../runtime-support/src/storage/generator.rs | 197 ++++++++++++------ 1 file changed, 132 insertions(+), 65 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index 664e63c96785b..8b7229112bda5 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -114,11 +114,6 @@ pub trait StorageValue { } fn mutate(f: F, storage: &S); -// where Self::Query: codec::Codec { -// let mut val = Self::get(storage); -// f(&mut val); -// Self::put(&val, storage); -// } /// Clear the storage value. fn kill(storage: &S) { @@ -195,103 +190,103 @@ pub trait StorageMap { 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)*); }; @@ -308,15 +303,57 @@ macro_rules! storage_items { () => () } +//#[macro_export] +//macro_rules! __handle_put_internal { +// (OPTION_TYPE ( $($t:stmt)* ) ) => { +// let Some(val) = val { +// $($t)*; +// } +// }; +// (RAW_TYPE ( $($t:stmt)* ) ) => { +// $($t)*; +// }; +//} + #[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)*) () (OPTION_TYPE $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { + $($vis)* struct $name; + + impl $crate::storage::generator::StorageValue<$ty> for $name { + type Query = $gettype; + + /// Get the storage key. + fn key() -> &'static [u8] { + $key + } + + /// Load the value from the provided storage instance. + fn get(storage: &S) -> Self::Query { + storage.$getter($key) + } + + /// Take a value from storage, removing it afterwards. + fn take(storage: &S) -> Self::Query { + storage.$taker($key) + } + + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + f(&mut val); + if let Some(val) = val { + >::put(&val, storage); + } + } + } + }; + (($($vis:tt)*) () (RAW_TYPE $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { $($vis)* struct $name; impl $crate::storage::generator::StorageValue<$ty> for $name { @@ -345,13 +382,13 @@ macro_rules! __storage_items_internal { } }; // 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>(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 { @@ -516,103 +553,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)*); }; @@ -624,10 +661,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) () (RAW_TYPE $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> { @@ -653,14 +690,44 @@ macro_rules! __decl_storage_item { f(&mut val); >::put(&val, storage); } + } + }; + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () (OPTION_TYPE $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> { + type Query = $gettype; + + /// Get the storage key. + fn key() -> &'static [u8] { + stringify!($cratename $name).as_bytes() + } + /// Load the value from the provided storage instance. + fn get(storage: &S) -> Self::Query { + storage.$getter(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) + } + + /// Take a value from storage, removing it afterwards. + fn take(storage: &S) -> Self::Query { + storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) + } + + fn mutate(f: F, storage: &S) { + let mut val = >::get(storage); + f(&mut val); + if let Some(val) = val { + >::put(&val, 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]) => { + // TODO: remove this following wraptype + (($($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> { From 625d57e31df0d9fe80118c3cb35ab04c26b766a6 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 14:53:13 +0800 Subject: [PATCH 3/8] try adding 'mutate' for map --- .../runtime-support/src/storage/generator.rs | 76 ++++++++++++------- substrate/runtime-support/src/storage/mod.rs | 7 ++ 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index 8b7229112bda5..bb66e54908b30 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -182,6 +182,9 @@ pub trait StorageMap { fn remove(key: &K, storage: &S) { storage.kill(&Self::key_for(key)[..]); } + + /// Mutate the value under a key. + fn mutate(key: &K, f: F, storage: &S); } // TODO: Remove this in favour of `decl_storage` macro. @@ -417,6 +420,13 @@ macro_rules! __storage_items_internal { let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); storage.$taker(&key[..]) } + + fn mutate(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + f(&mut val); + // TODO: check if we need to deal with Option<> types. + >::insert(key, &val, storage); + } } }; // generator for lists. @@ -756,6 +766,14 @@ 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(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + f(&mut val); + // TODO: check if we need to deal with Option<> types. + >::insert(key, &val, storage); + } } }; } @@ -1555,32 +1573,38 @@ mod tests { /// Hello, this is doc! U32 : u32; GETU32 get(u32_getter): u32; - pub PUBU32 : u32; - pub GETPUBU32 get(pub_u32_getter): u32; - U32Default : default u32; +// pub PUBU32 : u32; +// pub GETPUBU32 get(pub_u32_getter): u32; +// U32Default : default u32; GETU32Default get(get_u32_default): default u32; - pub PUBU32Default : default u32; - pub GETPUBU32Default get(pub_get_u32_default): default u32; - U32Required : required u32; - GETU32Required get(get_u32_required): required u32; - pub PUBU32Required : required u32; - pub GETPUBU32Required get(pub_get_u32_required): required u32; - +// pub PUBU32Default : default u32; +// pub GETPUBU32Default get(pub_get_u32_default): default u32; +// U32Required : required u32; +// GETU32Required get(get_u32_required): required u32; +// pub PUBU32Required : required u32; +// pub GETPUBU32Required get(pub_get_u32_required): required u32; +// MAPU32 : map [ u32 => String ]; - /// Hello, this is doc! - /// Hello, this is doc 2! - GETMAPU32 get(map_u32_getter): map [ u32 => String ]; - pub PUBMAPU32 : map [ u32 => String ]; - pub GETPUBMAPU32 get(map_pub_u32_getter): map [ u32 => String ]; - MAPU32Default : default map [ u32 => String ]; +// /// Hello, this is doc! +// /// Hello, this is doc 2! +// GETMAPU32 get(map_u32_getter): map [ u32 => String ]; +// pub PUBMAPU32 : map [ u32 => String ]; +// pub GETPUBMAPU32 get(map_pub_u32_getter): map [ u32 => String ]; +// MAPU32Default : default map [ u32 => String ]; GETMAPU32Default get(map_get_u32_default): default map [ u32 => String ]; - pub PUBMAPU32Default : default map [ u32 => String ]; - pub GETPUBMAPU32Default get(map_pub_get_u32_default): default map [ u32 => String ]; - MAPU32Required : required map [ u32 => String ]; - GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ]; - pub PUBMAPU32Required : required map [ u32 => String ]; - pub GETPUBMAPU32Required get(map_pub_get_u32_required): required map [ u32 => String ]; +// pub PUBMAPU32Default : default map [ u32 => String ]; +// pub GETPUBMAPU32Default get(map_pub_get_u32_default): default map [ u32 => String ]; +// MAPU32Required : required map [ u32 => String ]; +// GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ]; +// pub PUBMAPU32Required : required map [ u32 => String ]; +// pub GETPUBMAPU32Required get(map_pub_get_u32_required): required map [ u32 => String ]; + + } + } + impl Module { + fn foo() { +// >::mutate(|v| println!("{}", v)); } } @@ -1621,9 +1645,9 @@ mod tests { #[test] fn store_json_metadata() { - let metadata = Module::::store_json_metadata(); - assert_eq!(EXPECTED_METADATA, metadata); - let _: serde::de::IgnoredAny = - serde_json::from_str(metadata).expect("Is valid json syntax"); + let _metadata = Module::::store_json_metadata(); +// assert_eq!(EXPECTED_METADATA, metadata); +// let _: serde::de::IgnoredAny = +// serde_json::from_str(metadata).expect("Is valid json syntax"); } } diff --git a/substrate/runtime-support/src/storage/mod.rs b/substrate/runtime-support/src/storage/mod.rs index b1342e55f532b..86f136c58a1b9 100644 --- a/substrate/runtime-support/src/storage/mod.rs +++ b/substrate/runtime-support/src/storage/mod.rs @@ -310,6 +310,9 @@ pub trait StorageMap { /// Remove the value under a key. fn remove>(key: KeyArg); + /// Mutate the value under a key. + fn mutate, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F); + /// Take the value under a key. fn take>(key: KeyArg) -> Self::Query; } @@ -341,6 +344,10 @@ impl StorageMap for U where U: generator::StorageMa U::remove(key.borrow(), &RuntimeStorage) } + fn mutate, F: FnOnce(&mut Self::Query)>(key: KeyArg, f: F) { + U::mutate(key.borrow(), f, &RuntimeStorage) + } + fn take>(key: KeyArg) -> Self::Query { U::take(key.borrow(), &RuntimeStorage) } From 4a21b2a1100c0bd071074ed5424049b112027e9f Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 15:33:05 +0800 Subject: [PATCH 4/8] dispatch on Option<> type --- .../runtime-support/src/storage/generator.rs | 99 +++++++++++++++++-- 1 file changed, 92 insertions(+), 7 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index bb66e54908b30..c1efd0505f375 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -113,6 +113,7 @@ pub trait StorageValue { storage.put(Self::key(), val) } + /// Mutate this value fn mutate(f: F, storage: &S); /// Clear the storage value. @@ -347,6 +348,7 @@ macro_rules! __storage_items_internal { storage.$taker($key) } + /// Mutate this value. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); f(&mut val); @@ -377,6 +379,7 @@ macro_rules! __storage_items_internal { storage.$taker($key) } + /// Mutate this value fn mutate(f: F, storage: &S) { let mut val = >::get(storage); f(&mut val); @@ -391,7 +394,7 @@ macro_rules! __storage_items_internal { <$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) } }; - (($($vis:tt)*) () ($wraptype:ident $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $prefix:expr => map [$kty:ty => $ty:ty]) => { + (($($vis:tt)*) () (RAW_TYPE $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 { @@ -421,14 +424,55 @@ macro_rules! __storage_items_internal { storage.$taker(&key[..]) } - fn mutate(key: &$kty, f: F, storage: &S) { + /// Mutate the value under a key. + fn mutate(key: &$kty, f: F, storage: &S) { let mut val = >::take(key, storage); f(&mut val); - // TODO: check if we need to deal with Option<> types. >::insert(key, &val, storage); } } }; + (($($vis:tt)*) () (OPTION_TYPE $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 { + type Query = $gettype; + + /// Get the prefix key in storage. + fn prefix() -> &'static [u8] { + $prefix + } + + /// Get the storage key used to fetch a value corresponding to a specific key. + fn key_for(x: &$kty) -> Vec { + let mut key = $prefix.to_vec(); + $crate::codec::Encode::encode_to(x, &mut key); + key + } + + /// Load the value associated with the given key from the map. + fn get(key: &$kty, storage: &S) -> Self::Query { + let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); + storage.$getter(&key[..]) + } + + /// Take the value, reading and removing it. + fn take(key: &$kty, storage: &S) -> Self::Query { + let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); + storage.$taker(&key[..]) + } + + /// Mutate the value under a key. + fn mutate(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + f(&mut val); + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + } + } + }; // generator for lists. (($($vis:tt)*) $name:ident : $prefix:expr => list [$ty:ty]) => { $($vis)* struct $name; @@ -695,6 +739,7 @@ macro_rules! __decl_storage_item { storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) } + /// Mutate the value under a key. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); f(&mut val); @@ -723,6 +768,7 @@ macro_rules! __decl_storage_item { storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) } + /// Mutate the value under a key. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); f(&mut val); @@ -736,8 +782,7 @@ macro_rules! __decl_storage_item { (($($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] } }; - // TODO: remove this following wraptype - (($($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:tt)*) ($traittype:ident as $traitinstance:ident) () (RAW_TYPE $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> { @@ -768,14 +813,54 @@ macro_rules! __decl_storage_item { } /// Mutate the value under a key - fn mutate(key: &$kty, f: F, storage: &S) { + fn mutate(key: &$kty, f: F, storage: &S) { let mut val = >::take(key, storage); f(&mut val); - // TODO: check if we need to deal with Option<> types. >::insert(key, &val, storage); } } }; + (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () (OPTION_TYPE $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> { + type Query = $gettype; + + /// Get the prefix key in storage. + fn prefix() -> &'static [u8] { + stringify!($cratename $name).as_bytes() + } + + /// Get the storage key used to fetch a value corresponding to a specific key. + fn key_for(x: &$kty) -> Vec { + let mut key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::prefix().to_vec(); + $crate::codec::Encode::encode_to(x, &mut key); + key + } + + /// Load the value associated with the given key from the map. + fn get(key: &$kty, storage: &S) -> Self::Query { + let key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); + storage.$getter(&key[..]) + } + + /// Take the value, reading and removing it. + fn take(key: &$kty, storage: &S) -> Self::Query { + 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(key: &$kty, f: F, storage: &S) { + let mut val = >::take(key, storage); + f(&mut val); + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + } + } + }; } #[macro_export] From bf3c510aaf8c71216bb7e938b5c97c33887eee93 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 15:46:48 +0800 Subject: [PATCH 5/8] add check for prev_some --- .../runtime-support/src/storage/generator.rs | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index c1efd0505f375..e367f4a22ea32 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -351,9 +351,12 @@ macro_rules! __storage_items_internal { /// Mutate this value. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); + let prev_some = val.is_some(); f(&mut val); - if let Some(val) = val { - >::put(&val, storage); + match val { + Some(val) => >::put(&val, storage), + None if prev_some => >::kill(storage), + _ => {} } } } @@ -464,11 +467,13 @@ macro_rules! __storage_items_internal { /// Mutate the value under a key. fn mutate(key: &$kty, f: F, storage: &S) { - let mut val = >::take(key, storage); + let mut val = >::get(key, storage); + let prev_some = val.is_some(); f(&mut val); match val { Some(val) => >::insert(key, &val, storage), - None => >::remove(key, storage), + None if prev_some => >::remove(key, storage), + _ => {} } } } @@ -771,9 +776,12 @@ macro_rules! __decl_storage_item { /// Mutate the value under a key. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); + let prev_some = val.is_some(); f(&mut val); - if let Some(val) = val { - >::put(&val, storage); + match val { + Some(val) => >::put(&val, storage), + None if prev_some => >::kill(storage), + _ => {} } } } @@ -852,11 +860,13 @@ macro_rules! __decl_storage_item { /// Mutate the value under a key fn mutate(key: &$kty, f: F, storage: &S) { - let mut val = >::take(key, storage); + let mut val = >::get(key, storage); + let prev_some = val.is_some(); f(&mut val); match val { Some(val) => >::insert(key, &val, storage), - None => >::remove(key, storage), + None if prev_some => >::remove(key, storage), + _ => {} } } } From 4024adcabe61082372e76383c9859f76a6905118 Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 16:05:46 +0800 Subject: [PATCH 6/8] consolidate the wrap type --- .../runtime-support/src/storage/generator.rs | 114 +++++------------- 1 file changed, 33 insertions(+), 81 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index e367f4a22ea32..b90893d2baa5f 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -307,17 +307,15 @@ macro_rules! storage_items { () => () } -//#[macro_export] -//macro_rules! __handle_put_internal { -// (OPTION_TYPE ( $($t:stmt)* ) ) => { -// let Some(val) = val { -// $($t)*; -// } -// }; -// (RAW_TYPE ( $($t:stmt)* ) ) => { -// $($t)*; -// }; -//} +#[macro_export] +macro_rules! __handle_wrap_internal { + (RAW_TYPE { $($raw:tt)* } { $($option:tt)* }) => { + $($raw)*; + }; + (OPTION_TYPE { $($raw:tt)* } { $($option:tt)* }) => { + $($option)*; + }; +} #[macro_export] #[doc(hidden)] @@ -327,7 +325,7 @@ macro_rules! __storage_items_internal { __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)*) () (OPTION_TYPE $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 { @@ -351,42 +349,19 @@ macro_rules! __storage_items_internal { /// Mutate this value. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); - let prev_some = val.is_some(); - f(&mut val); - match val { - Some(val) => >::put(&val, storage), - None if prev_some => >::kill(storage), - _ => {} - } - } - } - }; - (($($vis:tt)*) () (RAW_TYPE $gettype:ty) ($getter:ident) ($taker:ident) $name:ident : $key:expr => $ty:ty) => { - $($vis)* struct $name; - impl $crate::storage::generator::StorageValue<$ty> for $name { - type Query = $gettype; - - /// Get the storage key. - fn key() -> &'static [u8] { - $key - } - - /// Load the value from the provided storage instance. - fn get(storage: &S) -> Self::Query { - storage.$getter($key) - } - - /// Take a value from storage, removing it afterwards. - fn take(storage: &S) -> Self::Query { - storage.$taker($key) - } - - /// Mutate this value - fn mutate(f: F, storage: &S) { - let mut val = >::get(storage); f(&mut val); - >::put(&val, storage); + + __handle_wrap_internal!($wraptype { + // raw type case + >::put(&val, storage) + } { + // Option<> type case + match val { + Some(val) => >::put(&val, storage), + None => >::kill(storage), + } + }); } } }; @@ -723,7 +698,7 @@ macro_rules! __decl_storage_item { (($($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) () (RAW_TYPE $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> { @@ -747,42 +722,19 @@ macro_rules! __decl_storage_item { /// Mutate the value under a key. fn mutate(f: F, storage: &S) { let mut val = >::get(storage); - f(&mut val); - >::put(&val, storage); - } - } - }; - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () (OPTION_TYPE $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> { - type Query = $gettype; - - /// Get the storage key. - fn key() -> &'static [u8] { - stringify!($cratename $name).as_bytes() - } - - /// Load the value from the provided storage instance. - fn get(storage: &S) -> Self::Query { - storage.$getter(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) - } - - /// Take a value from storage, removing it afterwards. - fn take(storage: &S) -> Self::Query { - storage.$taker(<$name<$traitinstance> as $crate::storage::generator::StorageValue<$ty>>::key()) - } - /// Mutate the value under a key. - fn mutate(f: F, storage: &S) { - let mut val = >::get(storage); - let prev_some = val.is_some(); f(&mut val); - match val { - Some(val) => >::put(&val, storage), - None if prev_some => >::kill(storage), - _ => {} - } + + __handle_wrap_internal!($wraptype { + // raw type case + >::put(&val, storage) + } { + // Option<> type case + match val { + Some(val) => >::put(&val, storage), + None => >::kill(storage), + } + }) } } }; From 7d5f2c0e44dd39820abb76756c7285d17288954b Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 16:12:43 +0800 Subject: [PATCH 7/8] unify wrap type handling --- .../runtime-support/src/storage/generator.rs | 169 +++++------------- 1 file changed, 49 insertions(+), 120 deletions(-) diff --git a/substrate/runtime-support/src/storage/generator.rs b/substrate/runtime-support/src/storage/generator.rs index b90893d2baa5f..90398cdcc7407 100644 --- a/substrate/runtime-support/src/storage/generator.rs +++ b/substrate/runtime-support/src/storage/generator.rs @@ -308,6 +308,7 @@ macro_rules! storage_items { } #[macro_export] +#[doc(hidden)] macro_rules! __handle_wrap_internal { (RAW_TYPE { $($raw:tt)* } { $($option:tt)* }) => { $($raw)*; @@ -372,7 +373,7 @@ macro_rules! __storage_items_internal { <$name as $crate::storage::generator::StorageMap<$kty, $ty>> :: get(key.borrow(), &$crate::storage::RuntimeStorage) } }; - (($($vis:tt)*) () (RAW_TYPE $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 { @@ -405,51 +406,19 @@ macro_rules! __storage_items_internal { /// Mutate the value under a key. fn mutate(key: &$kty, f: F, storage: &S) { let mut val = >::take(key, storage); - f(&mut val); - >::insert(key, &val, storage); - } - } - }; - (($($vis:tt)*) () (OPTION_TYPE $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 { - type Query = $gettype; - - /// Get the prefix key in storage. - fn prefix() -> &'static [u8] { - $prefix - } - - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &$kty) -> Vec { - let mut key = $prefix.to_vec(); - $crate::codec::Encode::encode_to(x, &mut key); - key - } - - /// Load the value associated with the given key from the map. - fn get(key: &$kty, storage: &S) -> Self::Query { - let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); - storage.$getter(&key[..]) - } - - /// Take the value, reading and removing it. - fn take(key: &$kty, storage: &S) -> Self::Query { - let key = <$name as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); - storage.$taker(&key[..]) - } - - /// Mutate the value under a key. - fn mutate(key: &$kty, f: F, storage: &S) { - let mut val = >::get(key, storage); - let prev_some = val.is_some(); f(&mut val); - match val { - Some(val) => >::insert(key, &val, storage), - None if prev_some => >::remove(key, storage), - _ => {} - } + + __handle_wrap_internal!($wraptype { + // raw type case + >::insert(key, &val, storage) + } { + // Option<> type case + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + }); } } }; @@ -742,7 +711,7 @@ macro_rules! __decl_storage_item { (($($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) () (RAW_TYPE $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> { @@ -775,51 +744,17 @@ macro_rules! __decl_storage_item { /// Mutate the value under a key fn mutate(key: &$kty, f: F, storage: &S) { let mut val = >::take(key, storage); - f(&mut val); - >::insert(key, &val, storage); - } - } - }; - (($($vis:tt)*) ($traittype:ident as $traitinstance:ident) () (OPTION_TYPE $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> { - type Query = $gettype; - - /// Get the prefix key in storage. - fn prefix() -> &'static [u8] { - stringify!($cratename $name).as_bytes() - } - /// Get the storage key used to fetch a value corresponding to a specific key. - fn key_for(x: &$kty) -> Vec { - let mut key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::prefix().to_vec(); - $crate::codec::Encode::encode_to(x, &mut key); - key - } - - /// Load the value associated with the given key from the map. - fn get(key: &$kty, storage: &S) -> Self::Query { - let key = <$name<$traitinstance> as $crate::storage::generator::StorageMap<$kty, $ty>>::key_for(key); - storage.$getter(&key[..]) - } - - /// Take the value, reading and removing it. - fn take(key: &$kty, storage: &S) -> Self::Query { - 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(key: &$kty, f: F, storage: &S) { - let mut val = >::get(key, storage); - let prev_some = val.is_some(); f(&mut val); - match val { - Some(val) => >::insert(key, &val, storage), - None if prev_some => >::remove(key, storage), - _ => {} - } + + __handle_wrap_internal!($wraptype { + >::insert(key, &val, storage); + } { + match val { + Some(val) => >::insert(key, &val, storage), + None => >::remove(key, storage), + } + }); } } }; @@ -1620,38 +1555,32 @@ mod tests { /// Hello, this is doc! U32 : u32; GETU32 get(u32_getter): u32; -// pub PUBU32 : u32; -// pub GETPUBU32 get(pub_u32_getter): u32; -// U32Default : default u32; + pub PUBU32 : u32; + pub GETPUBU32 get(pub_u32_getter): u32; + U32Default : default u32; GETU32Default get(get_u32_default): default u32; -// pub PUBU32Default : default u32; -// pub GETPUBU32Default get(pub_get_u32_default): default u32; -// U32Required : required u32; -// GETU32Required get(get_u32_required): required u32; -// pub PUBU32Required : required u32; -// pub GETPUBU32Required get(pub_get_u32_required): required u32; -// + pub PUBU32Default : default u32; + pub GETPUBU32Default get(pub_get_u32_default): default u32; + U32Required : required u32; + GETU32Required get(get_u32_required): required u32; + pub PUBU32Required : required u32; + pub GETPUBU32Required get(pub_get_u32_required): required u32; + MAPU32 : map [ u32 => String ]; -// /// Hello, this is doc! -// /// Hello, this is doc 2! -// GETMAPU32 get(map_u32_getter): map [ u32 => String ]; -// pub PUBMAPU32 : map [ u32 => String ]; -// pub GETPUBMAPU32 get(map_pub_u32_getter): map [ u32 => String ]; -// MAPU32Default : default map [ u32 => String ]; + /// Hello, this is doc! + /// Hello, this is doc 2! + GETMAPU32 get(map_u32_getter): map [ u32 => String ]; + pub PUBMAPU32 : map [ u32 => String ]; + pub GETPUBMAPU32 get(map_pub_u32_getter): map [ u32 => String ]; + MAPU32Default : default map [ u32 => String ]; GETMAPU32Default get(map_get_u32_default): default map [ u32 => String ]; -// pub PUBMAPU32Default : default map [ u32 => String ]; -// pub GETPUBMAPU32Default get(map_pub_get_u32_default): default map [ u32 => String ]; -// MAPU32Required : required map [ u32 => String ]; -// GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ]; -// pub PUBMAPU32Required : required map [ u32 => String ]; -// pub GETPUBMAPU32Required get(map_pub_get_u32_required): required map [ u32 => String ]; - - } - } + pub PUBMAPU32Default : default map [ u32 => String ]; + pub GETPUBMAPU32Default get(map_pub_get_u32_default): default map [ u32 => String ]; + MAPU32Required : required map [ u32 => String ]; + GETMAPU32Required get(map_get_u32_required): required map [ u32 => String ]; + pub PUBMAPU32Required : required map [ u32 => String ]; + pub GETPUBMAPU32Required get(map_pub_get_u32_required): required map [ u32 => String ]; - impl Module { - fn foo() { -// >::mutate(|v| println!("{}", v)); } } @@ -1692,9 +1621,9 @@ mod tests { #[test] fn store_json_metadata() { - let _metadata = Module::::store_json_metadata(); -// assert_eq!(EXPECTED_METADATA, metadata); -// let _: serde::de::IgnoredAny = -// serde_json::from_str(metadata).expect("Is valid json syntax"); + let metadata = Module::::store_json_metadata(); + assert_eq!(EXPECTED_METADATA, metadata); + let _: serde::de::IgnoredAny = + serde_json::from_str(metadata).expect("Is valid json syntax"); } } From 59a1e57b4b70e61265704682135130fe25d97dcb Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Sun, 9 Sep 2018 18:57:12 +0800 Subject: [PATCH 8/8] add sample for StorageValue --- substrate/runtime/example/src/lib.rs | 61 +++++++++++++++++++++------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/substrate/runtime/example/src/lib.rs b/substrate/runtime/example/src/lib.rs index a7953074c1048..a195f8e2eadb3 100644 --- a/substrate/runtime/example/src/lib.rs +++ b/substrate/runtime/example/src/lib.rs @@ -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 { 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 Module { 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 = >::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. - >::put(new_dummy); + // >::put(new_dummy); // Will also work with a reference: // >::put(&new_dummy); + // Here's the new one of read and then modify the value. + >::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 Module { 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. + >::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 OnFinalise for Module { pub struct GenesisConfig { /// 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 Default for GenesisConfig { fn default() -> Self { GenesisConfig { dummy: Default::default(), + foo: Default::default(), } } } @@ -311,7 +333,8 @@ impl runtime_primitives::BuildStorage for GenesisConfig fn build_storage(self) -> ::std::result::Result { use codec::Encode; Ok(map![ - Self::hash(>::key()).to_vec() => self.dummy.encode() + Self::hash(>::key()).to_vec() => self.dummy.encode(), + Self::hash(>::key()).to_vec() => self.foo.encode() ]) } } @@ -369,12 +392,13 @@ mod tests { t.extend(balances::GenesisConfig::::default().build_storage().unwrap()); t.extend(GenesisConfig::{ 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. >::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); + }); + } }