mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 15:51:12 +00:00
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
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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![], },
|
||||
},
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -15,22 +15,52 @@
|
||||
// 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
|
||||
/// By default final key generation rely on `KeyFormat`.
|
||||
pub trait StorageLinkedMap<K: FullCodec, V: FullCodec> {
|
||||
/// The type that get/take returns.
|
||||
type Query;
|
||||
|
||||
/// The family of key formats used for this map.
|
||||
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;
|
||||
|
||||
/// Convert a query to an optional value into storage.
|
||||
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) -> Vec<u8>
|
||||
where
|
||||
KeyArg: EncodeLike<K>,
|
||||
{
|
||||
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(&key)
|
||||
}
|
||||
|
||||
/// Generate the hashed key for head
|
||||
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
|
||||
/// Hasher(head_key)
|
||||
/// 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
|
||||
/// Hasher(prefix ++ key)
|
||||
/// 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
|
||||
@@ -40,66 +70,45 @@ use rstd::marker::PhantomData;
|
||||
///
|
||||
/// 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 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()
|
||||
}
|
||||
|
||||
/// Convert an optional value retrieved from storage to the type queried.
|
||||
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
|
||||
|
||||
/// Convert a query to an optional value into storage.
|
||||
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
|
||||
where
|
||||
KeyArg: EncodeLike<K>,
|
||||
{
|
||||
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_key::<KeyArg>(Self::prefix(), &key)
|
||||
}
|
||||
|
||||
/// Generate the hashed key for head
|
||||
fn storage_linked_map_final_head_key() -> <Self::Hasher as StorageHasher>::Output {
|
||||
<Self::KeyFormat as KeyFormat>::storage_linked_map_final_head_key()
|
||||
}
|
||||
}
|
||||
|
||||
/// A type-abstracted key format used for a family of linked-map types.
|
||||
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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<_>>(),
|
||||
);
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user