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

Allow pallet's info to be enumerated #10053

Merged
merged 18 commits into from
Oct 21, 2021
17 changes: 15 additions & 2 deletions frame/executive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ The default Substrate node template declares the [`Executive`](https://docs.rs/f
```rust
#
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, Context, Runtime, AllPallets>;
pub type Executive = executive::Executive<
Runtime,
Block,
Context,
Runtime,
AllPallets,
>;
```

### Custom `OnRuntimeUpgrade` logic
Expand All @@ -54,7 +60,14 @@ impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
}
}

pub type Executive = executive::Executive<Runtime, Block, Context, Runtime, AllPallets, CustomOnRuntimeUpgrade>;
pub type Executive = executive::Executive<
Runtime,
Block,
Context,
Runtime,
AllPallets,
CustomOnRuntimeUpgrade,
>;
```

License: Apache-2.0
1 change: 1 addition & 0 deletions frame/support/procedural/src/construct_runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ fn decl_all_pallets<'a>(

quote!(
#types

/// All pallets included in the runtime as a nested tuple of types.
/// Excludes the System pallet.
pub type AllPallets = ( #all_pallets );
Expand Down
19 changes: 19 additions & 0 deletions frame/support/procedural/src/pallet/expand/pallet_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,25 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
}
}

impl<#type_impl_gen> #frame_support::traits::PalletsInfoAccess
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn count() -> usize { 1 }
fn accumulate(
acc: &mut #frame_support::sp_std::vec::Vec<#frame_support::traits::PalletInfoData>
) {
use #frame_support::traits::PalletInfoAccess;
let item = #frame_support::traits::PalletInfoData {
index: Self::index(),
name: Self::name(),
module_name: Self::module_name(),
crate_version: Self::crate_version(),
};
acc.push(item);
}
}

#storage_info
)
}
16 changes: 16 additions & 0 deletions frame/support/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,6 +2165,22 @@ macro_rules! decl_module {
}
}

impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::traits::PalletsInfoAccess
for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
{
fn count() -> usize { 1 }
fn accumulate(acc: &mut $crate::sp_std::vec::Vec<$crate::traits::PalletInfoData>) {
use $crate::traits::PalletInfoAccess;
let item = $crate::traits::PalletInfoData {
index: Self::index(),
name: Self::name(),
module_name: Self::module_name(),
crate_version: Self::crate_version(),
};
acc.push(item);
}
}

// Implement GetCallName for the Call.
impl<$trait_instance: $trait_name $(<I>, $instance: $instantiable)?> $crate::dispatch::GetCallName
for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )*
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1476,11 +1476,11 @@ pub mod pallet_prelude {
/// * [`traits::OnGenesis`]: contains some logic to write pallet version into storage.
/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined.
///
/// It declare `type Module` type alias for `Pallet`, used by [`construct_runtime`].
/// It declares `type Module` type alias for `Pallet`, used by [`construct_runtime`].
///
/// It implements [`traits::PalletInfoAccess`] on `Pallet` to ease access to pallet
/// informations given by [`frame_support::traits::PalletInfo`].
/// (The implementation use the associated type `frame_system::Config::PalletInfo`).
/// (The implementation uses the associated type `frame_system::Config::PalletInfo`).
///
/// It implements [`traits::StorageInfoTrait`] on `Pallet` which give information about all
/// storages.
Expand Down
4 changes: 2 additions & 2 deletions frame/support/src/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ impl PalletVersionToStorageVersionHelper for T {
///
/// This will remove all `PalletVersion's` from the state and insert the current storage version.
pub fn migrate_from_pallet_version_to_storage_version<
AllPallets: PalletVersionToStorageVersionHelper,
Pallets: PalletVersionToStorageVersionHelper,
>(
db_weight: &RuntimeDbWeight,
) -> Weight {
AllPallets::migrate(db_weight)
Pallets::migrate(db_weight)
}
3 changes: 2 additions & 1 deletion frame/support/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ pub use randomness::Randomness;
mod metadata;
pub use metadata::{
CallMetadata, CrateVersion, GetCallMetadata, GetCallName, GetStorageVersion, PalletInfo,
PalletInfoAccess, StorageVersion, STORAGE_VERSION_STORAGE_KEY_POSTFIX,
PalletInfoAccess, PalletInfoData, PalletsInfoAccess, StorageVersion,
STORAGE_VERSION_STORAGE_KEY_POSTFIX,
};

mod hooks;
Expand Down
88 changes: 88 additions & 0 deletions frame/support/src/traits/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use codec::{Decode, Encode};
use sp_runtime::RuntimeDebug;
use sp_std::prelude::*;

/// Provides information about the pallet itself and its setup in the runtime.
///
Expand All @@ -35,6 +36,19 @@ pub trait PalletInfo {
fn crate_version<P: 'static>() -> Option<CrateVersion>;
}

/// Information regarding an instance of a pallet.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RuntimeDebug)]
pub struct PalletInfoData {
/// Index of the pallet as configured in the runtime.
pub index: usize,
/// Name of the pallet as configured in the runtime.
pub name: &'static str,
/// Name of the Rust module containing the pallet.
pub module_name: &'static str,
/// Version of the crate containing the pallet.
pub crate_version: CrateVersion,
}

/// Provides information about the pallet itself and its setup in the runtime.
///
/// Declare some information and access the information provided by [`PalletInfo`] for a specific
Expand All @@ -50,6 +64,49 @@ pub trait PalletInfoAccess {
fn crate_version() -> CrateVersion;
}

/// Provide information about a bunch of pallets.
pub trait PalletsInfoAccess {
/// The number of pallets' information that this type represents.
///
/// You probably don't want this function but `infos()` instead.
fn count() -> usize {
0
}

/// Extend the given vector by all of the pallets' information that this type represents.
///
/// You probably don't want this function but `infos()` instead.
fn accumulate(_accumulator: &mut Vec<PalletInfoData>) {}
Copy link
Contributor

@gui1117 gui1117 Oct 21, 2021

Choose a reason for hiding this comment

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

I usually prefer not to have default implementation when it needs to be overriden in most implementation, this can be error prone, someone can miss to override one implementation.


/// All of the pallets' information that this type represents.
fn infos() -> Vec<PalletInfoData> {
let mut result = Vec::with_capacity(Self::count());
Self::accumulate(&mut result);
result
}
}

impl PalletsInfoAccess for () {}
impl<T: PalletsInfoAccess> PalletsInfoAccess for (T,) {
fn count() -> usize {
T::count()
}
fn accumulate(acc: &mut Vec<PalletInfoData>) {
T::accumulate(acc)
}
}

impl<T1: PalletsInfoAccess, T2: PalletsInfoAccess> PalletsInfoAccess for (T1, T2) {
fn count() -> usize {
T1::count() + T2::count()
}
fn accumulate(acc: &mut Vec<PalletInfoData>) {
// The AllPallets type tuplises the pallets in reverse order, so we unreverse them here.
T2::accumulate(acc);
T1::accumulate(acc);
Comment on lines +105 to +106
Copy link
Contributor

Choose a reason for hiding this comment

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

This ordering will produce vec![T2, T1], is that what we need to re-reverse the order of the pallets?

Copy link
Member Author

Choose a reason for hiding this comment

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

indeed. i'll put a comment in.

}
}

/// The function and pallet name of the Call.
#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug)]
pub struct CallMetadata {
Expand Down Expand Up @@ -206,6 +263,37 @@ pub trait GetStorageVersion {
mod tests {
use super::*;

struct Pallet1;
impl PalletInfoAccess for Pallet1 {
fn index() -> usize {
1
}
fn name() -> &'static str {
"Pallet1"
}
fn module_name() -> &'static str {
"pallet1"
}
fn crate_version() -> CrateVersion {
CrateVersion::new(1, 0, 0)
}
}
struct Pallet2;
impl PalletInfoAccess for Pallet2 {
fn index() -> usize {
2
}
fn name() -> &'static str {
"Pallet2"
}
fn module_name() -> &'static str {
"pallet2"
}
fn crate_version() -> CrateVersion {
CrateVersion::new(1, 0, 0)
}
}

#[test]
fn check_storage_version_ordering() {
let version = StorageVersion::new(1);
Expand Down
42 changes: 42 additions & 0 deletions frame/support/test/tests/pallet_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,48 @@ fn storage_expand() {
});
}

#[test]
fn pallet_metadata_expands() {
use frame_support::traits::{CrateVersion, PalletInfoData, PalletsInfoAccess};
let mut infos = AllPalletsWithSystem::infos();
infos.sort_by_key(|x| x.index);
assert_eq!(
infos,
vec![
PalletInfoData {
index: 0,
name: "System",
module_name: "frame_system",
crate_version: CrateVersion { major: 4, minor: 0, patch: 0 },
},
PalletInfoData {
index: 1,
name: "Example",
module_name: "pallet",
crate_version: CrateVersion { major: 3, minor: 0, patch: 0 },
},
PalletInfoData {
index: 2,
name: "Instance1Example",
module_name: "pallet",
crate_version: CrateVersion { major: 3, minor: 0, patch: 0 },
},
PalletInfoData {
index: 3,
name: "Example2",
module_name: "pallet2",
crate_version: CrateVersion { major: 3, minor: 0, patch: 0 },
},
PalletInfoData {
index: 4,
name: "Instance1Example2",
module_name: "pallet2",
crate_version: CrateVersion { major: 3, minor: 0, patch: 0 },
},
]
);
}

#[test]
fn pallet_hooks_expand() {
TestExternalities::default().execute_with(|| {
Expand Down