Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
19 changes: 18 additions & 1 deletion frame/support/procedural/src/construct_runtime/expand/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,27 @@ pub fn expand_outer_dispatch(
let mut variant_patterns = Vec::new();
let mut query_call_part_macros = Vec::new();
let mut pallet_names = Vec::new();
let mut pallet_indices = Vec::new();
let mut pallet_structs = Vec::new();

let pallets_with_call = pallet_decls.iter().filter(|decl| decl.exists_part("Call"));

for pallet_declaration in pallets_with_call {
let name = &pallet_declaration.name;
let path = &pallet_declaration.path;
let index = pallet_declaration.index;
let pallet_struct = match pallet_declaration.instance.as_ref() {
Some(inst) => quote!(#path::Pallet::<#runtime, #path::#inst>),
None => quote!(#path::Pallet<#runtime>),
};

variant_defs.extend(
quote!(#[codec(index = #index)] #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ),),
);
variant_patterns.push(quote!(Call::#name(call)));
pallet_names.push(name);
pallet_indices.push(index);
pallet_structs.push(pallet_struct);
query_call_part_macros.push(quote! {
#path::__substrate_call_check::is_call_part_defined!(#name);
});
Expand Down Expand Up @@ -74,7 +82,16 @@ pub fn expand_outer_dispatch(
#variant_patterns => {
let function_name = call.get_call_name();
let pallet_name = stringify!(#pallet_names);
#scrate::dispatch::CallMetadata { function_name, pallet_name }
let index = #pallet_indices;
let crate_version = <
#pallet_structs as #scrate::traits::GetCrateVersion
>::crate_version();
#scrate::dispatch::CallMetadata {
function_name,
pallet_name,
index,
crate_version,
}
}
)*
}
Expand Down
64 changes: 64 additions & 0 deletions frame/support/procedural/src/crate_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// This file is part of Substrate.

// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Implementation of macros related to pallet versioning.

use frame_support_procedural_tools::generate_crate_access_2018;
use proc_macro2::{Span, TokenStream};
use std::{env, str::FromStr};
use syn::{Error, Result};

/// Get the version from the given version environment variable.
///
/// The version is parsed into the requested destination type.
fn get_version<T: FromStr>(version_env: &str) -> std::result::Result<T, ()> {
let version = env::var(version_env)
.unwrap_or_else(|_| panic!("`{}` is always set by cargo; qed", version_env));

T::from_str(&version).map_err(drop)
}

/// Create an error that will be shown by rustc at the call site of the macro.
fn create_error(message: &str) -> Error {
Error::new(Span::call_site(), message)
}

/// Implementation of the `crate_to_crate_version!` macro.
pub fn crate_to_crate_version(input: proc_macro::TokenStream) -> Result<TokenStream> {
if !input.is_empty() {
return Err(create_error("No arguments expected!"))
}

let major_version = get_version::<u16>("CARGO_PKG_VERSION_MAJOR")
.map_err(|_| create_error("Major version needs to fit into `u16`"))?;

let minor_version = get_version::<u8>("CARGO_PKG_VERSION_MINOR")
.map_err(|_| create_error("Minor version needs to fit into `u8`"))?;

let patch_version = get_version::<u8>("CARGO_PKG_VERSION_PATCH")
.map_err(|_| create_error("Patch version needs to fit into `u8`"))?;

let crate_ = generate_crate_access_2018("frame-support")?;

Ok(quote::quote! {
#crate_::traits::CrateVersion {
major: #major_version,
minor: #minor_version,
patch: #patch_version,
}
})
}
8 changes: 8 additions & 0 deletions frame/support/procedural/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

mod clone_no_bound;
mod construct_runtime;
mod crate_version;
mod debug_no_bound;
mod default_no_bound;
mod dummy_part_checker;
Expand Down Expand Up @@ -462,6 +463,13 @@ pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStre
.unwrap_or_else(|e| e.to_compile_error().into())
}

#[proc_macro]
pub fn crate_to_crate_version(input: TokenStream) -> TokenStream {
crate_version::crate_to_crate_version(input)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}

/// The number of module instances supported by the runtime, starting at index 1,
/// and up to `NUMBER_OF_INSTANCE`.
pub(crate) const NUMBER_OF_INSTANCE: u8 = 16;
Expand Down
11 changes: 11 additions & 0 deletions frame/support/procedural/src/pallet/expand/pallet_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::pallet::{expand::merge_where_clauses, parse::helper::get_doc_literals

///
/// * Add derive trait on Pallet
/// * Implement GetCrateVersion on Pallet
/// * Implement GetStorageVersion on Pallet
/// * Implement OnGenesis on Pallet
/// * Implement ModuleErrorMetadata on Pallet
Expand Down Expand Up @@ -168,6 +169,16 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
#[allow(dead_code)]
pub type Module<#type_decl_gen> = #pallet_ident<#type_use_gen>;

// Implement `GetCrateVersion` for `Pallet`
impl<#type_impl_gen> #frame_support::traits::GetCrateVersion
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn crate_version() -> #frame_support::traits::CrateVersion {
#frame_support::crate_to_crate_version!()
}
}

// Implement `GetStorageVersion` for `Pallet`
impl<#type_impl_gen> #frame_support::traits::GetStorageVersion
for #pallet_ident<#type_use_gen>
Expand Down
9 changes: 9 additions & 0 deletions frame/support/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,15 @@ macro_rules! decl_module {
}
}

// Implement `GetCrateVersion` for `Module`
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::GetCrateVersion
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
{
fn crate_version() -> $crate::traits::CrateVersion {
$crate::crate_to_crate_version!()
}
}

// Implement `OnGenesis` for `Module`
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::OnGenesis
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
Expand Down
15 changes: 15 additions & 0 deletions frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,21 @@ pub use frame_support_procedural::DefaultNoBound;
/// ```
pub use frame_support_procedural::require_transactional;

/// Convert the current crate version into a [`CrateVersion`](crate::traits::CrateVersion).
///
/// It uses the `CARGO_PKG_VERSION_MAJOR`, `CARGO_PKG_VERSION_MINOR` and
/// `CARGO_PKG_VERSION_PATCH` environment variables to fetch the crate version.
/// This means that the [`CrateVersion`](crate::traits::CrateVersion)
/// object will correspond to the version of the crate the macro is called in!
///
/// # Example
///
/// ```
/// # use frame_support::{traits::CrateVersion, crate_to_crate_version};
/// const Version: CrateVersion = crate_to_crate_version!();
/// ```
pub use frame_support_procedural::crate_to_crate_version;

/// Return Err of the expression: `return Err($expression);`.
///
/// Used as `fail!(expression)`.
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ pub use randomness::Randomness;

mod metadata;
pub use metadata::{
CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo, PalletInfoAccess,
StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
CallMetadata, CrateVersion, GetCallMetadata, GetCallName, GetCrateVersion, GetStorageVersion,
PalletInfo, PalletInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
};

mod hooks;
Expand Down
38 changes: 38 additions & 0 deletions frame/support/src/traits/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ pub struct CallMetadata {
pub function_name: &'static str,
/// Name of the pallet to which the function belongs.
pub pallet_name: &'static str,
/// Index of the containing pallet specified in `construct_runtime`.
pub index: u8,
/// Version of the crate containing the pallet to which the function belongs.
pub crate_version: CrateVersion,
}

/// Gets the function name of the Call.
Expand All @@ -68,6 +72,40 @@ pub trait GetCallMetadata {
fn get_call_metadata(&self) -> CallMetadata;
}

/// The version of a crate.
#[derive(RuntimeDebug, Eq, PartialEq, Encode, Decode, Ord, Clone, Copy, Default)]
pub struct CrateVersion {
/// The major version of the crate.
pub major: u16,
/// The minor version of the crate.
pub minor: u8,
/// The patch version of the crate.
pub patch: u8,
}

impl CrateVersion {
pub const fn new(major: u16, minor: u8, patch: u8) -> Self {
Self { major, minor, patch }
}
}

impl sp_std::cmp::PartialOrd for CrateVersion {
fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> {
let res = self
.major
.cmp(&other.major)
.then_with(|| self.minor.cmp(&other.minor).then_with(|| self.patch.cmp(&other.patch)));

Some(res)
}
}

/// Provides information about the version of a crate.
pub trait GetCrateVersion {
/// Returns the current version of the crate.
fn crate_version() -> CrateVersion;
}

/// The storage key postfix that is used to store the [`StorageVersion`] per pallet.
///
/// The full storage key is built by using:
Expand Down
9 changes: 7 additions & 2 deletions frame/support/test/tests/construct_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#![recursion_limit = "128"]

use frame_support::traits::PalletInfo as _;
use frame_support::traits::{CrateVersion, PalletInfo as _};
use sp_core::{sr25519, H256};
use sp_runtime::{
generic,
Expand Down Expand Up @@ -545,7 +545,12 @@ fn call_metadata() {
use frame_support::dispatch::{CallMetadata, GetCallMetadata};
let call = Call::Module3(module3::Call::<Runtime>::aux_4());
let metadata = call.get_call_metadata();
let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() };
let expected = CallMetadata {
function_name: "aux_4".into(),
pallet_name: "Module3".into(),
index: 35,
crate_version: CrateVersion { major: 3, minor: 0, patch: 0 },
};
assert_eq!(metadata, expected);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied
10 | #[pallet::generate_storage_info]
| ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar`
|
= note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key<frame_support::Twox64Concat, Bar>`
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, Key<frame_support::Twox64Concat, Bar>, u32>`
= note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey<frame_support::Twox64Concat, Bar>`
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, NMapKey<frame_support::Twox64Concat, Bar>, u32>`
= note: required by `storage_info`