Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit c867bc2

Browse files
gui1117bkchr
authored andcommitted
Frame-support storage: make iterations and translate consistent (#5470)
* implementation and factorisation * factorize test * doc * fix bug and improve test * address suggestions
1 parent b805faf commit c867bc2

File tree

4 files changed

+288
-168
lines changed

4 files changed

+288
-168
lines changed

frame/support/src/dispatch.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,7 @@ macro_rules! __dispatch_impl_metadata {
20672067
where $( $other_where_bounds )*
20682068
{
20692069
#[doc(hidden)]
2070+
#[allow(dead_code)]
20702071
pub fn call_functions() -> &'static [$crate::dispatch::FunctionMetadata] {
20712072
$crate::__call_to_functions!($($rest)*)
20722073
}
@@ -2140,6 +2141,7 @@ macro_rules! __impl_module_constants_metadata {
21402141
$mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
21412142
{
21422143
#[doc(hidden)]
2144+
#[allow(dead_code)]
21432145
pub fn module_constants_metadata() -> &'static [$crate::dispatch::ModuleConstantMetadata] {
21442146
// Create the `ByteGetter`s
21452147
$(

frame/support/src/storage/generator/double_map.rs

Lines changed: 84 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use sp_std::prelude::*;
1919
use sp_std::borrow::Borrow;
2020
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike};
21-
use crate::{storage::{self, unhashed, StorageAppend}, Never};
21+
use crate::{storage::{self, unhashed, StorageAppend, PrefixIterator}, Never};
2222
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};
2323

2424
/// Generator for `StorageDoubleMap` used by `decl_storage`.
@@ -213,10 +213,11 @@ impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G where
213213
KArg1: ?Sized + EncodeLike<K1>
214214
{
215215
let prefix = Self::storage_double_map_final_key1(k1);
216-
storage::PrefixIterator::<V> {
216+
storage::PrefixIterator {
217217
prefix: prefix.clone(),
218218
previous_key: prefix,
219-
phantom_data: Default::default(),
219+
drain: false,
220+
closure: |_raw_key, mut raw_value| V::decode(&mut raw_value),
220221
}
221222
}
222223

@@ -322,54 +323,6 @@ impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G where
322323
}
323324
}
324325

325-
/// Iterate over a prefix and decode raw_key and raw_value into `T`.
326-
pub struct MapIterator<T> {
327-
prefix: Vec<u8>,
328-
previous_key: Vec<u8>,
329-
/// If true then value are removed while iterating
330-
drain: bool,
331-
/// Function that take `(raw_key_without_prefix, raw_value)` and decode `T`.
332-
/// `raw_key_without_prefix` is the raw storage key without the prefix iterated on.
333-
closure: fn(&[u8], &[u8]) -> Result<T, codec::Error>,
334-
}
335-
336-
impl<T> Iterator for MapIterator<T> {
337-
type Item = T;
338-
339-
fn next(&mut self) -> Option<Self::Item> {
340-
loop {
341-
let maybe_next = sp_io::storage::next_key(&self.previous_key)
342-
.filter(|n| n.starts_with(&self.prefix));
343-
break match maybe_next {
344-
Some(next) => {
345-
self.previous_key = next;
346-
let raw_value = match unhashed::get_raw(&self.previous_key) {
347-
Some(raw_value) => raw_value,
348-
None => {
349-
frame_support::print("ERROR: next_key returned a key with no value in MapIterator");
350-
continue
351-
}
352-
};
353-
if self.drain {
354-
unhashed::kill(&self.previous_key)
355-
}
356-
let raw_key_without_prefix = &self.previous_key[self.prefix.len()..];
357-
let item = match (self.closure)(raw_key_without_prefix, &raw_value[..]) {
358-
Ok(item) => item,
359-
Err(_e) => {
360-
frame_support::print("ERROR: (key, value) failed to decode in MapIterator");
361-
continue
362-
}
363-
};
364-
365-
Some(item)
366-
}
367-
None => None,
368-
}
369-
}
370-
}
371-
}
372-
373326
impl<
374327
K1: FullCodec,
375328
K2: FullCodec,
@@ -379,8 +332,8 @@ impl<
379332
G::Hasher1: ReversibleStorageHasher,
380333
G::Hasher2: ReversibleStorageHasher
381334
{
382-
type PrefixIterator = MapIterator<(K2, V)>;
383-
type Iterator = MapIterator<(K1, K2, V)>;
335+
type PrefixIterator = PrefixIterator<(K2, V)>;
336+
type Iterator = PrefixIterator<(K1, K2, V)>;
384337

385338
fn iter_prefix(k1: impl EncodeLike<K1>) -> Self::PrefixIterator {
386339
let prefix = G::storage_double_map_final_key1(k1);
@@ -423,34 +376,54 @@ impl<
423376
iterator
424377
}
425378

426-
fn translate<O: Decode, F: Fn(O) -> Option<V>>(f: F) {
379+
fn translate<O: Decode, F: Fn(K1, K2, O) -> Option<V>>(f: F) {
427380
let prefix = G::prefix_hash();
428381
let mut previous_key = prefix.clone();
429-
loop {
430-
match sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) {
431-
Some(next) => {
432-
previous_key = next;
433-
let maybe_value = unhashed::get::<O>(&previous_key);
434-
match maybe_value {
435-
Some(value) => match f(value) {
436-
Some(new) => unhashed::put::<V>(&previous_key, &new),
437-
None => unhashed::kill(&previous_key),
438-
},
439-
None => continue,
440-
}
441-
}
442-
None => return,
382+
while let Some(next) = sp_io::storage::next_key(&previous_key)
383+
.filter(|n| n.starts_with(&prefix))
384+
{
385+
previous_key = next;
386+
let value = match unhashed::get::<O>(&previous_key) {
387+
Some(value) => value,
388+
None => {
389+
crate::debug::error!("Invalid translate: fail to decode old value");
390+
continue
391+
},
392+
};
393+
let mut key_material = G::Hasher1::reverse(&previous_key[prefix.len()..]);
394+
let key1 = match K1::decode(&mut key_material) {
395+
Ok(key1) => key1,
396+
Err(_) => {
397+
crate::debug::error!("Invalid translate: fail to decode key1");
398+
continue
399+
},
400+
};
401+
402+
let mut key2_material = G::Hasher2::reverse(&key_material);
403+
let key2 = match K2::decode(&mut key2_material) {
404+
Ok(key2) => key2,
405+
Err(_) => {
406+
crate::debug::error!("Invalid translate: fail to decode key2");
407+
continue
408+
},
409+
};
410+
411+
match f(key1, key2, value) {
412+
Some(new) => unhashed::put::<V>(&previous_key, &new),
413+
None => unhashed::kill(&previous_key),
443414
}
444415
}
445416
}
446417
}
447418

448419
/// Test iterators for StorageDoubleMap
449420
#[cfg(test)]
450-
#[allow(dead_code)]
451421
mod test_iterators {
452422
use codec::{Encode, Decode};
453-
use crate::storage::{generator::StorageDoubleMap, IterableStorageDoubleMap, unhashed};
423+
use crate::{
424+
hash::StorageHasher,
425+
storage::{generator::StorageDoubleMap, IterableStorageDoubleMap, unhashed},
426+
};
454427

455428
pub trait Trait {
456429
type Origin;
@@ -466,7 +439,7 @@ mod test_iterators {
466439

467440
crate::decl_storage! {
468441
trait Store for Module<T: Trait> as Test {
469-
DoubleMap: double_map hasher(blake2_128_concat) u16, hasher(blake2_128_concat) u32 => u64;
442+
DoubleMap: double_map hasher(blake2_128_concat) u16, hasher(twox_64_concat) u32 => u64;
470443
}
471444
}
472445

@@ -484,11 +457,6 @@ mod test_iterators {
484457
prefix
485458
}
486459

487-
fn key_in_prefix(mut prefix: Vec<u8>) -> Vec<u8> {
488-
prefix.push(0);
489-
prefix
490-
}
491-
492460
#[test]
493461
fn double_map_reversible_reversible_iteration() {
494462
sp_io::TestExternalities::default().execute_with(|| {
@@ -534,22 +502,59 @@ mod test_iterators {
534502

535503
assert_eq!(
536504
DoubleMap::iter_prefix(k1).collect::<Vec<_>>(),
537-
vec![(0, 0), (2, 2), (1, 1), (3, 3)],
505+
vec![(1, 1), (2, 2), (0, 0), (3, 3)],
538506
);
539507

540508
assert_eq!(
541509
DoubleMap::iter_prefix_values(k1).collect::<Vec<_>>(),
542-
vec![0, 2, 1, 3],
510+
vec![1, 2, 0, 3],
543511
);
544512

545513
assert_eq!(
546514
DoubleMap::drain_prefix(k1).collect::<Vec<_>>(),
547-
vec![(0, 0), (2, 2), (1, 1), (3, 3)],
515+
vec![(1, 1), (2, 2), (0, 0), (3, 3)],
548516
);
549517

550518
assert_eq!(DoubleMap::iter_prefix(k1).collect::<Vec<_>>(), vec![]);
551519
assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64));
552520
assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64));
521+
522+
// Translate
523+
let prefix = DoubleMap::prefix_hash();
524+
525+
unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
526+
unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
527+
for i in 0..4 {
528+
DoubleMap::insert(i as u16, i as u32, i as u64);
529+
}
530+
531+
// Wrong key1
532+
unhashed::put(
533+
&[prefix.clone(), vec![1, 2, 3]].concat(),
534+
&3u64.encode()
535+
);
536+
537+
// Wrong key2
538+
unhashed::put(
539+
&[prefix.clone(), crate::Blake2_128Concat::hash(&1u16.encode())].concat(),
540+
&3u64.encode()
541+
);
542+
543+
// Wrong value
544+
unhashed::put(
545+
&[
546+
prefix.clone(),
547+
crate::Blake2_128Concat::hash(&1u16.encode()),
548+
crate::Twox64Concat::hash(&2u32.encode()),
549+
].concat(),
550+
&vec![1],
551+
);
552+
553+
DoubleMap::translate(|_k1, _k2, v: u64| Some(v*2));
554+
assert_eq!(
555+
DoubleMap::iter().collect::<Vec<_>>(),
556+
vec![(3, 3, 6), (0, 0, 0), (2, 2, 4), (1, 1, 2)],
557+
);
553558
})
554559
}
555560
}

0 commit comments

Comments
 (0)