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 all 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
43 changes: 39 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 @@ -236,13 +236,24 @@ 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 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
.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>),
}
})
.collect::<Vec<_>>();

quote!(
/// Provides an implementation of `PalletInfo` to provide information
Expand All @@ -264,13 +275,37 @@ 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 module_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::<#names>() {
return Some(#module_names)
}
)*

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
12 changes: 12 additions & 0 deletions frame/support/procedural/src/construct_runtime/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ pub struct PalletPath {
pub inner: Path,
}

impl PalletPath {
pub fn module_name(&self) -> String {
self.inner.segments.iter().fold(String::new(), |mut acc, segment| {
if !acc.is_empty() {
acc.push_str("::");
}
acc.push_str(&segment.ident.to_string());
acc
})
}
}

impl Parse for PalletPath {
fn parse(input: ParseStream) -> Result<Self> {
let mut lookahead = input.lookahead1();
Expand Down
54 changes: 54 additions & 0 deletions frame/support/procedural/src/crate_version.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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 crate versioning.

use super::get_cargo_env_var;
use frame_support_procedural_tools::generate_crate_access_2018;
use proc_macro2::{Span, TokenStream};
use syn::{Error, Result};

/// 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_cargo_env_var::<u16>("CARGO_PKG_VERSION_MAJOR")
.map_err(|_| create_error("Major version needs to fit into `u16`"))?;

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

let patch_version = get_cargo_env_var::<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,
}
})
}
20 changes: 19 additions & 1 deletion 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 All @@ -31,7 +32,7 @@ mod storage;
mod transactional;

use proc_macro::TokenStream;
use std::cell::RefCell;
use std::{cell::RefCell, str::FromStr};
pub(crate) use storage::INHERENT_INSTANCE_NAME;

thread_local! {
Expand All @@ -52,6 +53,16 @@ impl Counter {
}
}

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

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

/// Declares strongly-typed wrappers around codec-compatible types in storage.
///
/// ## Example
Expand Down Expand Up @@ -462,6 +473,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
12 changes: 12 additions & 0 deletions frame/support/procedural/src/pallet/expand/pallet_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ 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 module_name() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
>::module_name::<Self>()
.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
32 changes: 30 additions & 2 deletions frame/support/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2151,6 +2151,18 @@ macro_rules! decl_module {
.expect("Pallet is part of the runtime because pallet `Config` trait is \
implemented by the runtime")
}

fn module_name() -> &'static str {
<
<$trait_instance as $system::Config>::PalletInfo as $crate::traits::PalletInfo
>::module_name::<Self>()
.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 @@ -2529,8 +2541,8 @@ mod tests {
use crate::{
metadata::*,
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 @@ -2631,6 +2643,22 @@ mod tests {
return Some("Test")
}

None
}
fn module_name<P: 'static>() -> Option<&'static str> {
let type_id = sp_std::any::TypeId::of::<P>();
if type_id == sp_std::any::TypeId::of::<Test>() {
return Some("tests")
}

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
22 changes: 22 additions & 0 deletions frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,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 @@ -819,6 +834,7 @@ pub mod tests {
StorageHasher,
};
use codec::{Codec, EncodeLike};
use frame_support::traits::CrateVersion;
use sp_io::TestExternalities;
use sp_std::result;

Expand All @@ -832,6 +848,12 @@ pub mod tests {
fn name<P: 'static>() -> Option<&'static str> {
unimplemented!("PanicPalletInfo mustn't be triggered by tests");
}
fn module_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
43 changes: 40 additions & 3 deletions frame/support/src/traits/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use codec::{Decode, Encode};
use sp_runtime::RuntimeDebug;

/// Provides information about the pallet setup in the runtime.
/// Provides information about the pallet itself and its setup in the runtime.
///
/// An implementor should be able to provide information about each pallet that
/// is configured in `construct_runtime!`.
Expand All @@ -29,16 +29,25 @@ 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 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.
fn crate_version<P: 'static>() -> Option<CrateVersion>;
}

/// Provides information about the pallet setup in the runtime.
/// Provides information about the pallet itself and its setup in the runtime.
///
/// Access the information provided by [`PalletInfo`] for a specific pallet.
/// Declare some information and access the information provided by [`PalletInfo`] for a specific
/// pallet.
pub trait PalletInfoAccess {
/// Index of the pallet as configured in the runtime.
fn index() -> usize;
/// Name of the pallet as configured in the runtime.
fn name() -> &'static str;
/// Name of the Rust module containing the pallet.
fn module_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 +77,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
Loading