Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: compute pallet/storage prefix hash at compile time #1539

Merged
merged 26 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6b8cacf
wip
yjhmelody Sep 13, 2023
2085d3f
feat: compile time two128 for storage prefix and pallet prefix
yjhmelody Sep 13, 2023
8cef0a2
fix `storage_prefix_hash`
yjhmelody Sep 13, 2023
2852706
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 13, 2023
8d72a7d
Update substrate/frame/support/src/traits/storage.rs
yjhmelody Sep 13, 2023
9fd6bab
Update substrate/frame/support/src/traits/storage.rs
yjhmelody Sep 13, 2023
23af461
".git/.scripts/commands/fmt/fmt.sh"
Sep 13, 2023
5f0e7ad
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 14, 2023
6e7a2e0
minor improve
yjhmelody Sep 14, 2023
2f486ff
rename all `module_prefix` to `pallet_prefix`
yjhmelody Sep 14, 2023
cc7337e
add `name_hash` to `PalletInfoAccess`
yjhmelody Sep 14, 2023
c81c7cd
impl `name_hash`
yjhmelody Sep 14, 2023
ab74491
fmt
yjhmelody Sep 14, 2023
3ff7d98
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 14, 2023
7f542a5
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 18, 2023
2eed609
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 21, 2023
63974e2
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 25, 2023
3d3b99d
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 25, 2023
891d7c2
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 26, 2023
32888bd
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 27, 2023
5394c97
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 30, 2023
be2e302
Merge branch 'master' into comptime-storage-prefix
yjhmelody Sep 30, 2023
2eb3840
Merge branch 'master' into comptime-storage-prefix
ggwpez Oct 1, 2023
44c8c05
Merge branch 'master' into comptime-storage-prefix
yjhmelody Oct 1, 2023
18f13e6
`fn prefix_hash() -> [u8; 32]`
yjhmelody Oct 2, 2023
ccfadd5
Merge branch 'master' into comptime-storage-prefix
yjhmelody Oct 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions substrate/frame/support/procedural/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ frame-support-procedural-tools = { path = "tools" }
proc-macro-warning = { version = "0.4.2", default-features = false }
macro_magic = { version = "0.4.2", features = ["proc_support"] }
expander = "2.0.0"
sp-core-hashing = { path = "../../../primitives/core/hashing" }

[features]
default = [ "std" ]
Expand Down
38 changes: 27 additions & 11 deletions substrate/frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
mod expand;
mod parse;

use crate::pallet::parse::helper::two128_str;
use cfg_expr::Predicate;
use frame_support_procedural_tools::{
generate_crate_access, generate_crate_access_2018, generate_hidden_includes,
Expand Down Expand Up @@ -403,17 +404,19 @@ fn construct_runtime_final_expansion(
let integrity_test = decl_integrity_test(&scrate);
let static_assertions = decl_static_assertions(&name, &pallets, &scrate);

let warning =
where_section.map_or(None, |where_section| {
Some(proc_macro_warning::Warning::new_deprecated("WhereSection")
.old("use a `where` clause in `construct_runtime`")
.new("use `frame_system::Config` to set the `Block` type and delete this clause.
It is planned to be removed in December 2023")
.help_links(&["https://github.com/paritytech/substrate/pull/14437"])
.span(where_section.span)
.build(),
let warning = where_section.map_or(None, |where_section| {
Some(
proc_macro_warning::Warning::new_deprecated("WhereSection")
.old("use a `where` clause in `construct_runtime`")
.new(
"use `frame_system::Config` to set the `Block` type and delete this clause.
It is planned to be removed in December 2023",
)
.help_links(&["https://github.com/paritytech/substrate/pull/14437"])
.span(where_section.span)
.build(),
)
});
});

let res = quote!(
#warning
Expand Down Expand Up @@ -659,14 +662,14 @@ fn decl_all_pallets<'a>(
#( #all_pallets_reversed_with_system_first )*
)
}

fn decl_pallet_runtime_setup(
runtime: &Ident,
pallet_declarations: &[Pallet],
scrate: &TokenStream2,
) -> TokenStream2 {
let names = pallet_declarations.iter().map(|d| &d.name).collect::<Vec<_>>();
let name_strings = pallet_declarations.iter().map(|d| d.name.to_string());
let name_hashes = pallet_declarations.iter().map(|d| two128_str(&d.name.to_string()));
let module_names = pallet_declarations.iter().map(|d| d.path.module_name());
let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize);
let pallet_structs = pallet_declarations
Expand Down Expand Up @@ -699,6 +702,7 @@ fn decl_pallet_runtime_setup(
pub struct PalletInfo;

impl #scrate::traits::PalletInfo for PalletInfo {

fn index<P: 'static>() -> Option<usize> {
let type_id = #scrate::__private::sp_std::any::TypeId::of::<P>();
#(
Expand All @@ -723,6 +727,18 @@ fn decl_pallet_runtime_setup(
None
}

fn name_hash<P: 'static>() -> Option<[u8; 16]> {
let type_id = #scrate::__private::sp_std::any::TypeId::of::<P>();
#(
#pallet_attrs
if type_id == #scrate::__private::sp_std::any::TypeId::of::<#names>() {
return Some(#name_hashes)
}
)*

None
}

fn module_name<P: 'static>() -> Option<&'static str> {
let type_id = #scrate::__private::sp_std::any::TypeId::of::<P>();
#(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
use crate::{
counter_prefix,
pallet::{
parse::storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
parse::{
helper::two128_str,
storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
},
Def,
},
};
Expand Down Expand Up @@ -638,6 +641,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
Metadata::CountedMap { .. } => {
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)*
#[doc(hidden)]
Expand All @@ -656,7 +660,19 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}

fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}

const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance
Expand All @@ -670,6 +686,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
Metadata::CountedNMap { .. } => {
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)*
#[doc(hidden)]
Expand All @@ -688,7 +705,17 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageNMapInstance
Expand All @@ -702,6 +729,7 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
_ => proc_macro2::TokenStream::default(),
};

let storage_prefix_hash = two128_str(&prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#maybe_counter

Expand All @@ -722,7 +750,19 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}

fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}

const STORAGE_PREFIX: &'static str = #prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
)
});
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/support/procedural/src/pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! to user defined types. And also crate new types and implement block.

mod expand;
mod parse;
pub(crate) mod parse;
bkchr marked this conversation as resolved.
Show resolved Hide resolved

pub use parse::{composite::keyword::CompositeKeyword, Def};
use syn::spanned::Spanned;
Expand Down
16 changes: 15 additions & 1 deletion substrate/frame/support/procedural/src/pallet/parse/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use quote::ToTokens;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::spanned::Spanned;

/// List of additional token to be used for parsing.
Expand Down Expand Up @@ -610,3 +611,16 @@ pub fn check_pallet_call_return_type(type_: &syn::Type) -> syn::Result<()> {

syn::parse2::<Checker>(type_.to_token_stream()).map(|_| ())
}

pub(crate) fn two128_str(s: &str) -> TokenStream {
bytes_to_array(sp_core_hashing::twox_128(s.as_bytes()).into_iter())
}

pub(crate) fn bytes_to_array(bytes: impl IntoIterator<Item = u8>) -> TokenStream {
let bytes = bytes.into_iter();

quote!(
[ #( #bytes ),* ]
)
.into()
}
bkchr marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 10 additions & 1 deletion substrate/frame/support/procedural/src/storage_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

//! Implementation of the `storage_alias` attribute macro.

use crate::counter_prefix;
use crate::{counter_prefix, pallet::parse::helper};
use frame_support_procedural_tools::generate_crate_access_2018;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
Expand Down Expand Up @@ -619,6 +619,7 @@ fn generate_storage_instance(
let counter_code = is_counted_map.then(|| {
let counter_name = Ident::new(&counter_prefix(&name_str), Span::call_site());
let counter_storage_name_str = counter_prefix(&storage_name_str);
let storage_prefix_hash = helper::two128_str(&counter_storage_name_str);

quote! {
#visibility struct #counter_name< #impl_generics >(
Expand All @@ -633,6 +634,9 @@ fn generate_storage_instance(
}

const STORAGE_PREFIX: &'static str = #counter_storage_name_str;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}

impl<#impl_generics> #crate_::storage::types::CountedStorageMapInstance
Expand All @@ -643,6 +647,8 @@ fn generate_storage_instance(
}
});

let storage_prefix_hash = helper::two128_str(&storage_name_str);

// Implement `StorageInstance` trait.
let code = quote! {
#[allow(non_camel_case_types)]
Expand All @@ -658,6 +664,9 @@ fn generate_storage_instance(
}

const STORAGE_PREFIX: &'static str = #storage_name_str;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}

#counter_code
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/support/src/storage/generator/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];

// TODO: use [u8; 32]?
/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
fn prefix_hash() -> Vec<u8> {
let result = storage_prefix(Self::module_prefix(), Self::storage_prefix());
result.to_vec()
storage_prefix(Self::module_prefix(), Self::storage_prefix()).to_vec()
}

/// Convert an optional value retrieved from storage to the type queried.
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/support/src/storage/generator/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ pub trait StorageMap<K: FullEncode, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];

// TODO: use [u8; 32]?
/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
Copy link
Contributor

@KiChjang KiChjang Oct 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By removing the default implementation, we can no longer guarantee that the full prefix is "just the hash of pallet_prefix concatenated to the hash of storage_prefix".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was it removed in the first place? I see no explanation and commit message is unhelpful "minor improve" 😕

fn prefix_hash() -> Vec<u8> {
let result = storage_prefix(Self::module_prefix(), Self::storage_prefix());
result.to_vec()
storage_prefix(Self::module_prefix(), Self::storage_prefix()).to_vec()
}

/// Convert an optional value retrieved from storage to the type queried.
Expand Down
1 change: 1 addition & 0 deletions substrate/frame/support/src/storage/generator/nmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub trait StorageNMap<K: KeyGenerator, V: FullCodec> {
/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];

// TODO: use [u8; 32]?
/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// `storage_prefix`.
fn prefix_hash() -> Vec<u8> {
Expand Down
5 changes: 5 additions & 0 deletions substrate/frame/support/src/storage/types/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ where
fn storage_prefix() -> &'static [u8] {
Prefix::STORAGE_PREFIX.as_bytes()
}

fn prefix_hash() -> Vec<u8> {
Prefix::prefix_hash().to_vec()
}

fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
QueryKind::from_optional_value_to_query(v)
}
Expand Down
3 changes: 3 additions & 0 deletions substrate/frame/support/src/storage/types/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ where
fn storage_prefix() -> &'static [u8] {
Prefix::STORAGE_PREFIX.as_bytes()
}
fn prefix_hash() -> Vec<u8> {
Prefix::prefix_hash().to_vec()
}
fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
QueryKind::from_optional_value_to_query(v)
}
Expand Down
4 changes: 4 additions & 0 deletions substrate/frame/support/src/storage/types/nmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ where
fn storage_prefix() -> &'static [u8] {
Prefix::STORAGE_PREFIX.as_bytes()
}

fn prefix_hash() -> Vec<u8> {
Prefix::prefix_hash().to_vec()
}
fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
QueryKind::from_optional_value_to_query(v)
}
Expand Down
3 changes: 3 additions & 0 deletions substrate/frame/support/src/storage/types/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ where
fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
QueryKind::from_query_to_optional_value(v)
}
fn storage_value_final_key() -> [u8; 32] {
Prefix::prefix_hash()
}
}

impl<Prefix, Value, QueryKind, OnEmpty> StorageValue<Prefix, Value, QueryKind, OnEmpty>
Expand Down
2 changes: 2 additions & 0 deletions substrate/frame/support/src/traits/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub trait PalletInfo {
fn index<P: 'static>() -> Option<usize>;
/// Convert the given pallet `P` into its name as configured in the runtime.
fn name<P: 'static>() -> Option<&'static str>;
/// The two128 hash of name.
fn name_hash<P: 'static>() -> Option<[u8; 16]>;
/// Convert the given pallet `P` into its Rust module name as used in `construct_runtime!`.
fn module_name<P: 'static>() -> Option<&'static str>;
/// Convert the given pallet `P` into its containing crate version.
Expand Down
25 changes: 25 additions & 0 deletions substrate/frame/support/src/traits/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,33 @@ pub trait StorageInstance {
/// Prefix of a pallet to isolate it from other pallets.
fn pallet_prefix() -> &'static str;

/// Return the prefix hash of pallet instance.
/// NOTE: This hash must be `twox_128(pallet_prefix())`
/// Should not impl this function by hand. Only use the default or macro generated impls.
fn pallet_prefix_hash() -> [u8; 16] {
yjhmelody marked this conversation as resolved.
Show resolved Hide resolved
yjhmelody marked this conversation as resolved.
Show resolved Hide resolved
sp_io::hashing::twox_128(Self::pallet_prefix().as_bytes())
}
bkchr marked this conversation as resolved.
Show resolved Hide resolved

/// Prefix given to a storage to isolate from other storages in the pallet.
const STORAGE_PREFIX: &'static str;

/// Return the prefix hash of storage instance.
/// NOTE: This hash must be `twox_128(STORAGE_PREFIX)`.
yjhmelody marked this conversation as resolved.
Show resolved Hide resolved
fn storage_prefix_hash() -> [u8; 16] {
sp_io::hashing::twox_128(Self::pallet_prefix().as_bytes())
yjhmelody marked this conversation as resolved.
Show resolved Hide resolved
}

/// Return the prefix hash of storage instance instance.
///
/// NOTE: This hash must be `twox_128(pallet_prefix())++twox_128(STORAGE_PREFIX)`.
/// Should not impl this function by hand. Only use the default or macro generated impls.
fn prefix_hash() -> [u8; 32] {
let mut final_key = [0u8; 32];
final_key[..16].copy_from_slice(&Self::pallet_prefix_hash());
final_key[16..].copy_from_slice(&Self::storage_prefix_hash());

final_key
}
}

/// Metadata about storage from the runtime.
Expand Down
Loading