mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 10:31:04 +00:00
[FRAME Core] Adds ability to split a pallet across multiple files (#13950)
* Initial setup * Updates macro_magic version and refactors accordingly * Removes unwrap from macro * Splits into multiple sections * Uses call_site to fix macro hygiene issue * Initial setup * Removes unnecessary changes * Moves template palet back * Updates cargo.lock * Moves BagsList inside mod * Comments access to internal functions for now * Updates tests * Uncomments code * Fixes test * Moves bags-list to separate crate * Initial setup * Removes bags-list changes * Fix structure * Minor update * Addresses review comment * Adds a couple of UI tests. More to be added * Adds err files * Adds test for no pallet * Adds doc * Updates versions * Adds benchmarking * Updates doc link * ".git/.scripts/commands/fmt/fmt.sh" * Minor update * Adds missing changes * ".git/.scripts/commands/fmt/fmt.sh" * Update frame/support/procedural/src/lib.rs Co-authored-by: Sam Johnson <sam@durosoft.com> * Addresses review comments * Addresses review comments * ".git/.scripts/commands/fmt/fmt.sh" * Update frame/support/procedural/src/lib.rs Co-authored-by: Sam Johnson <sam@durosoft.com> * Update frame/support/procedural/src/lib.rs Co-authored-by: Sam Johnson <sam@durosoft.com> * Update frame/support/procedural/src/lib.rs Co-authored-by: Sam Johnson <sam@durosoft.com> * Adds UI test for disambiguation * ".git/.scripts/commands/fmt/fmt.sh" * Makes clippy happy * ".git/.scripts/commands/fmt/fmt.sh" * Fixes frame support test * Fixes frame support test * Split items other than storage * Updates versions * Fixes some review comments * Addresses review comments * ".git/.scripts/commands/fmt/fmt.sh" * Updates docs * Adds experimental disclaimer * ".git/.scripts/commands/fmt/fmt.sh" * Update frame/support/test/tests/split_ui/no_section_found.rs Co-authored-by: Sam Johnson <sam@durosoft.com> * Addresses review comments * Fixes test --------- Co-authored-by: command-bot <> Co-authored-by: command-bot <ci@gitlab.parity.io> Co-authored-by: Sam Johnson <sam@durosoft.com>
This commit is contained in:
Generated
+16
@@ -6512,6 +6512,21 @@ dependencies = [
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-example-split"
|
||||
version = "4.0.0-dev"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-examples"
|
||||
version = "4.0.0-dev"
|
||||
@@ -6521,6 +6536,7 @@ dependencies = [
|
||||
"pallet-example-basic",
|
||||
"pallet-example-kitchensink",
|
||||
"pallet-example-offchain-worker",
|
||||
"pallet-example-split",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -111,6 +111,7 @@ members = [
|
||||
"frame/examples/offchain-worker",
|
||||
"frame/examples/kitchensink",
|
||||
"frame/examples/dev-mode",
|
||||
"frame/examples/split",
|
||||
"frame/examples/default-config",
|
||||
"frame/executive",
|
||||
"frame/nis",
|
||||
|
||||
@@ -17,6 +17,7 @@ pallet-default-config-example = { default-features = false, path = "./default-co
|
||||
pallet-example-offchain-worker = { default-features = false, path = "./offchain-worker" }
|
||||
pallet-example-kitchensink = { default-features = false, path = "./kitchensink" }
|
||||
pallet-dev-mode = { default-features = false, path = "./dev-mode" }
|
||||
pallet-example-split = { default-features = false, path = "./split" }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
@@ -26,6 +27,7 @@ std = [
|
||||
"pallet-example-offchain-worker/std",
|
||||
"pallet-example-kitchensink/std",
|
||||
"pallet-dev-mode/std",
|
||||
"pallet-example-split/std",
|
||||
]
|
||||
try-runtime = [
|
||||
"pallet-example-basic/try-runtime",
|
||||
@@ -33,4 +35,5 @@ try-runtime = [
|
||||
"pallet-example-offchain-worker/try-runtime",
|
||||
"pallet-example-kitchensink/try-runtime",
|
||||
"pallet-dev-mode/try-runtime",
|
||||
]
|
||||
"pallet-example-split/try-runtime",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
[package]
|
||||
name = "pallet-example-split"
|
||||
version = "4.0.0-dev"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
edition = "2021"
|
||||
license = "MIT-0"
|
||||
homepage = "https://substrate.io"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "FRAME example splitted pallet"
|
||||
readme = "README.md"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false }
|
||||
log = { version = "0.4.17", default-features = false }
|
||||
scale-info = { version = "2.5.0", default-features = false, features = ["derive"] }
|
||||
|
||||
frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" }
|
||||
frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" }
|
||||
|
||||
sp-io = { version = "23.0.0", default-features = false, path = "../../../primitives/io" }
|
||||
sp-std = { version = "8.0.0", default-features = false, path = "../../../primitives/std" }
|
||||
|
||||
frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../../benchmarking" }
|
||||
|
||||
[dev-dependencies]
|
||||
sp-core = { version = "21.0.0", default-features = false, path = "../../../primitives/core" }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"codec/std",
|
||||
"log/std",
|
||||
"scale-info/std",
|
||||
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
|
||||
"sp-io/std",
|
||||
"sp-std/std",
|
||||
|
||||
"frame-benchmarking?/std",
|
||||
]
|
||||
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
|
||||
try-runtime = ["frame-support/try-runtime"]
|
||||
@@ -0,0 +1,10 @@
|
||||
<!-- markdown-link-check-disable -->
|
||||
# Basic Example For Splitting A Pallet
|
||||
A simple example of a FRAME pallet demonstrating the ability to split sections across multiple
|
||||
files.
|
||||
|
||||
Note that this is purely experimental at this point.
|
||||
|
||||
Run `cargo doc --package pallet-example-split --open` to view this pallet's documentation.
|
||||
|
||||
License: MIT-0
|
||||
@@ -0,0 +1,54 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
//! Benchmarking setup for pallet-example-split
|
||||
|
||||
// Only enable this module for benchmarking.
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
use super::*;
|
||||
|
||||
#[allow(unused)]
|
||||
use crate::Pallet as Template;
|
||||
use frame_benchmarking::v2::*;
|
||||
use frame_system::RawOrigin;
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
#[benchmark]
|
||||
fn do_something() {
|
||||
let value = 100u32.into();
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
#[extrinsic_call]
|
||||
do_something(RawOrigin::Signed(caller), value);
|
||||
|
||||
assert_eq!(Something::<T>::get(), Some(value));
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn cause_error() {
|
||||
Something::<T>::put(100u32);
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
#[extrinsic_call]
|
||||
cause_error(RawOrigin::Signed(caller));
|
||||
|
||||
assert_eq!(Something::<T>::get(), Some(101u32));
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
/// A [`pallet_section`] that defines the events for a pallet.
|
||||
/// This can later be imported into the pallet using [`import_section`].
|
||||
#[pallet_section]
|
||||
mod events {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// Event documentation should end with an array that provides descriptive names for event
|
||||
/// parameters. [something, who]
|
||||
SomethingStored { something: u32, who: T::AccountId },
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
//! # Split Example Pallet
|
||||
//!
|
||||
//! **This pallet serves as an example and is not meant to be used in production.**
|
||||
//!
|
||||
//! A FRAME pallet demonstrating the ability to split sections across multiple files.
|
||||
//!
|
||||
//! Note that this is purely experimental at this point.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
// Re-export pallet items so that they can be accessed from the crate namespace.
|
||||
pub use pallet::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
mod events;
|
||||
|
||||
pub mod weights;
|
||||
pub use weights::*;
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
/// Imports a [`pallet_section`] defined at [`events::events`].
|
||||
/// This brings the events defined in that section into the pallet's namespace.
|
||||
#[import_section(events::events)]
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
use super::*;
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
/// Configure the pallet by specifying the parameters and types on which it depends.
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// Because this pallet emits events, it depends on the runtime's definition of an event.
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
/// Type representing the weight of this pallet
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
// The pallet's runtime storage items.
|
||||
#[pallet::storage]
|
||||
pub type Something<T> = StorageValue<_, u32>;
|
||||
|
||||
// Errors inform users that something went wrong.
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
/// Error names should be descriptive.
|
||||
NoneValue,
|
||||
/// Errors should have helpful documentation associated with them.
|
||||
StorageOverflow,
|
||||
}
|
||||
|
||||
// Dispatchable functions allows users to interact with the pallet and invoke state changes.
|
||||
// These functions materialize as "extrinsics", which are often compared to transactions.
|
||||
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// An example dispatchable that takes a singles value as a parameter, writes the value to
|
||||
/// storage and emits an event. This function must be dispatched by a signed extrinsic.
|
||||
#[pallet::call_index(0)]
|
||||
#[pallet::weight(T::WeightInfo::do_something())]
|
||||
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
|
||||
// Check that the extrinsic was signed and get the signer.
|
||||
// This function will return an error if the extrinsic is not signed.
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
// Update storage.
|
||||
<Something<T>>::put(something);
|
||||
|
||||
// Emit an event.
|
||||
Self::deposit_event(Event::SomethingStored { something, who });
|
||||
// Return a successful DispatchResultWithPostInfo
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// An example dispatchable that may throw a custom error.
|
||||
#[pallet::call_index(1)]
|
||||
#[pallet::weight(T::WeightInfo::cause_error())]
|
||||
pub fn cause_error(origin: OriginFor<T>) -> DispatchResult {
|
||||
let _who = ensure_signed(origin)?;
|
||||
|
||||
// Read a value from storage.
|
||||
match <Something<T>>::get() {
|
||||
// Return an error if the value has not been set.
|
||||
None => return Err(Error::<T>::NoneValue.into()),
|
||||
Some(old) => {
|
||||
// Increment the value read from storage; will error in the event of overflow.
|
||||
let new = old.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
|
||||
// Update the value in storage with the incremented result.
|
||||
<Something<T>>::put(new);
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
use crate as pallet_template;
|
||||
use frame_support::derive_impl;
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
type Block = frame_system::mocking::MockBlock<Test>;
|
||||
|
||||
// Configure a mock runtime to test the pallet.
|
||||
frame_support::construct_runtime!(
|
||||
pub enum Test where
|
||||
Block = Block,
|
||||
NodeBlock = Block,
|
||||
UncheckedExtrinsic = UncheckedExtrinsic,
|
||||
{
|
||||
System: frame_system,
|
||||
TemplatePallet: pallet_template,
|
||||
}
|
||||
);
|
||||
|
||||
/// Using a default config for [`frame_system`] in tests. See `default-config` example for more
|
||||
/// details.
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)]
|
||||
impl frame_system::Config for Test {
|
||||
type BaseCallFilter = frame_support::traits::Everything;
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
type RuntimeCall = RuntimeCall;
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type PalletInfo = PalletInfo;
|
||||
type OnSetCode = ();
|
||||
}
|
||||
|
||||
impl pallet_template::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
// Build genesis storage according to the mock runtime.
|
||||
pub fn new_test_ext() -> sp_io::TestExternalities {
|
||||
frame_system::GenesisConfig::default().build_storage::<Test>().unwrap().into()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
use crate::{mock::*, Error, Event, Something};
|
||||
use frame_support::{assert_noop, assert_ok};
|
||||
|
||||
#[test]
|
||||
fn it_works_for_default_value() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Go past genesis block so events get deposited
|
||||
System::set_block_number(1);
|
||||
// Dispatch a signed extrinsic.
|
||||
assert_ok!(TemplatePallet::do_something(RuntimeOrigin::signed(1), 42));
|
||||
// Read pallet storage and assert an expected result.
|
||||
assert_eq!(Something::<Test>::get(), Some(42));
|
||||
// Assert that the correct event was deposited
|
||||
System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correct_error_for_none_value() {
|
||||
new_test_ext().execute_with(|| {
|
||||
// Ensure the expected error is thrown when no value is present.
|
||||
assert_noop!(
|
||||
TemplatePallet::cause_error(RuntimeOrigin::signed(1)),
|
||||
Error::<Test>::NoneValue
|
||||
);
|
||||
});
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
|
||||
//! Autogenerated weights for pallet_template
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `<UNKNOWN>`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ../../target/release/node-template
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain
|
||||
// dev
|
||||
// --pallet
|
||||
// pallet_template
|
||||
// --extrinsic
|
||||
// *
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --output
|
||||
// pallets/template/src/weights.rs
|
||||
// --template
|
||||
// ../../.maintain/frame-weight-template.hbs
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for pallet_template.
|
||||
pub trait WeightInfo {
|
||||
fn do_something() -> Weight;
|
||||
fn cause_error() -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for pallet_template using the Substrate node and recommended hardware.
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
/// Storage: TemplatePallet Something (r:0 w:1)
|
||||
/// Proof: TemplatePallet Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
fn do_something() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 8_000_000 picoseconds.
|
||||
Weight::from_parts(9_000_000, 0)
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: TemplatePallet Something (r:1 w:1)
|
||||
/// Proof: TemplatePallet Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
fn cause_error() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `32`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 6_000_000 picoseconds.
|
||||
Weight::from_parts(6_000_000, 1489)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
/// Storage: TemplatePallet Something (r:0 w:1)
|
||||
/// Proof: TemplatePallet Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
fn do_something() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 8_000_000 picoseconds.
|
||||
Weight::from_parts(9_000_000, 0)
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
/// Storage: TemplatePallet Something (r:1 w:1)
|
||||
/// Proof: TemplatePallet Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
|
||||
fn cause_error() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `32`
|
||||
// Estimated: `1489`
|
||||
// Minimum execution time: 6_000_000 picoseconds.
|
||||
Weight::from_parts(6_000_000, 1489)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1_u64))
|
||||
}
|
||||
}
|
||||
@@ -35,3 +35,6 @@
|
||||
//!
|
||||
//! - [**`pallet-example-kitchensink`**](./kitchensink): A simple example of a FRAME pallet
|
||||
//! demonstrating a catalog of the the FRAME macros and their various syntax options.
|
||||
//!
|
||||
//! - [**`pallet-example-split`**](./split): A simple example of a FRAME pallet demonstrating the
|
||||
//! ability to split sections across multiple files.
|
||||
|
||||
@@ -43,7 +43,7 @@ use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use std::{cell::RefCell, str::FromStr};
|
||||
pub(crate) use storage::INHERENT_INSTANCE_NAME;
|
||||
use syn::{parse_macro_input, ItemImpl};
|
||||
use syn::{parse_macro_input, Error, ItemImpl, ItemMod};
|
||||
|
||||
thread_local! {
|
||||
/// A global counter, can be used to generate a relatively unique identifier.
|
||||
@@ -1761,3 +1761,113 @@ pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
pub fn composite_enum(_: TokenStream, _: TokenStream) -> TokenStream {
|
||||
pallet_macro_stub()
|
||||
}
|
||||
|
||||
/// Can be attached to a module. Doing so will declare that module as importable into a pallet
|
||||
/// via [`#[import_section]`](`macro@import_section`).
|
||||
///
|
||||
/// Note that sections are imported by their module name/ident, and should be referred to by
|
||||
/// their _full path_ from the perspective of the target pallet. Do not attempt to make use
|
||||
/// of `use` statements to bring pallet sections into scope, as this will not work (unless
|
||||
/// you do so as part of a wildcard import, in which case it will work).
|
||||
///
|
||||
/// ## Naming Logistics
|
||||
///
|
||||
/// Also note that because of how `#[pallet_section]` works, pallet section names must be
|
||||
/// globally unique _within the crate in which they are defined_. For more information on
|
||||
/// why this must be the case, see macro_magic's
|
||||
/// [`#[export_tokens]`](https://docs.rs/macro_magic/latest/macro_magic/attr.export_tokens.html) macro.
|
||||
///
|
||||
/// Optionally, you may provide an argument to `#[pallet_section]` such as
|
||||
/// `#[pallet_section(some_ident)]`, in the event that there is another pallet section in
|
||||
/// same crate with the same ident/name. The ident you specify can then be used instead of
|
||||
/// the module's ident name when you go to import it via `#[import_section]`.
|
||||
#[proc_macro_attribute]
|
||||
pub fn pallet_section(attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let tokens_clone = tokens.clone();
|
||||
// ensure this can only be attached to a module
|
||||
let _mod = parse_macro_input!(tokens_clone as ItemMod);
|
||||
|
||||
// use macro_magic's export_tokens as the internal implementation otherwise
|
||||
match macro_magic::mm_core::export_tokens_internal(attr, tokens, false) {
|
||||
Ok(tokens) => tokens.into(),
|
||||
Err(err) => err.to_compile_error().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// An attribute macro that can be attached to a module declaration. Doing so will
|
||||
/// Imports the contents of the specified external pallet section that was defined
|
||||
/// previously using [`#[pallet_section]`](`macro@pallet_section`).
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ignore
|
||||
/// #[import_section(some_section)]
|
||||
/// #[pallet]
|
||||
/// pub mod pallet {
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
/// where `some_section` was defined elsewhere via:
|
||||
/// ```ignore
|
||||
/// #[pallet_section]
|
||||
/// pub mod some_section {
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This will result in the contents of `some_section` being _verbatim_ imported into
|
||||
/// the pallet above. Note that since the tokens for `some_section` are essentially
|
||||
/// copy-pasted into the target pallet, you cannot refer to imports that don't also
|
||||
/// exist in the target pallet, but this is easily resolved by including all relevant
|
||||
/// `use` statements within your pallet section, so they are imported as well, or by
|
||||
/// otherwise ensuring that you have the same imports on the target pallet.
|
||||
///
|
||||
/// It is perfectly permissible to import multiple pallet sections into the same pallet,
|
||||
/// which can be done by having multiple `#[import_section(something)]` attributes
|
||||
/// attached to the pallet.
|
||||
///
|
||||
/// Note that sections are imported by their module name/ident, and should be referred to by
|
||||
/// their _full path_ from the perspective of the target pallet.
|
||||
#[import_tokens_attr {
|
||||
format!(
|
||||
"{}::macro_magic",
|
||||
match generate_crate_access_2018("frame-support") {
|
||||
Ok(path) => Ok(path),
|
||||
Err(_) => generate_crate_access_2018("frame"),
|
||||
}
|
||||
.expect("Failed to find either `frame-support` or `frame` in `Cargo.toml` dependencies.")
|
||||
.to_token_stream()
|
||||
.to_string()
|
||||
)
|
||||
}]
|
||||
#[proc_macro_attribute]
|
||||
pub fn import_section(attr: TokenStream, tokens: TokenStream) -> TokenStream {
|
||||
let foreign_mod = parse_macro_input!(attr as ItemMod);
|
||||
let mut internal_mod = parse_macro_input!(tokens as ItemMod);
|
||||
|
||||
// check that internal_mod is a pallet module
|
||||
if !internal_mod.attrs.iter().any(|attr| {
|
||||
if let Some(last_seg) = attr.path().segments.last() {
|
||||
last_seg.ident == "pallet"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
return Error::new(
|
||||
internal_mod.ident.span(),
|
||||
"`#[import_section]` can only be applied to a valid pallet module",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into()
|
||||
}
|
||||
|
||||
if let Some(ref mut content) = internal_mod.content {
|
||||
if let Some(foreign_content) = foreign_mod.content {
|
||||
content.1.extend(foreign_content.1);
|
||||
}
|
||||
}
|
||||
|
||||
quote! {
|
||||
#internal_mod
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
@@ -2896,9 +2896,9 @@ pub mod pallet_macros {
|
||||
pub use frame_support_procedural::{
|
||||
call_index, compact, composite_enum, config, constant,
|
||||
disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit,
|
||||
generate_store, genesis_build, genesis_config, getter, hooks, inherent, no_default, origin,
|
||||
storage, storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight,
|
||||
whitelist_storage,
|
||||
generate_store, genesis_build, genesis_config, getter, hooks, import_section, inherent,
|
||||
no_default, origin, pallet_section, storage, storage_prefix, storage_version, type_value,
|
||||
unbounded, validate_unsigned, weight, whitelist_storage,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 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.
|
||||
|
||||
#[rustversion::attr(not(stable), ignore)]
|
||||
#[cfg(not(feature = "disable-ui-tests"))]
|
||||
#[test]
|
||||
fn split_ui() {
|
||||
// Only run the ui tests when `RUN_UI_TESTS` is set.
|
||||
if std::env::var("RUN_UI_TESTS").is_err() {
|
||||
return
|
||||
}
|
||||
|
||||
// As trybuild is using `cargo check`, we don't need the real WASM binaries.
|
||||
std::env::set_var("SKIP_WASM_BUILD", "1");
|
||||
|
||||
// Deny all warnings since we emit warnings as part of a Pallet's UI.
|
||||
std::env::set_var("RUSTFLAGS", "--deny warnings");
|
||||
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/split_ui/*.rs");
|
||||
t.pass("tests/split_ui/pass/*.rs");
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
#[pallet_section]
|
||||
mod storages {
|
||||
#[pallet::storage]
|
||||
pub type MyStorageMap<T: Config> = StorageMap<_, _, u32, u64>;
|
||||
}
|
||||
|
||||
#[import_section(storages)]
|
||||
pub mod pallet {
|
||||
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
error: `#[import_section]` can only be applied to a valid pallet module
|
||||
--> tests/split_ui/import_without_pallet.rs:12:9
|
||||
|
|
||||
12 | pub mod pallet {
|
||||
| ^^^^^^
|
||||
@@ -0,0 +1,29 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[import_section(storages_dev)]
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn my_call(_origin: OriginFor<T>) -> DispatchResult {
|
||||
MyStorageMap::<T>::insert(1, 2);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
error[E0432]: unresolved import `pallet`
|
||||
--> tests/split_ui/no_section_found.rs:5:9
|
||||
|
|
||||
5 | pub use pallet::*;
|
||||
| ^^^^^^ help: a similar path exists: `test_pallet::pallet`
|
||||
|
||||
error: cannot find macro `__export_tokens_tt_storages_dev` in this scope
|
||||
--> tests/split_ui/no_section_found.rs:7:1
|
||||
|
|
||||
7 | #[import_section(storages_dev)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `frame_support::macro_magic::forward_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
@@ -0,0 +1,40 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[pallet_section]
|
||||
mod events {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
SomethingDone,
|
||||
}
|
||||
}
|
||||
|
||||
#[import_section(events)]
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn my_call(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Self::deposit_event(Event::SomethingDone);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
mod first {
|
||||
use super::*;
|
||||
|
||||
#[pallet_section]
|
||||
mod section {
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
SomethingDone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod second {
|
||||
use super::*;
|
||||
|
||||
#[pallet_section(section2)]
|
||||
mod section {
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
NoneValue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[import_section(first::section)]
|
||||
#[import_section(second::section2)]
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn my_call(_origin: OriginFor<T>) -> DispatchResult {
|
||||
Self::deposit_event(Event::SomethingDone);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn my_call_2(_origin: OriginFor<T>) -> DispatchResult {
|
||||
return Err(Error::<T>::NoneValue.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use frame_support::pallet_macros::*;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
#[pallet_section]
|
||||
mod storages {
|
||||
#[pallet::storage]
|
||||
pub type MyStorageMap<T: Config> = StorageMap<_, _, u32, u64>;
|
||||
}
|
||||
|
||||
#[frame_support::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub fn my_call(_origin: OriginFor<T>) -> DispatchResult {
|
||||
MyStorageMap::<T>::insert(1, 2);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
error[E0433]: failed to resolve: use of undeclared type `MyStorageMap`
|
||||
--> tests/split_ui/section_not_imported.rs:27:4
|
||||
|
|
||||
27 | MyStorageMap::<T>::insert(1, 2);
|
||||
| ^^^^^^^^^^^^
|
||||
| |
|
||||
| use of undeclared type `MyStorageMap`
|
||||
| help: a struct with a similar name exists: `StorageMap`
|
||||
Reference in New Issue
Block a user