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 24 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.

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
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")
Copy link
Contributor

Choose a reason for hiding this comment

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

So, this might not be true under a misconfiguration, i.e. someone implements the pallet Config trait for a runtime, but forgets to include the actual pallet in construct_runtime.

Hopefully we do now have lints or warnings to catch this, but on the off-chance that we don't, I'd want to make sure that this expect doesn't trigger and cause a panic in runtime.

Copy link
Member

Choose a reason for hiding this comment

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

This assumption is already used there multiple times.

}

fn module_name() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
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
19 changes: 8 additions & 11 deletions substrate/frame/support/src/storage/generator/double_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use sp_std::prelude::*;
///
/// Thus value for (key1, key2) is stored at:
/// ```nocompile
/// Twox128(module_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2))
/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2))
/// ```
///
/// # Warning
Expand All @@ -53,18 +53,15 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
/// Hasher for the second key.
type Hasher2: StorageHasher;

/// Module prefix. Used for generating final key.
fn module_prefix() -> &'static [u8];
/// Pallet prefix. Used for generating final key.
fn pallet_prefix() -> &'static [u8];

/// Storage prefix. Used for generating final key.
fn storage_prefix() -> &'static [u8];

/// The full prefix; just the hash of `module_prefix` concatenated to the hash of
/// The full prefix; just the hash of `pallet_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()
}
fn prefix_hash() -> Vec<u8>;
yjhmelody marked this conversation as resolved.
Show resolved Hide resolved

/// Convert an optional value retrieved from storage to the type queried.
fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
Expand All @@ -77,7 +74,7 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
where
KArg1: EncodeLike<K1>,
{
let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix());
let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
let key_hashed = k1.using_encoded(Self::Hasher1::hash);

let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.as_ref().len());
Expand All @@ -94,7 +91,7 @@ pub trait StorageDoubleMap<K1: FullEncode, K2: FullEncode, V: FullCodec> {
KArg1: EncodeLike<K1>,
KArg2: EncodeLike<K2>,
{
let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix());
let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
let key1_hashed = k1.using_encoded(Self::Hasher1::hash);
let key2_hashed = k2.using_encoded(Self::Hasher2::hash);

Expand Down Expand Up @@ -334,7 +331,7 @@ where
key2: KeyArg2,
) -> Option<V> {
let old_key = {
let storage_prefix = storage_prefix(Self::module_prefix(), Self::storage_prefix());
let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());

let key1_hashed = key1.using_encoded(OldHasher1::hash);
let key2_hashed = key2.using_encoded(OldHasher2::hash);
Expand Down
Loading
Loading