From f4035cd5ac862d63113f6fb2806b691895254321 Mon Sep 17 00:00:00 2001 From: thiolliere <gui.thiolliere@gmail.com> Date: Wed, 27 Nov 2019 19:23:20 +0100 Subject: [PATCH] Implement all storage after prefix (#4227) * Implement all storage after prefix * fix test, bump version and fix doc * bump metadata version * Update frame/support/procedural/src/storage/storage_struct.rs --- substrate/bin/node/runtime/src/lib.rs | 2 +- substrate/frame/executive/src/lib.rs | 2 +- substrate/frame/metadata/src/lib.rs | 12 +- substrate/frame/support/procedural/src/lib.rs | 46 +++++- .../procedural/src/storage/instance_trait.rs | 73 +-------- .../procedural/src/storage/storage_struct.rs | 73 +++++---- .../src/storage/generator/double_map.rs | 31 +++- .../src/storage/generator/linked_map.rs | 154 +++++++++--------- .../support/src/storage/generator/map.rs | 35 ++-- .../support/src/storage/generator/mod.rs | 10 +- .../support/src/storage/generator/value.rs | 20 ++- substrate/frame/support/src/storage/mod.rs | 2 +- .../frame/support/test/tests/final_keys.rs | 146 ++++++++--------- .../frame/support/test/tests/instance.rs | 11 -- substrate/utils/frame/rpc/support/src/lib.rs | 4 +- 15 files changed, 303 insertions(+), 318 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 8e405739167..fbb690a622e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -78,7 +78,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 195, + spec_version: 196, impl_version: 196, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/frame/executive/src/lib.rs b/substrate/frame/executive/src/lib.rs index f6b50143a70..d160bd7bdd4 100644 --- a/substrate/frame/executive/src/lib.rs +++ b/substrate/frame/executive/src/lib.rs @@ -525,7 +525,7 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!("f0d1d66255c2e5b40580eb8b93ddbe732491478487f85e358e1d167d369e398e").into(), + state_root: hex!("c6b01b27df520ba23adb96e7fc032acb7c586ba1b477c6282de43184111f2091").into(), extrinsics_root: hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into(), digest: Digest { logs: vec![], }, }, diff --git a/substrate/frame/metadata/src/lib.rs b/substrate/frame/metadata/src/lib.rs index d85a6837fc6..113273be028 100644 --- a/substrate/frame/metadata/src/lib.rs +++ b/substrate/frame/metadata/src/lib.rs @@ -342,8 +342,10 @@ pub enum RuntimeMetadata { V6(RuntimeMetadataDeprecated), /// Version 7 for runtime metadata. No longer used. V7(RuntimeMetadataDeprecated), - /// Version 8 for runtime metadata. - V8(RuntimeMetadataV8), + /// Version 8 for runtime metadata. No longer used. + V8(RuntimeMetadataDeprecated), + /// Version 9 for runtime metadata. + V9(RuntimeMetadataV9), } /// Enum that should fail. @@ -367,12 +369,12 @@ impl Decode for RuntimeMetadataDeprecated { /// The metadata of a runtime. #[derive(Eq, Encode, PartialEq, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Decode, Serialize))] -pub struct RuntimeMetadataV8 { +pub struct RuntimeMetadataV9 { pub modules: DecodeDifferentArray<ModuleMetadata>, } /// The latest version of the metadata. -pub type RuntimeMetadataLastVersion = RuntimeMetadataV8; +pub type RuntimeMetadataLastVersion = RuntimeMetadataV9; /// All metadata about an runtime module. #[derive(Clone, PartialEq, Eq, Encode, RuntimeDebug)] @@ -397,6 +399,6 @@ impl Into<primitives::OpaqueMetadata> for RuntimeMetadataPrefixed { impl Into<RuntimeMetadataPrefixed> for RuntimeMetadataLastVersion { fn into(self) -> RuntimeMetadataPrefixed { - RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V8(self)) + RuntimeMetadataPrefixed(META_RESERVED, RuntimeMetadata::V9(self)) } } diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 8f23142beab..506e55fa175 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -56,7 +56,15 @@ use proc_macro::TokenStream; /// * Value: `Foo: type`: Implements the /// [`StorageValue`](../frame_support/storage/trait.StorageValue.html) trait using the /// [`StorageValue generator`](../frame_support/storage/generator/trait.StorageValue.html). -/// The generator `unhashed_key` is `$module_prefix ++ " " ++ $storage_name` +/// +/// The generator is implemented with: +/// * `module_prefix`: module_prefix +/// * `storage_prefix`: storage_name +/// +/// Thus the storage value is finally stored at: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(storage_prefix) +/// ``` /// /// * Map: `Foo: map hasher($hash) type => type`: Implements the /// [`StorageMap`](../frame_support/storage/trait.StorageMap.html) trait using the @@ -69,9 +77,15 @@ use proc_macro::TokenStream; /// with care, see generator documentation. /// /// The generator is implemented with: -/// * `prefix`: `$module_prefix ++ " " ++ $storage_name` +/// * `module_prefix`: $module_prefix +/// * `storage_prefix`: storage_name /// * `Hasher`: $hash /// +/// Thus the keys are stored at: +/// ```nocompile +/// twox128(module_prefix) ++ twox128(storage_prefix) ++ hasher(encode(key)) +/// ``` +/// /// * Linked map: `Foo: linked_map hasher($hash) type => type`: Implements the /// [`StorageLinkedMap`](../frame_support/storage/trait.StorageLinkedMap.html) trait using the /// [`StorageLinkedMap generator`](../frame_support/storage/generator/trait.StorageLinkedMap.html). @@ -82,15 +96,25 @@ use proc_macro::TokenStream; /// `hasher($hash)` is optional and its default is `blake2_256`. One should use another hasher /// with care, see generator documentation. /// -/// The generator is implemented with: -/// * `prefix`: `$module_prefix ++ " " ++ $storage_name` -/// * `head_key`: `"head of " ++ $module_prefix ++ " " ++ $storage_name` -/// * `Hasher`: $hash -/// /// All key formatting logic can be accessed in a type-agnostic format via the /// [`KeyFormat`](../srml_support/storage/generator/trait.KeyFormat.html) trait, which /// is implemented for the storage linked map type as well. /// +/// The generator key format is implemented with: +/// * `module_prefix`: $module_prefix +/// * `storage_prefix`: storage_name +/// * `head_prefix`: `"HeadOf" ++ storage_name` +/// * `Hasher`: $hash +/// +/// Thus the keys are stored at: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key)) +/// ``` +/// and head is stored at: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(head_prefix) +/// ``` +/// /// * Double map: `Foo: double_map hasher($hash1) u32, $hash2(u32) => u32`: Implements the /// [`StorageDoubleMap`](../frame_support/storage/trait.StorageDoubleMap.html) trait using the /// [`StorageDoubleMap generator`](../frame_support/storage/generator/trait.StorageDoubleMap.html). @@ -111,10 +135,16 @@ use proc_macro::TokenStream; /// Otherwise, other items in storage with the same first key can be compromised. /// /// The generator is implemented with: -/// * `key1_prefix`: `$module_prefix ++ " " ++ $storage_name` +/// * `module_prefix`: $module_prefix +/// * `storage_prefix`: storage_name /// * `Hasher1`: $hash1 /// * `Hasher2`: $hash2 /// +/// Thus keys are stored at: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) +/// ``` +/// /// Supported hashers (ordered from least to best security): /// /// * `twox_64_concat` - TwoX with 64bit + key concatenated. diff --git a/substrate/frame/support/procedural/src/storage/instance_trait.rs b/substrate/frame/support/procedural/src/storage/instance_trait.rs index 1a7add89a4b..abc56092e31 100644 --- a/substrate/frame/support/procedural/src/storage/instance_trait.rs +++ b/substrate/frame/support/procedural/src/storage/instance_trait.rs @@ -19,24 +19,12 @@ use proc_macro2::{TokenStream, Span}; use quote::quote; -use super::{DeclStorageDefExt, StorageLineTypeDef}; +use super::DeclStorageDefExt; const NUMBER_OF_INSTANCE: usize = 16; -const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance"; +pub(crate) const INHERENT_INSTANCE_NAME: &str = "__InherentHiddenInstance"; pub(crate) const DEFAULT_INSTANTIABLE_TRAIT_NAME: &str = "__GeneratedInstantiable"; -// prefix for consts in trait Instance -pub(crate) const PREFIX_FOR: &str = "PREFIX_FOR_"; -pub(crate) const HEAD_KEY_FOR: &str = "HEAD_KEY_FOR_"; - -// Used to generate the const: -// `const $name: &'static str = $value_prefix ++ instance_prefix ++ $value_suffix` -struct InstanceConstDef { - name: syn::Ident, - value_prefix: String, - value_suffix: String, -} - // Used to generate an instance implementation. struct InstanceDef { prefix: String, @@ -47,33 +35,7 @@ struct InstanceDef { pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStream { let mut impls = TokenStream::new(); - let mut const_defs = vec![]; - - for line in def.storage_lines.iter() { - let storage_prefix = format!("{} {}", def.crate_name, line.name); - - let const_name = syn::Ident::new( - &format!("{}{}", PREFIX_FOR, line.name.to_string()), proc_macro2::Span::call_site() - ); - const_defs.push(InstanceConstDef { - name: const_name, - value_prefix: String::new(), - value_suffix: storage_prefix.clone(), - }); - - if let StorageLineTypeDef::LinkedMap(_) = line.storage_type { - let const_name = syn::Ident::new( - &format!("{}{}", HEAD_KEY_FOR, line.name.to_string()), proc_macro2::Span::call_site() - ); - const_defs.push(InstanceConstDef { - name: const_name, - value_prefix: "head of ".into(), - value_suffix: storage_prefix, - }); - } - } - - impls.extend(create_instance_trait(&const_defs, def)); + impls.extend(create_instance_trait(def)); // Implementation of instances. if let Some(module_instance) = &def.module_instance { @@ -95,7 +57,7 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre ); for instance_def in instance_defs { - impls.extend(create_and_impl_instance_struct(scrate, &instance_def, &const_defs, def)); + impls.extend(create_and_impl_instance_struct(scrate, &instance_def, def)); } } @@ -116,27 +78,18 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre instance_struct: inherent_instance, doc: quote!(#[doc(hidden)]), }; - impls.extend(create_and_impl_instance_struct(scrate, &instance_def, &const_defs, def)); + impls.extend(create_and_impl_instance_struct(scrate, &instance_def, def)); } impls } fn create_instance_trait( - const_defs: &[InstanceConstDef], def: &DeclStorageDefExt, ) -> TokenStream { let instance_trait = def.module_instance.as_ref().map(|i| i.instance_trait.clone()) .unwrap_or_else(|| syn::Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); - let mut const_impls = TokenStream::new(); - for const_def in const_defs { - let const_name = &const_def.name; - const_impls.extend(quote! { - const #const_name: &'static str; - }); - } - let optional_hide = if def.module_instance.is_some() { quote!() } else { @@ -151,7 +104,6 @@ fn create_instance_trait( pub trait #instance_trait: 'static { /// The prefix used by any storage entry of an instance. const PREFIX: &'static str; - #const_impls } } } @@ -159,22 +111,8 @@ fn create_instance_trait( fn create_and_impl_instance_struct( scrate: &TokenStream, instance_def: &InstanceDef, - const_defs: &[InstanceConstDef], def: &DeclStorageDefExt, ) -> TokenStream { - let mut const_impls = TokenStream::new(); - - for const_def in const_defs { - let const_value = format!( - "{}{}{}", const_def.value_prefix, instance_def.prefix, const_def.value_suffix - ); - let const_name = &const_def.name; - - const_impls.extend(quote! { - const #const_name: &'static str = #const_value; - }); - } - let instance_trait = def.module_instance.as_ref().map(|i| i.instance_trait.clone()) .unwrap_or_else(|| syn::Ident::new(DEFAULT_INSTANTIABLE_TRAIT_NAME, Span::call_site())); @@ -194,7 +132,6 @@ fn create_and_impl_instance_struct( pub struct #instance_struct; impl #instance_trait for #instance_struct { const PREFIX: &'static str = #prefix; - #const_impls } } } diff --git a/substrate/frame/support/procedural/src/storage/storage_struct.rs b/substrate/frame/support/procedural/src/storage/storage_struct.rs index 5267876a441..017e6cf2ff1 100644 --- a/substrate/frame/support/procedural/src/storage/storage_struct.rs +++ b/substrate/frame/support/procedural/src/storage/storage_struct.rs @@ -16,11 +16,11 @@ //! Implementation of storage structures and implementation of storage traits on them. -use proc_macro2::TokenStream; +use proc_macro2::{TokenStream, Ident, Span}; use quote::quote; use super::{ DeclStorageDefExt, StorageLineTypeDef, - instance_trait::{PREFIX_FOR, HEAD_KEY_FOR}, + instance_trait::INHERENT_INSTANCE_NAME, }; fn from_optional_value_to_query(is_option: bool, default: &Option<syn::Expr>) -> TokenStream { @@ -78,17 +78,14 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre let from_optional_value_to_query = from_optional_value_to_query(line.is_option, &line.default_value); - let final_prefix = if let Some(instance) = def.module_instance.as_ref() { - let instance = &instance.instance_generic; - let const_name = syn::Ident::new( - &format!("{}{}", PREFIX_FOR, line.name.to_string()), proc_macro2::Span::call_site() - ); - quote!( #instance::#const_name.as_bytes() ) + // Contains accessor to instance, used to get prefixes + let instance_or_inherent = if let Some(instance) = def.module_instance.as_ref() { + instance.instance_generic.clone() } else { - let prefix = format!("{} {}", def.crate_name, line.name); - quote!( #prefix.as_bytes() ) + Ident::new(INHERENT_INSTANCE_NAME, Span::call_site()) }; + let storage_name_str = syn::LitStr::new(&line.name.to_string(), line.name.span()); let storage_generator_trait = &line.storage_generator_trait; let storage_struct = &line.storage_struct; @@ -104,8 +101,12 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre { type Query = #query_type; - fn unhashed_key() -> &'static [u8] { - #final_prefix + fn module_prefix() -> &'static [u8] { + #instance_or_inherent::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_str.as_bytes() } fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { @@ -127,8 +128,12 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre type Query = #query_type; type Hasher = #scrate::#hasher; - fn prefix() -> &'static [u8] { - #final_prefix + fn module_prefix() -> &'static [u8] { + #instance_or_inherent::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_str.as_bytes() } fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { @@ -144,30 +149,18 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre StorageLineTypeDef::LinkedMap(map) => { let hasher = map.hasher.to_storage_hasher_struct(); - // make sure to use different prefix for head and elements. - let head_key = if let Some(instance) = def.module_instance.as_ref() { - let instance = &instance.instance_generic; - let const_name = syn::Ident::new( - &format!("{}{}", HEAD_KEY_FOR, line.name.to_string()), proc_macro2::Span::call_site() - ); - quote!( #instance::#const_name.as_bytes() ) - } else { - let prefix = format!("head of {} {}", def.crate_name, line.name); - quote!( #prefix.as_bytes() ) - }; + let head_prefix_str = syn::LitStr::new( + &format!("HeadOf{}", line.name.to_string()), + line.name.span(), + ); quote!( impl<#impl_trait> #scrate::#storage_generator_trait for #storage_struct #optional_storage_where_clause { type Query = #query_type; - type Hasher = #scrate::#hasher; type KeyFormat = Self; - fn prefix() -> &'static [u8] { - #final_prefix - } - fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { #from_optional_value_to_query } @@ -180,8 +173,16 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre impl<#impl_trait> #scrate::storage::generator::LinkedMapKeyFormat for #storage_struct { type Hasher = #scrate::#hasher; - fn head_key() -> &'static [u8] { - #head_key + fn module_prefix() -> &'static [u8] { + #instance_or_inherent::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_str.as_bytes() + } + + fn head_prefix() -> &'static [u8] { + #head_prefix_str.as_bytes() } } ) @@ -199,8 +200,12 @@ pub fn decl_and_impl(scrate: &TokenStream, def: &DeclStorageDefExt) -> TokenStre type Hasher2 = #scrate::#hasher2; - fn key1_prefix() -> &'static [u8] { - #final_prefix + fn module_prefix() -> &'static [u8] { + #instance_or_inherent::PREFIX.as_bytes() + } + + fn storage_prefix() -> &'static [u8] { + #storage_name_str.as_bytes() } fn from_optional_value_to_query(v: Option<#value_type>) -> Self::Query { diff --git a/substrate/frame/support/src/storage/generator/double_map.rs b/substrate/frame/support/src/storage/generator/double_map.rs index 072b530e4cd..28378034b22 100644 --- a/substrate/frame/support/src/storage/generator/double_map.rs +++ b/substrate/frame/support/src/storage/generator/double_map.rs @@ -17,7 +17,7 @@ use rstd::prelude::*; use rstd::borrow::Borrow; use codec::{Ref, FullCodec, FullEncode, Encode, EncodeLike, EncodeAppend}; -use crate::{storage::{self, unhashed}, hash::StorageHasher}; +use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}}; /// Generator for `StorageDoubleMap` used by `decl_storage`. /// @@ -29,7 +29,7 @@ use crate::{storage::{self, unhashed}, hash::StorageHasher}; /// /// Thus value for (key1, key2) is stored at: /// ```nocompile -/// Hasher1(key1_prefix ++ key1) ++ Hasher2(key2) +/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) /// ``` /// /// # Warning @@ -49,8 +49,11 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> { /// Hasher for the second key. type Hasher2: StorageHasher; - /// Get the prefix for first key. - fn key1_prefix() -> &'static [u8]; + /// Module prefix. Used for generating final key. + fn module_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final key. + fn storage_prefix() -> &'static [u8]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option<V>) -> Self::Query; @@ -59,13 +62,23 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> { fn from_query_to_optional_value(v: Self::Query) -> Option<V>; /// Generate the first part of the key used in top storage. - fn storage_double_map_final_key1<KArg1>(k1: KArg1) -> <Self::Hasher1 as StorageHasher>::Output + fn storage_double_map_final_key1<KArg1>(k1: KArg1) -> Vec<u8> where KArg1: EncodeLike<K1>, { - let mut final_key1 = Self::key1_prefix().to_vec(); - k1.encode_to(&mut final_key1); - Self::Hasher1::hash(&final_key1) + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = k1.borrow().using_encoded(Self::Hasher1::hash); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key } /// Generate the full key used in top storage. @@ -74,7 +87,7 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> { KArg1: EncodeLike<K1>, KArg2: EncodeLike<K2>, { - let mut final_key = Self::storage_double_map_final_key1(k1).as_ref().to_vec(); + let mut final_key = Self::storage_double_map_final_key1(k1); final_key.extend_from_slice(k2.using_encoded(Self::Hasher2::hash).as_ref()); final_key } diff --git a/substrate/frame/support/src/storage/generator/linked_map.rs b/substrate/frame/support/src/storage/generator/linked_map.rs index cf403496990..fb0603fce76 100644 --- a/substrate/frame/support/src/storage/generator/linked_map.rs +++ b/substrate/frame/support/src/storage/generator/linked_map.rs @@ -15,48 +15,18 @@ // along with Substrate. If not, see <http://www.gnu.org/licenses/>. use codec::{FullCodec, Encode, Decode, EncodeLike, Ref}; -use crate::{storage::{self, unhashed}, hash::StorageHasher, traits::Len}; -use rstd::marker::PhantomData; +use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len}; +use rstd::{prelude::*, marker::PhantomData}; /// Generator for `StorageLinkedMap` used by `decl_storage`. /// -/// # Mapping of keys to a storage path -/// -/// The key for the head of the map is stored at one fixed path: -/// ```nocompile -/// Hasher(head_key) -/// ``` -/// -/// For each key, the value stored under that key is appended with a -/// [`Linkage`](struct.Linkage.html) (which hold previous and next key) at the path: -/// ```nocompile -/// Hasher(prefix ++ key) -/// ``` -/// -/// Enumeration is done by getting the head of the linked map and then iterating getting the -/// value and linkage stored at the key until the found linkage has no next key. -/// -/// # Warning -/// -/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as -/// `blake2_256` must be used. Otherwise, other values in storage can be compromised. +/// By default final key generation rely on `KeyFormat`. pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> { /// The type that get/take returns. type Query; - /// Hasher used to insert into storage. - type Hasher: StorageHasher; - /// The family of key formats used for this map. - type KeyFormat: KeyFormat<Hasher=Self::Hasher>; - - /// Prefix used to prepend each key. - fn prefix() -> &'static [u8]; - - /// The head key of the linked-map. - fn head_key() -> &'static [u8] { - <Self::KeyFormat as KeyFormat>::head_key() - } + type KeyFormat: KeyFormat; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option<V>) -> Self::Query; @@ -65,41 +35,80 @@ pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> { fn from_query_to_optional_value(v: Self::Query) -> Option<V>; /// Generate the full key used in top storage. - fn storage_linked_map_final_key<KeyArg>(key: KeyArg) -> <Self::Hasher as StorageHasher>::Output + fn storage_linked_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8> where KeyArg: EncodeLike<K>, { - <Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(Self::prefix(), &key) + <Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(&key) } /// Generate the hashed key for head - fn storage_linked_map_final_head_key() -> <Self::Hasher as StorageHasher>::Output { + fn storage_linked_map_final_head_key() -> Vec<u8> { <Self::KeyFormat as KeyFormat>::storage_linked_map_final_head_key() } } /// A type-abstracted key format used for a family of linked-map types. +/// +/// # Default mapping of keys to a storage path +/// +/// The key for the head of the map is stored at one fixed path: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(head_prefix) +/// ``` +/// +/// For each key, the value stored under that key is appended with a +/// [`Linkage`](struct.Linkage.html) (which hold previous and next key) at the path: +/// ```nocompile +/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key)) +/// ``` +/// +/// Enumeration is done by getting the head of the linked map and then iterating getting the +/// value and linkage stored at the key until the found linkage has no next key. +/// +/// # Warning +/// +/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as +/// `blake2_256` must be used. Otherwise, other values in storage can be compromised. pub trait KeyFormat { + /// Hasher. Used for generating final key and final head key. type Hasher: StorageHasher; - /// Key used to store linked map head. - fn head_key() -> &'static [u8]; + /// Module prefix. Used for generating final key. + fn module_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final key. + fn storage_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final head key. + fn head_prefix() -> &'static [u8]; /// Generate the full key used in top storage. - fn storage_linked_map_final_key<K>(prefix: &[u8], key: &K) - -> <Self::Hasher as StorageHasher>::Output + fn storage_linked_map_final_key<K>(key: &K) -> Vec<u8> where K: Encode, { - let mut final_key = prefix.to_vec(); - key.encode_to(&mut final_key); - <Self::Hasher as StorageHasher>::hash(&final_key) + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = key.using_encoded(Self::Hasher::hash); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key } - fn storage_linked_map_final_head_key() - -> <Self::Hasher as StorageHasher>::Output - { - <Self::Hasher as StorageHasher>::hash(Self::head_key()) + /// Generate the full key used in top storage to store the head of the linked map. + fn storage_linked_map_final_head_key() -> Vec<u8> { + [ + Twox128::hash(Self::module_prefix()), + Twox128::hash(Self::head_prefix()), + ].concat() } } @@ -135,17 +144,15 @@ struct EncodeLikeLinkage<PKey: EncodeLike<Key>, NKey: EncodeLike<Key>, Key: Enco /// A key-value pair iterator for enumerable map. pub struct Enumerator<K, V, F> { next: Option<K>, - prefix: &'static [u8], _phantom: PhantomData<(V, F)>, } impl<K, V, F> Enumerator<K, V, F> { /// Create an explicit enumerator for testing. #[cfg(test)] - pub fn from_head(head: K, prefix: &'static [u8]) -> Self { + pub fn from_head(head: K) -> Self { Enumerator { next: Some(head), - prefix, _phantom: Default::default(), } } @@ -163,15 +170,15 @@ where let next = self.next.take()?; let (val, linkage): (V, Linkage<K>) = { - let next_full_key = F::storage_linked_map_final_key(self.prefix, &next); + let next_full_key = F::storage_linked_map_final_key(&next); match read_with_linkage::<K, V>(next_full_key.as_ref()) { Some(value) => value, None => { // TODO #3700: error should be handleable. runtime_print!( - "ERROR: Corrupted state: linked map head_key={:?}: \ + "ERROR: Corrupted state: linked map {:?}{:?}: \ next value doesn't exist at {:?}", - F::head_key(), next_full_key.as_ref(), + F::module_prefix(), F::storage_prefix(), next_full_key, ); return None } @@ -187,18 +194,14 @@ where /// /// Takes care of updating previous and next elements points /// as well as updates head if the element is first or last. -fn remove_linkage<K, V, F>(linkage: Linkage<K>, prefix: &[u8]) +fn remove_linkage<K, V, F>(linkage: Linkage<K>) where K: FullCodec, V: FullCodec, F: KeyFormat, { - let next_key = linkage.next.as_ref() - .map(|k| F::storage_linked_map_final_key(prefix, k)) - .map(|x| x.as_ref().to_vec()); - let prev_key = linkage.previous.as_ref() - .map(|k| F::storage_linked_map_final_key(prefix, k)) - .map(|x| x.as_ref().to_vec()); + let next_key = linkage.next.as_ref().map(|k| F::storage_linked_map_final_key(k)); + let prev_key = linkage.previous.as_ref().map(|k| F::storage_linked_map_final_key(k)); if let Some(prev_key) = prev_key { // Retrieve previous element and update `next` @@ -208,9 +211,9 @@ where } else { // TODO #3700: error should be handleable. runtime_print!( - "ERROR: Corrupted state: linked map head_key={:?}: \ + "ERROR: Corrupted state: linked map {:?}{:?}: \ previous value doesn't exist at {:?}", - F::head_key(), prev_key, + F::module_prefix(), F::storage_prefix(), prev_key, ); } } else { @@ -225,9 +228,9 @@ where } else { // TODO #3700: error should be handleable. runtime_print!( - "ERROR: Corrupted state: linked map head_key={:?}: \ + "ERROR: Corrupted state: linked map {:?}{:?}: \ next value doesn't exist at {:?}", - F::head_key(), next_key, + F::module_prefix(), F::storage_prefix(), next_key, ); } } @@ -245,7 +248,7 @@ where /// Generate linkage for newly inserted element. /// /// Takes care of updating head and previous head's pointer. -pub(super) fn new_head_linkage<KeyArg, K, V, F>(key: KeyArg, prefix: &[u8]) -> Linkage<K> +pub(super) fn new_head_linkage<KeyArg, K, V, F>(key: KeyArg) -> Linkage<K> where KeyArg: EncodeLike<K>, K: FullCodec, @@ -255,7 +258,7 @@ where if let Some(head) = read_head::<K, F>() { // update previous head predecessor { - let head_key = F::storage_linked_map_final_key(prefix, &head); + let head_key = F::storage_linked_map_final_key(&head); if let Some((data, linkage)) = read_with_linkage::<K, V>(head_key.as_ref()) { let new_linkage = EncodeLikeLinkage::<_, _, K> { previous: Some(Ref::from(&key)), @@ -266,9 +269,9 @@ where } else { // TODO #3700: error should be handleable. runtime_print!( - "ERROR: Corrupted state: linked map head_key={:?}: \ + "ERROR: Corrupted state: linked map {:?}{:?}: \ head value doesn't exist at {:?}", - F::head_key(), head_key.as_ref(), + F::module_prefix(), F::storage_prefix(), head_key, ); // Thus we consider we are first - update the head and produce empty linkage @@ -333,7 +336,6 @@ where } fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) { - let prefix = Self::prefix(); let final_key1 = Self::storage_linked_map_final_key(Ref::from(&key1)); let final_key2 = Self::storage_linked_map_final_key(Ref::from(&key2)); let full_value_1 = read_with_linkage::<K, V>(final_key1.as_ref()); @@ -348,13 +350,13 @@ where // Remove key and insert the new one. (Some((value, _linkage)), None) => { Self::remove(key1); - let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key2, prefix); + let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key2); unhashed::put(final_key2.as_ref(), &(value, linkage)); } // Remove key and insert the new one. (None, Some((value, _linkage))) => { Self::remove(key2); - let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key1, prefix); + let linkage = new_head_linkage::<_, _, V, G::KeyFormat>(key1); unhashed::put(final_key1.as_ref(), &(value, linkage)); } // No-op. @@ -368,7 +370,7 @@ where // overwrite but reuse existing linkage Some((_data, linkage)) => linkage, // create new linkage - None => new_head_linkage::<_, _, V, G::KeyFormat>(key, Self::prefix()), + None => new_head_linkage::<_, _, V, G::KeyFormat>(key), }; unhashed::put(final_key.as_ref(), &(val, linkage)) } @@ -398,7 +400,7 @@ where let full_value: Option<(V, Linkage<K>)> = unhashed::take(final_key.as_ref()); let value = full_value.map(|(data, linkage)| { - remove_linkage::<K, V, G::KeyFormat>(linkage, Self::prefix()); + remove_linkage::<K, V, G::KeyFormat>(linkage); data }); @@ -408,7 +410,6 @@ where fn enumerate() -> Self::Enumerator { Enumerator::<_, _, G::KeyFormat> { next: read_head::<_, G::KeyFormat>(), - prefix: Self::prefix(), _phantom: Default::default(), } } @@ -436,7 +437,6 @@ where where K2: FullCodec + Clone, V2: Decode, TK: Fn(K2) -> K, TV: Fn(V2) -> V { let head_key = read_head::<K2, G::KeyFormat>().ok_or(None)?; - let prefix = G::prefix(); let mut last_key = None; let mut current_key = head_key.clone(); @@ -451,7 +451,7 @@ where }; loop { - let old_raw_key = G::KeyFormat::storage_linked_map_final_key(prefix, ¤t_key); + let old_raw_key = G::KeyFormat::storage_linked_map_final_key(¤t_key); let x = unhashed::take(old_raw_key.as_ref()); let (val, linkage): (V2, Linkage<K2>) = match x { Some(v) => v, diff --git a/substrate/frame/support/src/storage/generator/map.rs b/substrate/frame/support/src/storage/generator/map.rs index 3c3edac28a4..926fe8748db 100644 --- a/substrate/frame/support/src/storage/generator/map.rs +++ b/substrate/frame/support/src/storage/generator/map.rs @@ -18,13 +18,13 @@ use rstd::prelude::*; use rstd::borrow::Borrow; use codec::{FullCodec, FullEncode, Encode, EncodeLike, Ref, EncodeAppend}; -use crate::{storage::{self, unhashed}, hash::StorageHasher, traits::Len}; +use crate::{storage::{self, unhashed}, hash::{StorageHasher, Twox128}, traits::Len}; /// Generator for `StorageMap` used by `decl_storage`. /// -/// For each key value is stored at: +/// By default each key value is stored at: /// ```nocompile -/// Hasher(prefix ++ key) +/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key)) /// ``` /// /// # Warning @@ -35,11 +35,14 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> { /// The type that get/take returns. type Query; - /// Hasher used to insert into storage. + /// Hasher. Used for generating final key. type Hasher: StorageHasher; - /// Prefix used to prepend each key. - fn prefix() -> &'static [u8]; + /// Module prefix. Used for generating final key. + fn module_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final key. + fn storage_prefix() -> &'static [u8]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option<V>) -> Self::Query; @@ -48,13 +51,23 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> { fn from_query_to_optional_value(v: Self::Query) -> Option<V>; /// Generate the full key used in top storage. - fn storage_map_final_key<KeyArg>(key: KeyArg) -> <Self::Hasher as StorageHasher>::Output + fn storage_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8> where KeyArg: EncodeLike<K>, { - let mut final_key = Self::prefix().to_vec(); - key.borrow().encode_to(&mut final_key); - Self::Hasher::hash(&final_key) + let module_prefix_hashed = Twox128::hash(Self::module_prefix()); + let storage_prefix_hashed = Twox128::hash(Self::storage_prefix()); + let key_hashed = key.borrow().using_encoded(Self::Hasher::hash); + + let mut final_key = Vec::with_capacity( + module_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len() + ); + + final_key.extend_from_slice(&module_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + final_key } } @@ -62,7 +75,7 @@ impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V> type Query = G::Query; fn hashed_key_for<KeyArg: EncodeLike<K>>(key: KeyArg) -> Vec<u8> { - Self::storage_map_final_key(key).as_ref().to_vec() + Self::storage_map_final_key(key) } fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) { diff --git a/substrate/frame/support/src/storage/generator/mod.rs b/substrate/frame/support/src/storage/generator/mod.rs index f546546dc72..2db3e08ccf2 100644 --- a/substrate/frame/support/src/storage/generator/mod.rs +++ b/substrate/frame/support/src/storage/generator/mod.rs @@ -94,22 +94,18 @@ mod tests { let t = GenesisConfig::default().build_storage().unwrap(); TestExternalities::new(t).execute_with(|| { - let prefix = NumberMap::prefix(); - // start with a map of u32 -> u32. for i in 0u32..100u32 { - let final_key = <Format as KeyFormat>::storage_linked_map_final_key( - prefix, &i, - ); + let final_key = <Format as KeyFormat>::storage_linked_map_final_key(&i); - let linkage = linked_map::new_head_linkage::<_, u32, u32, Format>(&i, prefix); + let linkage = linked_map::new_head_linkage::<_, u32, u32, Format>(&i); unhashed::put(final_key.as_ref(), &(&i, linkage)); } let head = linked_map::read_head::<u32, Format>().unwrap(); assert_eq!( - Enumerator::<u32, u32, Format>::from_head(head, prefix).collect::<Vec<_>>(), + Enumerator::<u32, u32, Format>::from_head(head).collect::<Vec<_>>(), (0..100).rev().map(|x| (x, x)).collect::<Vec<_>>(), ); diff --git a/substrate/frame/support/src/storage/generator/value.rs b/substrate/frame/support/src/storage/generator/value.rs index 5ebc25a70af..0cf143bac1f 100644 --- a/substrate/frame/support/src/storage/generator/value.rs +++ b/substrate/frame/support/src/storage/generator/value.rs @@ -21,16 +21,19 @@ use crate::{storage::{self, unhashed}, hash::{Twox128, StorageHasher}, traits::L /// Generator for `StorageValue` used by `decl_storage`. /// -/// Value is stored at: +/// By default value is stored at: /// ```nocompile -/// Twox128(unhashed_key) +/// Twox128(module_prefix) ++ Twox128(storage_prefix) /// ``` pub trait StorageValue<T: FullCodec> { /// The type that get/take returns. type Query; - /// Unhashed key used in storage - fn unhashed_key() -> &'static [u8]; + /// Module prefix. Used for generating final key. + fn module_prefix() -> &'static [u8]; + + /// Storage prefix. Used for generating final key. + fn storage_prefix() -> &'static [u8]; /// Convert an optional value retrieved from storage to the type queried. fn from_optional_value_to_query(v: Option<T>) -> Self::Query; @@ -39,15 +42,18 @@ pub trait StorageValue<T: FullCodec> { fn from_query_to_optional_value(v: Self::Query) -> Option<T>; /// Generate the full key used in top storage. - fn storage_value_final_key() -> [u8; 16] { - Twox128::hash(Self::unhashed_key()) + fn storage_value_final_key() -> [u8; 32] { + let mut final_key = [0u8; 32]; + final_key[0..16].copy_from_slice(&Twox128::hash(Self::module_prefix())); + final_key[16..32].copy_from_slice(&Twox128::hash(Self::storage_prefix())); + final_key } } impl<T: FullCodec, G: StorageValue<T>> storage::StorageValue<T> for G { type Query = G::Query; - fn hashed_key() -> [u8; 16] { + fn hashed_key() -> [u8; 32] { Self::storage_value_final_key() } diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index 91e17767885..88818b84e2e 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -34,7 +34,7 @@ pub trait StorageValue<T: FullCodec> { type Query; /// Get the storage key. - fn hashed_key() -> [u8; 16]; + fn hashed_key() -> [u8; 32]; /// Does the value (explicitly) exist in storage? fn exists() -> bool; diff --git a/substrate/frame/support/test/tests/final_keys.rs b/substrate/frame/support/test/tests/final_keys.rs index c1cf5c651a5..365aa5779d1 100644 --- a/substrate/frame/support/test/tests/final_keys.rs +++ b/substrate/frame/support/test/tests/final_keys.rs @@ -17,7 +17,7 @@ use support::storage::unhashed; use codec::Encode; use support::{StorageDoubleMap, StorageLinkedMap, StorageMap, StorageValue}; -use runtime_io::{TestExternalities, hashing}; +use runtime_io::{TestExternalities, hashing::{twox_128, blake2_128, blake2_256}}; mod no_instance { use codec::{Encode, Decode, EncodeLike}; @@ -89,44 +89,43 @@ mod instance { fn final_keys_no_instance() { TestExternalities::default().execute_with(|| { no_instance::Value::put(1); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(b"FinalKeysNone Value")), Some(1u32)); + let k = [twox_128(b"FinalKeysNone"), twox_128(b"Value")].concat(); + assert_eq!(unhashed::get::<u32>(&k), Some(1u32)); no_instance::Map::insert(1, 2); - let mut k = b"FinalKeysNone Map".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); no_instance::Map2::insert(1, 2); - let mut k = b"FinalKeysNone Map2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"Map2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); - let head = b"head of FinalKeysNone LinkedMap".to_vec(); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), None); + let head = [twox_128(b"FinalKeysNone"), twox_128(b"HeadOfLinkedMap")].concat(); + assert_eq!(unhashed::get::<u32>(&head), None); no_instance::LinkedMap::insert(1, 2); - let mut k = b"FinalKeysNone LinkedMap".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), Some(1u32)); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); + assert_eq!(unhashed::get::<u32>(&head), Some(1u32)); no_instance::LinkedMap2::insert(1, 2); - let mut k = b"FinalKeysNone LinkedMap2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"LinkedMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); no_instance::DoubleMap::insert(&1, &2, &3); - let mut k = b"FinalKeysNone DoubleMap".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::blake2_256(&k).to_vec(); - k.extend(&hashing::blake2_256(&2u32.encode())); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + k.extend(2u32.using_encoded(blake2_256).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); no_instance::DoubleMap2::insert(&1, &2, &3); - let mut k = b"FinalKeysNone DoubleMap2".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::twox_128(&k).to_vec(); - k.extend(&hashing::blake2_128(&2u32.encode())); + let mut k = [twox_128(b"FinalKeysNone"), twox_128(b"DoubleMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + k.extend(2u32.using_encoded(blake2_128).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); }); } @@ -135,44 +134,43 @@ fn final_keys_no_instance() { fn final_keys_default_instance() { TestExternalities::default().execute_with(|| { <instance::Value<instance::DefaultInstance>>::put(1); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(b"FinalKeysSome Value")), Some(1u32)); + let k = [twox_128(b"FinalKeysSome"), twox_128(b"Value")].concat(); + assert_eq!(unhashed::get::<u32>(&k), Some(1u32)); <instance::Map<instance::DefaultInstance>>::insert(1, 2); - let mut k = b"FinalKeysSome Map".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); <instance::Map2<instance::DefaultInstance>>::insert(1, 2); - let mut k = b"FinalKeysSome Map2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"Map2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); - let head = b"head of FinalKeysSome LinkedMap".to_vec(); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), None); + let head = [twox_128(b"FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat(); + assert_eq!(unhashed::get::<u32>(&head), None); <instance::LinkedMap<instance::DefaultInstance>>::insert(1, 2); - let mut k = b"FinalKeysSome LinkedMap".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), Some(1u32)); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); + assert_eq!(unhashed::get::<u32>(&head), Some(1u32)); <instance::LinkedMap2<instance::DefaultInstance>>::insert(1, 2); - let mut k = b"FinalKeysSome LinkedMap2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"LinkedMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); <instance::DoubleMap<instance::DefaultInstance>>::insert(&1, &2, &3); - let mut k = b"FinalKeysSome DoubleMap".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::blake2_256(&k).to_vec(); - k.extend(&hashing::blake2_256(&2u32.encode())); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + k.extend(2u32.using_encoded(blake2_256).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); <instance::DoubleMap2<instance::DefaultInstance>>::insert(&1, &2, &3); - let mut k = b"FinalKeysSome DoubleMap2".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::twox_128(&k).to_vec(); - k.extend(&hashing::blake2_128(&2u32.encode())); + let mut k = [twox_128(b"FinalKeysSome"), twox_128(b"DoubleMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + k.extend(2u32.using_encoded(blake2_128).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); }); } @@ -181,47 +179,43 @@ fn final_keys_default_instance() { fn final_keys_instance_2() { TestExternalities::default().execute_with(|| { <instance::Value<instance::Instance2>>::put(1); - assert_eq!( - unhashed::get::<u32>(&hashing::twox_128(b"Instance2FinalKeysSome Value")), - Some(1u32) - ); + let k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Value")].concat(); + assert_eq!(unhashed::get::<u32>(&k), Some(1u32)); <instance::Map<instance::Instance2>>::insert(1, 2); - let mut k = b"Instance2FinalKeysSome Map".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); <instance::Map2<instance::Instance2>>::insert(1, 2); - let mut k = b"Instance2FinalKeysSome Map2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"Map2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); - let head = b"head of Instance2FinalKeysSome LinkedMap".to_vec(); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), None); + let head = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"HeadOfLinkedMap")].concat(); + assert_eq!(unhashed::get::<u32>(&head), None); <instance::LinkedMap<instance::Instance2>>::insert(1, 2); - let mut k = b"Instance2FinalKeysSome LinkedMap".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&k)), Some(2u32)); - assert_eq!(unhashed::get::<u32>(&hashing::blake2_256(&head)), Some(1u32)); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); + assert_eq!(unhashed::get::<u32>(&head), Some(1u32)); <instance::LinkedMap2<instance::Instance2>>::insert(1, 2); - let mut k = b"Instance2FinalKeysSome LinkedMap2".to_vec(); - k.extend(1u32.encode()); - assert_eq!(unhashed::get::<u32>(&hashing::twox_128(&k)), Some(2u32)); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"LinkedMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + assert_eq!(unhashed::get::<u32>(&k), Some(2u32)); <instance::DoubleMap<instance::Instance2>>::insert(&1, &2, &3); - let mut k = b"Instance2FinalKeysSome DoubleMap".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::blake2_256(&k).to_vec(); - k.extend(&hashing::blake2_256(&2u32.encode())); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap")].concat(); + k.extend(1u32.using_encoded(blake2_256).to_vec()); + k.extend(2u32.using_encoded(blake2_256).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); <instance::DoubleMap2<instance::Instance2>>::insert(&1, &2, &3); - let mut k = b"Instance2FinalKeysSome DoubleMap2".to_vec(); - k.extend(1u32.encode()); - let mut k = hashing::twox_128(&k).to_vec(); - k.extend(&hashing::blake2_128(&2u32.encode())); + let mut k = [twox_128(b"Instance2FinalKeysSome"), twox_128(b"DoubleMap2")].concat(); + k.extend(1u32.using_encoded(twox_128).to_vec()); + k.extend(2u32.using_encoded(blake2_128).to_vec()); assert_eq!(unhashed::get::<u32>(&k), Some(3u32)); }); } diff --git a/substrate/frame/support/test/tests/instance.rs b/substrate/frame/support/test/tests/instance.rs index dc4fded17ed..eff73ad6eaf 100644 --- a/substrate/frame/support/test/tests/instance.rs +++ b/substrate/frame/support/test/tests/instance.rs @@ -472,14 +472,3 @@ fn test_instance_storage_metadata() { let metadata = Module2_2::storage_metadata(); pretty_assertions::assert_eq!(EXPECTED_METADATA, metadata); } - -#[test] -fn instance_prefix_is_prefix_of_entries() { - use module2::Instance; - - let prefix = module2::Instance2::PREFIX; - assert!(module2::Instance2::PREFIX_FOR_Value.starts_with(prefix)); - assert!(module2::Instance2::PREFIX_FOR_Map.starts_with(prefix)); - assert!(module2::Instance2::PREFIX_FOR_LinkedMap.starts_with(prefix)); - assert!(module2::Instance2::PREFIX_FOR_DoubleMap.starts_with(prefix)); -} diff --git a/substrate/utils/frame/rpc/support/src/lib.rs b/substrate/utils/frame/rpc/support/src/lib.rs index ef594b687e2..c9163bdc306 100644 --- a/substrate/utils/frame/rpc/support/src/lib.rs +++ b/substrate/utils/frame/rpc/support/src/lib.rs @@ -108,7 +108,7 @@ impl<V: FullCodec> StorageQuery<V> { /// Create a storage query for a value in a StorageMap. pub fn map<St: StorageMap<K, V>, K: FullEncode>(key: K) -> Self { Self { - key: StorageKey(St::storage_map_final_key(key).as_ref().to_vec()), + key: StorageKey(St::storage_map_final_key(key)), _spook: PhantomData, } } @@ -116,7 +116,7 @@ impl<V: FullCodec> StorageQuery<V> { /// Create a storage query for a value in a StorageLinkedMap. pub fn linked_map<St: StorageLinkedMap<K, V>, K: FullCodec>(key: K) -> Self { Self { - key: StorageKey(St::storage_linked_map_final_key(key).as_ref().to_vec()), + key: StorageKey(St::storage_linked_map_final_key(key)), _spook: PhantomData, } } -- GitLab