Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Extend PalletInfoAccess with module_name and crate_version method #9690

Merged
merged 20 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from 10 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
28 changes: 24 additions & 4 deletions frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream

let outer_origin = expand::expand_outer_origin(&name, &pallets, pallets_token, &scrate)?;
let all_pallets = decl_all_pallets(&name, pallets.iter());
let pallet_to_index = decl_pallet_runtime_setup(&pallets, &scrate);
let pallet_to_index = decl_pallet_runtime_setup(&name, &pallets, &scrate);

let dispatch = expand::expand_outer_dispatch(&name, &pallets, &scrate);
let metadata = expand::expand_runtime_metadata(&name, &pallets, &scrate, &unchecked_extrinsic);
Expand Down Expand Up @@ -233,13 +233,20 @@ fn decl_all_pallets<'a>(
}

fn decl_pallet_runtime_setup(
runtime: &Ident,
pallet_declarations: &[Pallet],
scrate: &TokenStream2,
) -> TokenStream2 {
let names = pallet_declarations.iter().map(|d| &d.name);
let names2 = pallet_declarations.iter().map(|d| &d.name);
let names = pallet_declarations.iter().map(|d| &d.name).collect::<Vec<_>>();
let name_strings = pallet_declarations.iter().map(|d| d.name.to_string());
let indices = pallet_declarations.iter().map(|pallet| pallet.index as usize);
let pallet_structs = pallet_declarations.iter().map(|pallet| {
let path = &pallet.path;
match pallet.instance.as_ref() {
Some(inst) => quote!(#path::Pallet<#runtime, #path::#inst>),
None => quote!(#path::Pallet<#runtime>),
}
});

quote!(
/// Provides an implementation of `PalletInfo` to provide information
Expand All @@ -261,13 +268,26 @@ fn decl_pallet_runtime_setup(
fn name<P: 'static>() -> Option<&'static str> {
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
#(
if type_id == #scrate::sp_std::any::TypeId::of::<#names2>() {
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
return Some(#name_strings)
}
)*

None
}

fn crate_version<P: 'static>() -> Option<#scrate::traits::CrateVersion> {
let type_id = #scrate::sp_std::any::TypeId::of::<P>();
#(
if type_id == #scrate::sp_std::any::TypeId::of::<#names>() {
return Some(
<#pallet_structs as #scrate::traits::PalletInfoAccess>::crate_version()
)
}
)*

None
}
}
)
}
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
4 changes: 4 additions & 0 deletions frame/support/procedural/src/pallet/expand/pallet_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
.expect("Pallet is part of the runtime because pallet `Config` trait is \
implemented by the runtime")
}

fn crate_version() -> #frame_support::traits::CrateVersion {
#frame_support::crate_to_crate_version!()
}
}

#storage_info
Expand Down
16 changes: 14 additions & 2 deletions frame/support/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2140,6 +2140,10 @@ macro_rules! decl_module {
.expect("Pallet is part of the runtime because pallet `Config` trait is \
implemented by the runtime")
}

fn crate_version() -> $crate::traits::CrateVersion {
$crate::crate_to_crate_version!()
}
}

// Implement GetCallName for the Call.
Expand Down Expand Up @@ -2598,8 +2602,8 @@ mod tests {
use super::*;
use crate::{
traits::{
Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade,
PalletInfo,
CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize,
OnRuntimeUpgrade, PalletInfo,
},
weights::{DispatchClass, DispatchInfo, Pays, RuntimeDbWeight},
};
Expand Down Expand Up @@ -2761,6 +2765,14 @@ mod tests {
return Some("Test")
}

None
}
fn crate_version<P: 'static>() -> Option<CrateVersion> {
let type_id = sp_std::any::TypeId::of::<P>();
if type_id == sp_std::any::TypeId::of::<Test>() {
return Some(frame_support::crate_to_crate_version!())
}

None
}
}
Expand Down
19 changes: 19 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 Expand Up @@ -783,6 +798,7 @@ pub mod tests {
DecodeDifferent, DefaultByteGetter, StorageEntryMetadata, StorageEntryModifier,
StorageEntryType, StorageHasher, StorageMetadata,
};
use frame_support::traits::CrateVersion;
use sp_io::TestExternalities;
use sp_std::{marker::PhantomData, result};

Expand All @@ -796,6 +812,9 @@ pub mod tests {
fn name<P: 'static>() -> Option<&'static str> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn crate_version<P: 'static>() -> Option<CrateVersion> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
}

pub trait Config: 'static {
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, GetStorageVersion, PalletInfo,
PalletInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
};

mod hooks;
Expand Down
32 changes: 32 additions & 0 deletions frame/support/src/traits/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,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>;
/// Convert the given pallet `P` into its containing crate version.
fn crate_version<P: 'static>() -> Option<CrateVersion>;
}

/// Provides information about the pallet setup in the runtime.
Expand All @@ -39,6 +41,8 @@ pub trait PalletInfoAccess {
fn index() -> usize;
/// Name of the pallet as configured in the runtime.
fn name() -> &'static str;
/// Version of the crate containing the pallet.
fn crate_version() -> CrateVersion;
}

/// The function and pallet name of the Call.
Expand Down Expand Up @@ -68,6 +72,34 @@ 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)
}
}

/// The storage key postfix that is used to store the [`StorageVersion`] per pallet.
///
/// The full storage key is built by using:
Expand Down
3 changes: 3 additions & 0 deletions frame/support/test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ impl frame_support::traits::PalletInfo for PanicPalletInfo {
fn name<P: 'static>() -> Option<&'static str> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn crate_version<P: 'static>() -> Option<frame_support::traits::CrateVersion> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
}

/// Provides an implementation of [`frame_support::traits::Randomness`] that should only be used in
Expand Down
15 changes: 14 additions & 1 deletion 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 @@ -948,40 +948,53 @@ fn test_metadata() {
fn pallet_in_runtime_is_correct() {
assert_eq!(PalletInfo::index::<System>().unwrap(), 30);
assert_eq!(PalletInfo::name::<System>().unwrap(), "System");
assert_eq!(PalletInfo::crate_version::<System>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_1>().unwrap(), 31);
assert_eq!(PalletInfo::name::<Module1_1>().unwrap(), "Module1_1");
assert_eq!(PalletInfo::crate_version::<Module1_1>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module2>().unwrap(), 32);
assert_eq!(PalletInfo::name::<Module2>().unwrap(), "Module2");
assert_eq!(PalletInfo::crate_version::<Module2>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_2>().unwrap(), 33);
assert_eq!(PalletInfo::name::<Module1_2>().unwrap(), "Module1_2");
assert_eq!(PalletInfo::crate_version::<Module1_2>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<NestedModule3>().unwrap(), 34);
assert_eq!(PalletInfo::name::<NestedModule3>().unwrap(), "NestedModule3");
assert_eq!(PalletInfo::crate_version::<NestedModule3>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module3>().unwrap(), 35);
assert_eq!(PalletInfo::name::<Module3>().unwrap(), "Module3");
assert_eq!(PalletInfo::crate_version::<Module3>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_3>().unwrap(), 6);
assert_eq!(PalletInfo::name::<Module1_3>().unwrap(), "Module1_3");
assert_eq!(PalletInfo::crate_version::<Module1_3>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_4>().unwrap(), 3);
assert_eq!(PalletInfo::name::<Module1_4>().unwrap(), "Module1_4");
assert_eq!(PalletInfo::crate_version::<Module1_4>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_5>().unwrap(), 4);
assert_eq!(PalletInfo::name::<Module1_5>().unwrap(), "Module1_5");
assert_eq!(PalletInfo::crate_version::<Module1_5>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_6>().unwrap(), 1);
assert_eq!(PalletInfo::name::<Module1_6>().unwrap(), "Module1_6");
assert_eq!(PalletInfo::crate_version::<Module1_6>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_7>().unwrap(), 2);
assert_eq!(PalletInfo::name::<Module1_7>().unwrap(), "Module1_7");
assert_eq!(PalletInfo::crate_version::<Module1_7>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_8>().unwrap(), 12);
assert_eq!(PalletInfo::name::<Module1_8>().unwrap(), "Module1_8");
assert_eq!(PalletInfo::crate_version::<Module1_8>().unwrap(), CrateVersion::new(3, 0, 0));

assert_eq!(PalletInfo::index::<Module1_9>().unwrap(), 13);
assert_eq!(PalletInfo::name::<Module1_9>().unwrap(), "Module1_9");
assert_eq!(PalletInfo::crate_version::<Module1_9>().unwrap(), CrateVersion::new(3, 0, 0));
}
Loading