From c19838924ed941de28ea9d6ec25a74ccf207bc65 Mon Sep 17 00:00:00 2001 From: muraca Date: Thu, 26 Jan 2023 17:33:51 -0300 Subject: [PATCH 1/4] mutate_exists for StorageValue with ValueQuery Signed-off-by: muraca --- frame/support/src/lib.rs | 50 ++++++++++++++++++++ frame/support/src/storage/generator/value.rs | 24 ++++++++++ frame/support/src/storage/mod.rs | 6 +++ frame/support/src/storage/types/value.rs | 12 +++++ 4 files changed, 92 insertions(+) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 40bc878cff365..57aea5071ae11 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -874,6 +874,7 @@ pub mod tests { decl_storage! { trait Store for Module as Test { + pub Value get(fn value): u64; pub Data get(fn data) build(|_| vec![(15u32, 42u64)]): map hasher(twox_64_concat) u32 => u64; pub OptionLinkedMap: map hasher(blake2_128_concat) u32 => Option; @@ -946,6 +947,55 @@ pub mod tests { }); } + #[test] + fn storage_value_mutate_exists_should_work() { + new_test_ext().execute_with(|| { + assert!(!Value::exists()); + + Value::mutate_exists(|v| *v = Some(1)); + assert!(Value::exists()); + assert_eq!(Value::get(), 1); + + // removed if mutated to `None` + Value::mutate_exists(|v| *v = None); + assert!(!Value::exists()); + }); + } + + #[test] + fn storage_value_try_mutate_exists_should_work() { + new_test_ext().execute_with(|| { + type TestResult = result::Result<(), &'static str>; + + assert!(!Value::exists()); + + // mutated if `Ok` + assert_ok!(Value::try_mutate_exists(|v| -> TestResult { + *v = Some(1); + Ok(()) + })); + assert!(Value::exists()); + assert_eq!(Value::get(), 1); + + // no-op if `Err` + assert_noop!( + Value::try_mutate_exists(|v| -> TestResult { + *v = Some(2); + Err("nah") + }), + "nah" + ); + assert_eq!(Value::get(), 1); + + // removed if mutated to`None` + assert_ok!(Value::try_mutate_exists(|v| -> TestResult { + *v = None; + Ok(()) + })); + assert!(!Value::exists()); + }); + } + #[test] fn map_issue_3318() { new_test_ext().execute_with(|| { diff --git a/frame/support/src/storage/generator/value.rs b/frame/support/src/storage/generator/value.rs index 55b3487b1324c..4a1fd5c551d3f 100644 --- a/frame/support/src/storage/generator/value.rs +++ b/frame/support/src/storage/generator/value.rs @@ -118,6 +118,30 @@ impl> storage::StorageValue for G { ret } + fn mutate_exists(f: F) -> R + where + F: FnOnce(&mut Option) -> R, + { + Self::try_mutate_exists(|v| Ok::(f(v))) + .expect("`Never` can not be constructed; qed") + } + + fn try_mutate_exists(f: F) -> Result + where + F: FnOnce(&mut Option) -> Result, + { + let mut val = G::from_query_to_optional_value(Self::get()); + + let ret = f(&mut val); + if ret.is_ok() { + match val { + Some(ref val) => Self::put(val), + None => Self::kill(), + } + } + ret + } + fn take() -> G::Query { let key = Self::storage_value_final_key(); let value = unhashed::get(&key); diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index 8c0d6207c3f4d..28f2dee992281 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -114,6 +114,12 @@ pub trait StorageValue { /// Mutate the value if closure returns `Ok` fn try_mutate Result>(f: F) -> Result; + /// Mutate the value. Deletes the item if mutated to a `None`. + fn mutate_exists) -> R>(f: F) -> R; + + /// Mutate the value if closure returns `Ok`. Deletes the item if mutated to a `None`. + fn try_mutate_exists) -> Result>(f: F) -> Result; + /// Clear the storage value. fn kill(); diff --git a/frame/support/src/storage/types/value.rs b/frame/support/src/storage/types/value.rs index f145e9fb30414..15290f1b1e085 100644 --- a/frame/support/src/storage/types/value.rs +++ b/frame/support/src/storage/types/value.rs @@ -142,6 +142,18 @@ where >::try_mutate(f) } + /// Mutate the value. Deletes the item if mutated to a `None`. + pub fn mutate_exists) -> R>(f: F) -> R { + >::mutate_exists(f) + } + + /// Mutate the value if closure returns `Ok`. Deletes the item if mutated to a `None`. + pub fn try_mutate_exists) -> Result>( + f: F, + ) -> Result { + >::try_mutate_exists(f) + } + /// Clear the storage value. pub fn kill() { >::kill() From 7698d7ff30fbe6374b3eb401f8a24cb74d6b5518 Mon Sep 17 00:00:00 2001 From: muraca Date: Fri, 27 Jan 2023 19:03:56 -0300 Subject: [PATCH 2/4] added `#[crate::storage_alias]` to tests Signed-off-by: muraca --- frame/support/src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 57aea5071ae11..31e6f212aa219 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -950,11 +950,14 @@ pub mod tests { #[test] fn storage_value_mutate_exists_should_work() { new_test_ext().execute_with(|| { + #[crate::storage_alias] + pub type Value = StorageValue; + assert!(!Value::exists()); Value::mutate_exists(|v| *v = Some(1)); assert!(Value::exists()); - assert_eq!(Value::get(), 1); + assert_eq!(Value::get(), Some(1)); // removed if mutated to `None` Value::mutate_exists(|v| *v = None); @@ -965,6 +968,9 @@ pub mod tests { #[test] fn storage_value_try_mutate_exists_should_work() { new_test_ext().execute_with(|| { + #[crate::storage_alias] + pub type Value = StorageValue; + type TestResult = result::Result<(), &'static str>; assert!(!Value::exists()); @@ -975,7 +981,7 @@ pub mod tests { Ok(()) })); assert!(Value::exists()); - assert_eq!(Value::get(), 1); + assert_eq!(Value::get(), Some(1)); // no-op if `Err` assert_noop!( @@ -985,7 +991,7 @@ pub mod tests { }), "nah" ); - assert_eq!(Value::get(), 1); + assert_eq!(Value::get(), Some(1)); // removed if mutated to`None` assert_ok!(Value::try_mutate_exists(|v| -> TestResult { From ea19be8d7a5c4609bfa6bed773bdb6cb9fbcb96a Mon Sep 17 00:00:00 2001 From: muraca Date: Fri, 27 Jan 2023 19:28:15 -0300 Subject: [PATCH 3/4] added StorageEntryMetadata Signed-off-by: muraca --- frame/support/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 31e6f212aa219..ec34d29cac901 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1313,6 +1313,13 @@ pub mod tests { PalletStorageMetadata { prefix: "Test", entries: vec![ + StorageEntryMetadata { + name: "Value", + modifier: StorageEntryModifier::Default, + ty: StorageEntryType::Plain(scale_info::meta_type::()), + default: vec![0, 0, 0, 0, 0, 0, 0, 0], + docs: vec![], + }, StorageEntryMetadata { name: "Data", modifier: StorageEntryModifier::Default, From 72320d2219f2d81b9f91007ce08790c4aabbca0c Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Sat, 28 Jan 2023 00:15:06 +0100 Subject: [PATCH 4/4] Update frame/support/src/lib.rs --- frame/support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index ec34d29cac901..e7b2db4aa9b51 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -1316,7 +1316,7 @@ pub mod tests { StorageEntryMetadata { name: "Value", modifier: StorageEntryModifier::Default, - ty: StorageEntryType::Plain(scale_info::meta_type::()), + ty: StorageEntryType::Plain(scale_info::meta_type::()), default: vec![0, 0, 0, 0, 0, 0, 0, 0], docs: vec![], },