Skip to content

Commit

Permalink
feat: compute pallet/storage prefix hash at compile time (#1539)
Browse files Browse the repository at this point in the history
Since the hash rules of this part of the `pallet_prefix/storage_prefix`
are always fixed, we can put the runtime calculation into compile time.

---
polkadot address: 15ouFh2SHpGbHtDPsJ6cXQfes9Cx1gEFnJJsJVqPGzBSTudr

---------

Co-authored-by: Juan <[email protected]>
Co-authored-by: command-bot <>
Co-authored-by: Oliver Tale-Yazdi <[email protected]>
  • Loading branch information
3 people authored Oct 3, 2023
1 parent 3ea497b commit aad80cc
Show file tree
Hide file tree
Showing 28 changed files with 263 additions and 123 deletions.
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.

2 changes: 1 addition & 1 deletion substrate/client/basic-authorship/src/basic_authorship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub struct ProposerFactory<A, B, C, PR> {
/// The soft deadline indicates where we should stop attempting to add transactions
/// to the block, which exhaust resources. After soft deadline is reached,
/// we switch to a fixed-amount mode, in which after we see `MAX_SKIPPED_TRANSACTIONS`
/// transactions which exhaust resrouces, we will conclude that the block is full.
/// transactions which exhaust resources, we will conclude that the block is full.
soft_deadline_percent: Percent,
telemetry: Option<TelemetryHandle>,
/// When estimating the block size, should the proof be included?
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/bags-list/remote-tests/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ where
.to_string()],
at: None,
hashed_prefixes: vec![
<pallet_staking::Bonded<Runtime>>::prefix_hash(),
<pallet_staking::Ledger<Runtime>>::prefix_hash(),
<pallet_staking::Bonded<Runtime>>::prefix_hash().to_vec(),
<pallet_staking::Ledger<Runtime>>::prefix_hash().to_vec(),
<pallet_staking::Validators<Runtime>>::map_storage_final_prefix(),
<pallet_staking::Nominators<Runtime>>::map_storage_final_prefix(),
],
Expand Down
4 changes: 2 additions & 2 deletions substrate/frame/bags-list/remote-tests/src/try_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub async fn execute<Runtime, Block>(
pallets: vec![pallet_bags_list::Pallet::<Runtime, pallet_bags_list::Instance1>::name()
.to_string()],
hashed_prefixes: vec![
<pallet_staking::Bonded<Runtime>>::prefix_hash(),
<pallet_staking::Ledger<Runtime>>::prefix_hash(),
<pallet_staking::Bonded<Runtime>>::prefix_hash().to_vec(),
<pallet_staking::Ledger<Runtime>>::prefix_hash().to_vec(),
],
..Default::default()
}))
Expand Down
12 changes: 6 additions & 6 deletions substrate/frame/paged-list/src/paged_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub type ValueIndex = u32;
/// [`Page`]s.
///
/// Each [`Page`] holds at most `ValuesPerNewPage` values in its `values` vector. The last page is
/// the only one that could have less than `ValuesPerNewPage` values.
/// the only one that could have less than `ValuesPerNewPage` values.
/// **Iteration** happens by starting
/// at [`first_page`][StoragePagedListMeta::first_page]/
/// [`first_value_offset`][StoragePagedListMeta::first_value_offset] and incrementing these indices
Expand Down Expand Up @@ -373,11 +373,11 @@ where
/// that are completely useless for prefix calculation.
struct StoragePagedListPrefix<Prefix>(PhantomData<Prefix>);

impl<Prefix> frame_support::storage::StoragePrefixedContainer for StoragePagedListPrefix<Prefix>
impl<Prefix> StoragePrefixedContainer for StoragePagedListPrefix<Prefix>
where
Prefix: StorageInstance,
{
fn module_prefix() -> &'static [u8] {
fn pallet_prefix() -> &'static [u8] {
Prefix::pallet_prefix().as_bytes()
}

Expand All @@ -386,15 +386,15 @@ where
}
}

impl<Prefix, Value, ValuesPerNewPage> frame_support::storage::StoragePrefixedContainer
impl<Prefix, Value, ValuesPerNewPage> StoragePrefixedContainer
for StoragePagedList<Prefix, Value, ValuesPerNewPage>
where
Prefix: StorageInstance,
Value: FullCodec,
ValuesPerNewPage: Get<u32>,
{
fn module_prefix() -> &'static [u8] {
StoragePagedListPrefix::<Prefix>::module_prefix()
fn pallet_prefix() -> &'static [u8] {
StoragePagedListPrefix::<Prefix>::pallet_prefix()
}

fn storage_prefix() -> &'static [u8] {
Expand Down
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 @@ -246,6 +246,14 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
implemented by the runtime")
}

fn name_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
>::name_hash::<Self>()
.expect("Pallet is part of the runtime because pallet `Config` trait is \
implemented by the runtime")
}

fn module_name() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
Expand Down
42 changes: 41 additions & 1 deletion substrate/frame/support/procedural/src/pallet/expand/storage.rs
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;

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()
}
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
Loading

0 comments on commit aad80cc

Please sign in to comment.