Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0b6f313
System.BlockHash
gavofyork Mar 11, 2020
051967a
Fix hash
gavofyork Mar 11, 2020
5fb1aeb
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 11, 2020
3921666
Introduce K/V iteration in all _concat maps
gavofyork Mar 11, 2020
a926a45
Build fixes
gavofyork Mar 11, 2020
e73f349
Ensure migration happens in correct order
gavofyork Mar 11, 2020
1e8230d
Staking.*
gavofyork Mar 12, 2020
855f20e
Vesting.* Offences.*
gavofyork Mar 12, 2020
d195330
Democracy.*
gavofyork Mar 12, 2020
cc6a4d0
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 12, 2020
c82856e
Babe.* Collective.*
gavofyork Mar 12, 2020
13ad20c
Grandpa.*
gavofyork Mar 12, 2020
bdde997
Assets.* Benchmark.* Contracts.* Elections.* Asset.* Nicks.*
gavofyork Mar 12, 2020
2cbc09e
ImOnline.*
gavofyork Mar 12, 2020
182ec5a
Treasury.*
gavofyork Mar 12, 2020
c573e56
Recovery.*
gavofyork Mar 12, 2020
cf69961
Final bits.
gavofyork Mar 12, 2020
c03a485
Docs
gavofyork Mar 12, 2020
0e3d187
Fix one test
gavofyork Mar 12, 2020
990e972
Fix test
gavofyork Mar 12, 2020
4e2acc9
All passing except the UI tests
gavofyork Mar 12, 2020
1c73a1f
Remove linked_map part 1
gavofyork Mar 12, 2020
5108dc9
Remove linked_map
gavofyork Mar 12, 2020
11a8b94
Some iterator utils for double maps.
gavofyork Mar 12, 2020
d14ba60
Remove old migrations
gavofyork Mar 12, 2020
becb495
Introduce tombstone for LinkedMap type
gavofyork Mar 13, 2020
fb97b30
Migration for genesis hash
gavofyork Mar 13, 2020
7ee5cee
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 15, 2020
0d95a1e
Fix build
gavofyork Mar 15, 2020
1e52937
Fix hash
gavofyork Mar 15, 2020
869b18f
Rename Map is_linked -> unused, keeping backwards compat (#5256)
jacogr Mar 16, 2020
9eb0ea3
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 16, 2020
f4e3c00
Update frame/balances/src/lib.rs
gavofyork Mar 16, 2020
43f3fb0
Update frame/elections/src/lib.rs
gavofyork Mar 16, 2020
3e50210
Remove old migration code.
gavofyork Mar 16, 2020
c90efd0
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 16, 2020
fbbcf01
Update frame/system/src/lib.rs
gavofyork Mar 16, 2020
84af903
Update bin/node/runtime/src/lib.rs
gavofyork Mar 16, 2020
9bcf544
Merge branch 'gav-refactor-hashing' of github.com:paritytech/substrat…
gavofyork Mar 16, 2020
12382d8
Fix hash
gavofyork Mar 16, 2020
07e3361
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 16, 2020
e971241
Merge remote-tracking branch 'origin/master' into gav-refactor-hashing
gavofyork Mar 16, 2020
a2ca4ea
fix session migration
rphmeier Mar 16, 2020
c34e064
Fix watning
gavofyork Mar 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Some iterator utils for double maps.
  • Loading branch information
gavofyork committed Mar 12, 2020
commit 11a8b94f53f94f882e1f88e8f0544d756524565e
33 changes: 21 additions & 12 deletions frame/support/procedural/src/storage/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ mod keyword {
syn::custom_keyword!(get);
syn::custom_keyword!(map);
syn::custom_keyword!(double_map);
syn::custom_keyword!(blake2_256);
syn::custom_keyword!(blake2_128);
syn::custom_keyword!(opaque_blake2_256);
syn::custom_keyword!(opaque_blake2_128);
syn::custom_keyword!(blake2_128_concat);
syn::custom_keyword!(twox_256);
syn::custom_keyword!(twox_128);
syn::custom_keyword!(opaque_twox_256);
syn::custom_keyword!(opaque_twox_128);
syn::custom_keyword!(twox_64_concat);
syn::custom_keyword!(identity);
syn::custom_keyword!(hasher);
syn::custom_keyword!(tainted);
syn::custom_keyword!(natural);
syn::custom_keyword!(prehashed);
}

/// Specific `Opt` to implement structure with optional parsing
Expand Down Expand Up @@ -233,32 +236,38 @@ struct DeclStorageDoubleMap {

#[derive(ToTokens, Debug)]
enum Hasher {
Blake2_256(keyword::blake2_256),
Blake2_128(keyword::blake2_128),
Blake2_256(keyword::opaque_blake2_256),
Blake2_128(keyword::opaque_blake2_128),
Blake2_128Concat(keyword::blake2_128_concat),
Twox256(keyword::twox_256),
Twox128(keyword::twox_128),
Twox256(keyword::opaque_twox_256),
Twox128(keyword::opaque_twox_128),
Twox64Concat(keyword::twox_64_concat),
Identity(keyword::identity),
}

impl syn::parse::Parse for Hasher {
fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(keyword::blake2_256) {
if lookahead.peek(keyword::opaque_blake2_256) {
Ok(Self::Blake2_256(input.parse()?))
} else if lookahead.peek(keyword::blake2_128) {
} else if lookahead.peek(keyword::opaque_blake2_128) {
Ok(Self::Blake2_128(input.parse()?))
} else if lookahead.peek(keyword::blake2_128_concat) {
Ok(Self::Blake2_128Concat(input.parse()?))
} else if lookahead.peek(keyword::twox_256) {
} else if lookahead.peek(keyword::opaque_twox_256) {
Ok(Self::Twox256(input.parse()?))
} else if lookahead.peek(keyword::twox_128) {
} else if lookahead.peek(keyword::opaque_twox_128) {
Ok(Self::Twox128(input.parse()?))
} else if lookahead.peek(keyword::twox_64_concat) {
Ok(Self::Twox64Concat(input.parse()?))
} else if lookahead.peek(keyword::identity) {
Ok(Self::Identity(input.parse()?))
} else if lookahead.peek(keyword::tainted) {
Ok(Self::Blake2_128Concat(input.parse()?))
} else if lookahead.peek(keyword::natural) {
Ok(Self::Twox64Concat(input.parse()?))
} else if lookahead.peek(keyword::prehashed) {
Ok(Self::Identity(input.parse()?))
} else {
Err(lookahead.error())
}
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ pub use self::hash::{
StorageHasher
};
pub use self::storage::{
StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap,
IterableStorageMap
StorageValue, StorageMap, StorageDoubleMap, StoragePrefixedMap, IterableStorageMap,
IterableStorageDoubleMap,
};
pub use self::dispatch::{Parameter, Callable, IsSubType};
pub use sp_runtime::{self, ConsensusEngineId, print, traits::Printable};
Expand Down
117 changes: 115 additions & 2 deletions frame/support/src/storage/generator/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@

use sp_std::prelude::*;
use sp_std::borrow::Borrow;
use codec::{Ref, FullCodec, FullEncode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
use codec::{Ref, FullCodec, FullEncode, Decode, Encode, EncodeLike, EncodeAppend};
use crate::{storage::{self, unhashed}, traits::Len};
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};

/// Generator for `StorageDoubleMap` used by `decl_storage`.
///
Expand Down Expand Up @@ -55,6 +56,22 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];

/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
fn prefix_hash() -> Vec<u8> {
let module_prefix_hashed = Twox128::hash(Self::module_prefix());
let storage_prefix_hashed = Twox128::hash(Self::storage_prefix());

let mut result = Vec::with_capacity(
module_prefix_hashed.len() + storage_prefix_hashed.len()
);

result.extend_from_slice(&module_prefix_hashed[..]);
result.extend_from_slice(&storage_prefix_hashed[..]);

result
}

/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;

Expand Down Expand Up @@ -314,7 +331,103 @@ impl<K1, K2, V, G> storage::StorageDoubleMap<K1, K2, V> for G where
unhashed::put(Self::storage_double_map_final_key(key1, key2).as_ref(), &value);
value
})
}
}

/// Utility to iterate through items in a storage map.
pub struct MapIterator<K, V, Hasher> {
prefix: Vec<u8>,
previous_key: Vec<u8>,
drain: bool,
_phantom: ::sp_std::marker::PhantomData<(K, V, Hasher)>,
}

impl<
K: Decode + Sized,
V: Decode + Sized,
Hasher: ReversibleStorageHasher
> Iterator for MapIterator<K, V, Hasher> {
type Item = (K, V);

fn next(&mut self) -> Option<(K, V)> {
loop {
let maybe_next = sp_io::storage::next_key(&self.previous_key)
.filter(|n| n.starts_with(&self.prefix));
break match maybe_next {
Some(next) => {
self.previous_key = next;
match unhashed::get::<V>(&self.previous_key) {
Some(value) => {
if self.drain {
unhashed::kill(&self.previous_key)
}
let mut key_material = Hasher::reverse(&self.previous_key[self.prefix.len()..]);
match K::decode(&mut key_material) {
Ok(key) => Some((key, value)),
Err(_) => continue,
}
}
None => continue,
}
}
None => None,
}
}
}
}

impl<
K1: FullCodec,
K2: FullCodec,
V: FullCodec,
G: StorageDoubleMap<K1, K2, V>,
> storage::IterableStorageDoubleMap<K1, K2, V> for G where
G::Hasher1: ReversibleStorageHasher,
G::Hasher2: ReversibleStorageHasher
{
type Iterator = MapIterator<K2, V, G::Hasher2>;

/// Enumerate all elements in the map.
fn iter(k1: impl EncodeLike<K1>) -> Self::Iterator {
let prefix = G::storage_double_map_final_key1(k1);
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: false,
_phantom: Default::default(),
}
}

/// Enumerate all elements in the map.
fn drain(k1: impl EncodeLike<K1>) -> Self::Iterator {
let prefix = G::storage_double_map_final_key1(k1);
Self::Iterator {
prefix: prefix.clone(),
previous_key: prefix,
drain: true,
_phantom: Default::default(),
}
}

fn translate<O: Decode, F: Fn(O) -> Option<V>>(f: F) {
let prefix = G::prefix_hash();
let mut previous_key = prefix.clone();
loop {
match sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix)) {
Some(next) => {
previous_key = next;
let maybe_value = unhashed::get::<O>(&previous_key);
match maybe_value {
Some(value) => match f(value) {
Some(new) => unhashed::put::<V>(&previous_key, &new),
None => unhashed::kill(&previous_key),
},
None => continue,
}
}
None => return,
}
}
}
}

Expand Down
5 changes: 2 additions & 3 deletions frame/support/src/storage/generator/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
use sp_std::prelude::*;
use sp_std::borrow::Borrow;
use codec::{FullCodec, FullEncode, Decode, Encode, EncodeLike, Ref, EncodeAppend};
use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len};
use crate::hash::ReversibleStorageHasher;
use crate::{storage::{self, unhashed}, traits::Len};
use crate::hash::{StorageHasher, Twox128, ReversibleStorageHasher};

/// Generator for `StorageMap` used by `decl_storage`.
///
Expand Down Expand Up @@ -185,7 +185,6 @@ impl<
None => return,
}
}

}
}

Expand Down
24 changes: 24 additions & 0 deletions frame/support/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,30 @@ pub trait IterableStorageMap<K: FullEncode, V: FullCodec>: StorageMap<K, V> {
fn translate<O: Decode, F: Fn(K, O) -> Option<V>>(f: F);
}

/// A strongly-typed double map in storage whose secondary keys and values can be iterated over.
pub trait IterableStorageDoubleMap<
K1: FullCodec,
K2: FullCodec,
V: FullCodec
>: StorageDoubleMap<K1, K2, V> {
/// The type that iterates over all `(key, value)`.
type Iterator: Iterator<Item = (K2, V)>;

/// Enumerate all elements in the map with first key `k1` in no particular order. If you add or
/// remove values whose first key is `k1` to the map while doing this, you'll get undefined
/// results.
fn iter(k1: impl EncodeLike<K1>) -> Self::Iterator;

/// Remove all elements from the map with first key `k1` and iterate through them in no
/// particular order. If you add elements with first key `k1` to the map while doing this,
/// you'll get undefined results.
fn drain(k1: impl EncodeLike<K1>) -> Self::Iterator;

/// Translate the values of all elements by a function `f`, in the map in no particular order.
/// By returning `None` from `f` for an element, you'll remove it from the map.
fn translate<O: Decode, F: Fn(O) -> Option<V>>(f: F);
}

/// An implementation of a map with a two keys.
///
/// It provides an important ability to efficiently remove all entries
Expand Down