Skip to content

Commit

Permalink
[FRAME Core] Adds ability to split a pallet across multiple files (pa…
Browse files Browse the repository at this point in the history
…ritytech#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>
  • Loading branch information
3 people authored and nathanwhit committed Jul 19, 2023
1 parent 5aa73df commit fdcb8bb
Show file tree
Hide file tree
Showing 23 changed files with 837 additions and 5 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 4 additions & 1 deletion frame/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
Expand All @@ -26,11 +27,13 @@ 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",
"pallet-default-config-example/try-runtime",
"pallet-example-offchain-worker/try-runtime",
"pallet-example-kitchensink/try-runtime",
"pallet-dev-mode/try-runtime",
]
"pallet-example-split/try-runtime",
]
47 changes: 47 additions & 0 deletions frame/examples/split/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"]
10 changes: 10 additions & 0 deletions frame/examples/split/README.md
Original file line number Diff line number Diff line change
@@ -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
54 changes: 54 additions & 0 deletions frame/examples/split/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -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);
}
31 changes: 31 additions & 0 deletions frame/examples/split/src/events.rs
Original file line number Diff line number Diff line change
@@ -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 },
}
}
123 changes: 123 additions & 0 deletions frame/examples/split/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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(())
},
}
}
}
}
56 changes: 56 additions & 0 deletions frame/examples/split/src/mock.rs
Original file line number Diff line number Diff line change
@@ -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()
}
Loading

0 comments on commit fdcb8bb

Please sign in to comment.