From abe619617bfb050bd72ae3b58ccfddeeb9153e9b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 28 Oct 2019 19:39:13 +0100 Subject: [PATCH 1/7] Add translate item. --- srml/support/src/storage/generator/value.rs | 17 +++++++++++++++++ srml/support/src/storage/mod.rs | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/srml/support/src/storage/generator/value.rs b/srml/support/src/storage/generator/value.rs index 8423503dde20e..3a96c82dc1699 100644 --- a/srml/support/src/storage/generator/value.rs +++ b/srml/support/src/storage/generator/value.rs @@ -60,6 +60,23 @@ impl> storage::StorageValue for G { G::from_optional_value_to_query(value) } + fn translate) -> Option>(f: F) -> Result { + let key = Self::storage_value_final_key(); + + // attempt to get the length directly. + let maybe_old = match unhashed::get_raw(&key) { + Some(old_data) => Some(O::decode(&mut &old_data).ok_or(())?), + None => None, + }; + let maybe_new = f(maybe_old); + if let Some(new) = maybe_new { + new.with_encoded(|d| unhashed::put_raw(&key, d)); + } else { + unhashed::kill(&key); + } + Ok(new) + } + fn put>(val: Arg) { unhashed::put(&Self::storage_value_final_key(), &val) } diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 648009b470e42..69d46ec1f513c 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -41,6 +41,17 @@ pub trait StorageValue { /// Load the value from the provided storage instance. fn get() -> Self::Query; + /// Translate a value from some previous type (`O`) to the current type. + /// + /// `f: F` is the translation function. + /// + /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along + /// with the new value if it could. + /// + /// NOTE: This operates from and to `Option<>` types; no effort is made to respect the default + /// value of the original type. + fn translate) -> Option>(f: F) -> Result; + /// Store a value under this key into the provided storage instance. fn put>(val: Arg); From d2b0edb19c0e0c5a99ced6c3de896c6a3844a6d0 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Tue, 29 Oct 2019 13:54:49 +0100 Subject: [PATCH 2/7] fix --- srml/support/src/storage/generator/value.rs | 12 ++++++------ srml/support/src/storage/mod.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/srml/support/src/storage/generator/value.rs b/srml/support/src/storage/generator/value.rs index 3a96c82dc1699..5ebc25a70af2a 100644 --- a/srml/support/src/storage/generator/value.rs +++ b/srml/support/src/storage/generator/value.rs @@ -16,7 +16,7 @@ #[cfg(not(feature = "std"))] use rstd::prelude::*; -use codec::{FullCodec, Encode, EncodeAppend, EncodeLike}; +use codec::{FullCodec, Encode, EncodeAppend, EncodeLike, Decode}; use crate::{storage::{self, unhashed}, hash::{Twox128, StorageHasher}, traits::Len}; /// Generator for `StorageValue` used by `decl_storage`. @@ -60,21 +60,21 @@ impl> storage::StorageValue for G { G::from_optional_value_to_query(value) } - fn translate) -> Option>(f: F) -> Result { + fn translate) -> Option>(f: F) -> Result, ()> { let key = Self::storage_value_final_key(); // attempt to get the length directly. let maybe_old = match unhashed::get_raw(&key) { - Some(old_data) => Some(O::decode(&mut &old_data).ok_or(())?), + Some(old_data) => Some(O::decode(&mut &old_data[..]).map_err(|_| ())?), None => None, }; let maybe_new = f(maybe_old); - if let Some(new) = maybe_new { - new.with_encoded(|d| unhashed::put_raw(&key, d)); + if let Some(new) = maybe_new.as_ref() { + new.using_encoded(|d| unhashed::put_raw(&key, d)); } else { unhashed::kill(&key); } - Ok(new) + Ok(maybe_new) } fn put>(val: Arg) { diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 69d46ec1f513c..1a3bf702facaa 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -17,7 +17,7 @@ //! Stuff to do with the runtime's storage. use rstd::prelude::*; -use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike}; +use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode}; use crate::traits::Len; #[macro_use] @@ -50,7 +50,7 @@ pub trait StorageValue { /// /// NOTE: This operates from and to `Option<>` types; no effort is made to respect the default /// value of the original type. - fn translate) -> Option>(f: F) -> Result; + fn translate) -> Option>(f: F) -> Result, ()>; /// Store a value under this key into the provided storage instance. fn put>(val: Arg); From e54cba1d10e62287d8fb6f68bac5a64adcbb2424 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 30 Oct 2019 10:15:13 +0100 Subject: [PATCH 3/7] doc --- srml/support/src/storage/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index 1a3bf702facaa..bade74202101c 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -50,6 +50,17 @@ pub trait StorageValue { /// /// NOTE: This operates from and to `Option<>` types; no effort is made to respect the default /// value of the original type. + /// + /// # Warning + /// + /// This function must be used with care as every other call to the storage still contains the + /// old type. + /// + /// # Usage + /// + /// This would typically be called inside the module implementation of on_initialize, while + /// ensuring no usage of this storage are made before the call to on_initialize. + /// (More precisely prior initialized modules doesn't make use of this storage). fn translate) -> Option>(f: F) -> Result, ()>; /// Store a value under this key into the provided storage instance. From 1895cef48958064cfe39a2b368eded7bf33b7f7d Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 30 Oct 2019 10:39:45 +0100 Subject: [PATCH 4/7] fix doc --- srml/support/src/storage/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index bade74202101c..d7cca2c3b3b33 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -53,8 +53,8 @@ pub trait StorageValue { /// /// # Warning /// - /// This function must be used with care as every other call to the storage still contains the - /// old type. + /// This function must be used with care, before being updated the storage still contains the + /// old type, thus other calls (such as `get`) will fail at decoding it. /// /// # Usage /// From 4c95fcf986e31489a96962e425ad77ae0bd0fd07 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 30 Oct 2019 11:36:18 +0100 Subject: [PATCH 5/7] A test added. --- srml/support/src/storage/generator/mod.rs | 55 +++++++++++++++++++++++ srml/support/src/storage/mod.rs | 6 +-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/srml/support/src/storage/generator/mod.rs b/srml/support/src/storage/generator/mod.rs index ab7616158afd8..6af0138d4737a 100644 --- a/srml/support/src/storage/generator/mod.rs +++ b/srml/support/src/storage/generator/mod.rs @@ -30,3 +30,58 @@ pub use linked_map::{StorageLinkedMap, Enumerator, Linkage}; pub use map::StorageMap; pub use double_map::StorageDoubleMap; pub use value::StorageValue; + + +#[cfg(test)] +#[allow(dead_code)] +mod tests { + use runtime_io::TestExternalities; + use crate::storage::{unhashed, generator::StorageValue}; + + struct Runtime {} + pub trait Trait { + type Origin; + type BlockNumber; + } + + impl Trait for Runtime { + type Origin = u32; + type BlockNumber = u32; + } + + decl_module! { + pub struct Module for enum Call where origin: T::Origin {} + } + + crate::decl_storage! { + trait Store for Module as Runtime { + // assume this had a previous signature of `u32`. `ValueOld` acts as a proxy of the old + // value stored in storage. + ValueOld: u32; + // new storage should be `(1111, 1111 * 2)` + Value get(fn value) config(): (u64, u64); + } + } + + #[test] + fn value_translate_works() { + let t = GenesisConfig::default().build_storage().unwrap(); + TestExternalities::new(t).execute_with(|| { + // write and get the encoded value via proxy + ValueOld::put(1111); + let old_key = ValueOld::storage_value_final_key(); + let old_raw_value = unhashed::get_raw(&old_key).unwrap(); + + // put the old value in the new key. + let key = Value::storage_value_final_key(); + unhashed::put_raw(&key, &old_raw_value); + + // translate + let translate_fn = |old: Option| -> Option<(u64, u64)> { + Some(old.map_or_else(|| unimplemented!(), |o| (o.into(), (o*2).into()))) + }; + let _ = Value::translate(translate_fn); + assert_eq!(Value::get(), (1111, 2222)); + }) + } +} diff --git a/srml/support/src/storage/mod.rs b/srml/support/src/storage/mod.rs index bade74202101c..e1c32338ba776 100644 --- a/srml/support/src/storage/mod.rs +++ b/srml/support/src/storage/mod.rs @@ -48,7 +48,7 @@ pub trait StorageValue { /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along /// with the new value if it could. /// - /// NOTE: This operates from and to `Option<>` types; no effort is made to respect the default + /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default /// value of the original type. /// /// # Warning @@ -59,8 +59,8 @@ pub trait StorageValue { /// # Usage /// /// This would typically be called inside the module implementation of on_initialize, while - /// ensuring no usage of this storage are made before the call to on_initialize. - /// (More precisely prior initialized modules doesn't make use of this storage). + /// ensuring **no usage of this storage are made before the call to `on_initialize`**. (More + /// precisely prior initialized modules doesn't make use of this storage). fn translate) -> Option>(f: F) -> Result, ()>; /// Store a value under this key into the provided storage instance. From fa251c5a209324a5c4e1fd9a73b2bbbe1094e3f7 Mon Sep 17 00:00:00 2001 From: Gavin Wood Date: Wed, 30 Oct 2019 15:36:10 +0100 Subject: [PATCH 6/7] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bastian Köcher --- srml/support/src/storage/generator/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srml/support/src/storage/generator/mod.rs b/srml/support/src/storage/generator/mod.rs index 6af0138d4737a..17c345367cdae 100644 --- a/srml/support/src/storage/generator/mod.rs +++ b/srml/support/src/storage/generator/mod.rs @@ -74,11 +74,11 @@ mod tests { // put the old value in the new key. let key = Value::storage_value_final_key(); - unhashed::put_raw(&key, &old_raw_value); + unhashed::put_raw(&key, &1111u32.encode()); // translate let translate_fn = |old: Option| -> Option<(u64, u64)> { - Some(old.map_or_else(|| unimplemented!(), |o| (o.into(), (o*2).into()))) + old.map(|o| (o.into(), (o*2).into())) }; let _ = Value::translate(translate_fn); assert_eq!(Value::get(), (1111, 2222)); From d7b3658e682329e27d9acf4695ccfec6088b3403 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 30 Oct 2019 15:55:11 +0100 Subject: [PATCH 7/7] address suggestion --- srml/support/src/storage/generator/mod.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/srml/support/src/storage/generator/mod.rs b/srml/support/src/storage/generator/mod.rs index 17c345367cdae..1bda791023792 100644 --- a/srml/support/src/storage/generator/mod.rs +++ b/srml/support/src/storage/generator/mod.rs @@ -36,6 +36,7 @@ pub use value::StorageValue; #[allow(dead_code)] mod tests { use runtime_io::TestExternalities; + use codec::Encode; use crate::storage::{unhashed, generator::StorageValue}; struct Runtime {} @@ -55,10 +56,6 @@ mod tests { crate::decl_storage! { trait Store for Module as Runtime { - // assume this had a previous signature of `u32`. `ValueOld` acts as a proxy of the old - // value stored in storage. - ValueOld: u32; - // new storage should be `(1111, 1111 * 2)` Value get(fn value) config(): (u64, u64); } } @@ -67,12 +64,7 @@ mod tests { fn value_translate_works() { let t = GenesisConfig::default().build_storage().unwrap(); TestExternalities::new(t).execute_with(|| { - // write and get the encoded value via proxy - ValueOld::put(1111); - let old_key = ValueOld::storage_value_final_key(); - let old_raw_value = unhashed::get_raw(&old_key).unwrap(); - - // put the old value in the new key. + // put the old value `1111u32` in the storage. let key = Value::storage_value_final_key(); unhashed::put_raw(&key, &1111u32.encode()); @@ -81,6 +73,8 @@ mod tests { old.map(|o| (o.into(), (o*2).into())) }; let _ = Value::translate(translate_fn); + + // new storage should be `(1111, 1111 * 2)` assert_eq!(Value::get(), (1111, 2222)); }) }