mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 18:41:05 +00:00
Add translate function for storage prefixed map. (#4555)
* translace values for prefixed storages * improve doc * new impl * update test
This commit is contained in:
@@ -403,6 +403,7 @@ pub trait StoragePrefixedMap<Value: FullCodec> {
|
|||||||
/// Storage prefix. Used for generating final key.
|
/// Storage prefix. Used for generating final key.
|
||||||
fn storage_prefix() -> &'static [u8];
|
fn storage_prefix() -> &'static [u8];
|
||||||
|
|
||||||
|
/// Final full prefix that prefixes all keys.
|
||||||
fn final_prefix() -> [u8; 32] {
|
fn final_prefix() -> [u8; 32] {
|
||||||
let mut final_key = [0u8; 32];
|
let mut final_key = [0u8; 32];
|
||||||
final_key[0..16].copy_from_slice(&Twox128::hash(Self::module_prefix()));
|
final_key[0..16].copy_from_slice(&Twox128::hash(Self::module_prefix()));
|
||||||
@@ -410,10 +411,12 @@ pub trait StoragePrefixedMap<Value: FullCodec> {
|
|||||||
final_key
|
final_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove all value of the storage.
|
||||||
fn remove_all() {
|
fn remove_all() {
|
||||||
sp_io::storage::clear_prefix(&Self::final_prefix())
|
sp_io::storage::clear_prefix(&Self::final_prefix())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iter over all value of the storage.
|
||||||
fn iter() -> PrefixIterator<Value> {
|
fn iter() -> PrefixIterator<Value> {
|
||||||
let prefix = Self::final_prefix();
|
let prefix = Self::final_prefix();
|
||||||
PrefixIterator {
|
PrefixIterator {
|
||||||
@@ -422,6 +425,51 @@ pub trait StoragePrefixedMap<Value: FullCodec> {
|
|||||||
phantom_data: Default::default(),
|
phantom_data: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Translate the values from some previous `OldValue` to the current type.
|
||||||
|
///
|
||||||
|
/// `TV` translates values.
|
||||||
|
///
|
||||||
|
/// Returns `Err` if the map could not be interpreted as the old type, and Ok if it could.
|
||||||
|
/// The `Err` contains the number of value that couldn't be interpreted, those value are
|
||||||
|
/// removed from the map.
|
||||||
|
///
|
||||||
|
/// # Warning
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// 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_values<OldValue, TV>(translate_val: TV) -> Result<(), u32>
|
||||||
|
where OldValue: Decode, TV: Fn(OldValue) -> Value
|
||||||
|
{
|
||||||
|
let prefix = Self::final_prefix();
|
||||||
|
let mut previous_key = prefix.to_vec();
|
||||||
|
let mut errors = 0;
|
||||||
|
while let Some(next_key) = sp_io::storage::next_key(&previous_key)
|
||||||
|
.filter(|n| n.starts_with(&prefix[..]))
|
||||||
|
{
|
||||||
|
if let Some(value) = unhashed::get(&next_key) {
|
||||||
|
unhashed::put(&next_key[..], &translate_val(value));
|
||||||
|
} else {
|
||||||
|
// We failed to read the value. Remove the key and increment errors.
|
||||||
|
unhashed::kill(&next_key[..]);
|
||||||
|
errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_key = next_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errors)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -463,6 +511,7 @@ mod test {
|
|||||||
let k = [twox_128(b"MyModule"), twox_128(b"MyStorage")].concat();
|
let k = [twox_128(b"MyModule"), twox_128(b"MyStorage")].concat();
|
||||||
assert_eq!(MyStorage::final_prefix().to_vec(), k);
|
assert_eq!(MyStorage::final_prefix().to_vec(), k);
|
||||||
|
|
||||||
|
// test iteration
|
||||||
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
|
||||||
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u64);
|
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u64);
|
||||||
@@ -472,9 +521,32 @@ mod test {
|
|||||||
|
|
||||||
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// test removal
|
||||||
MyStorage::remove_all();
|
MyStorage::remove_all();
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
|
||||||
|
// test migration
|
||||||
|
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u32);
|
||||||
|
unhashed::put(&[&k[..], &vec![8][..]].concat(), &2u32);
|
||||||
|
|
||||||
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
MyStorage::translate_values(|v: u32| v as u64).unwrap();
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2]);
|
||||||
|
MyStorage::remove_all();
|
||||||
|
|
||||||
|
// test migration 2
|
||||||
|
unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u128);
|
||||||
|
unhashed::put(&[&k[..], &vec![1, 1][..]].concat(), &2u64);
|
||||||
|
unhashed::put(&[&k[..], &vec![8][..]].concat(), &3u128);
|
||||||
|
unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u32);
|
||||||
|
|
||||||
|
// (contains some value that successfully decoded to u64)
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 2, 3]);
|
||||||
|
assert_eq!(MyStorage::translate_values(|v: u128| v as u64), Err(2));
|
||||||
|
assert_eq!(MyStorage::iter().collect::<Vec<_>>(), vec![1, 3]);
|
||||||
|
MyStorage::remove_all();
|
||||||
|
|
||||||
|
// test that other values are not modified.
|
||||||
assert_eq!(unhashed::get(&key_before[..]), Some(32u64));
|
assert_eq!(unhashed::get(&key_before[..]), Some(32u64));
|
||||||
assert_eq!(unhashed::get(&key_after[..]), Some(33u64));
|
assert_eq!(unhashed::get(&key_after[..]), Some(33u64));
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user