Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explain usage of <T: Config> in FRAME storage + Update parachain pallet template #4941

Merged
merged 27 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
df831b6
omni-node basics
kianenigma Jun 1, 2024
110f282
Fix --help commands
serban300 Jun 12, 2024
df08dba
`--execution` has no effect and a warning is printed
serban300 Jun 14, 2024
d2e8881
Cosmetics
serban300 Jun 14, 2024
e0a3e1f
Remove unneeded Runtime variant
serban300 Jun 14, 2024
84b1d32
polkadot-parachain-omni-node v0.1.0
serban300 Jun 17, 2024
2c36b25
Remove manual testing chain specs
serban300 Jun 18, 2024
e766b02
Revert renaming
serban300 Jun 19, 2024
37cf6dd
Avoid using hardcoded binary name
serban300 Jun 19, 2024
52c3551
Remove banner
serban300 Jun 19, 2024
a796cd8
polkadot-parachain-bin
serban300 Jun 19, 2024
f758ade
Cargo.lock
serban300 Jun 19, 2024
819d06d
Merge branch 'master' into polkadot-parachain-omni-node
serban300 Jun 20, 2024
db414bd
small fixes
serban300 Jun 20, 2024
afee2dc
Merge remote-tracking branch 'upstream/master' into polkadot-parachai…
serban300 Jun 27, 2024
df2a0a5
Remove more unneeded Runtime variants
serban300 Jun 27, 2024
c19b29a
Fix typo
serban300 Jun 27, 2024
5ad5db6
Merge branch 'master' of github.com:paritytech/polkadot-sdk
kianenigma Jun 28, 2024
ae5fecc
Master.into()
kianenigma Jul 3, 2024
d5a7084
explain how to make FRAME storage generic over <T> + update in pallet…
kianenigma Jul 4, 2024
ce9f542
Merge branch 'master' into kiz-update-tempalates-and-t-in-storage
kianenigma Jul 4, 2024
bb45cd5
fmt
kianenigma Jul 5, 2024
79b25f6
fix
kianenigma Jul 5, 2024
91f3cba
".git/.scripts/commands/fmt/fmt.sh"
Jul 5, 2024
4350d46
Master.into()
kianenigma Jul 10, 2024
211c185
update
kianenigma Jul 10, 2024
6f3193c
Merge branch 'kiz-update-tempalates-and-t-in-storage' of github.com:p…
kianenigma Jul 10, 2024
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
1 change: 1 addition & 0 deletions Cargo.lock

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

4 changes: 1 addition & 3 deletions docs/sdk/src/polkadot_sdk/frame_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,14 @@
//! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template).
//! * writing a runtime in AssemblyScript,as explored in [this project](https://github.com/LimeChain/subsembly).

use frame::prelude::*;

/// A FRAME based pallet. This `mod` is the entry point for everything else. All
/// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an
/// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for
/// more.
#[docify::export]
#[frame::pallet(dev_mode)]
pub mod pallet {
use super::*;
use frame::prelude::*;

/// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a
/// later point from the runtime that wishes to contain it. It allows the pallet to be
Expand Down
199 changes: 199 additions & 0 deletions docs/sdk/src/reference_docs/frame_storage_derives.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
//! <section class="info">
//! In all examples, a few lines of boilerplate have been hidden from each snippet for conciseness.
//! </section>
//!
//! Let's begin by starting to store a `NewType` in a storage item:
//!
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! pub struct NewType(u32);
//
//! #[pallet::storage]
//! pub type Something<T> = StorageValue<_, NewType>;
//! }
//! ```
//!
//! This raises a number of compiler errors, like:
//! ```text
//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
//! StorageInfoTrait`
//! ```
//!
//! This implies the following set of traits that need to be derived for a type to be stored in
//! `frame` storage:
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! pub struct NewType(u32);
//!
//! #[pallet::storage]
//! pub type Something<T> = StorageValue<_, NewType>;
//! }
//! ```
//!
//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
//! storage, such as [`frame::prelude::BlockNumberFor`]:
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
//! }
//! ```
//!
//! Surprisingly, this will also raise a number of errors, like:
//! ```text
//! the trait `TypeInfo` is not implemented for `T`, which is required
//! by`frame_support::pallet_prelude::StorageValue<pallet_2::_GeneratedPrefixForStorageSomething<T>,
//! pallet_2::NewType<T>>:StorageEntryMetadataBuilder
//! ```
//!
//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
//! in the example above.
//!
//! If you expand an instance of the derive, you will find something along the lines of:
//! `impl<T> TypeInfo for NewType<T> where T: TypeInfo { ... }`. This is the reason why the
//! `TypeInfo` trait is required for `T`.
//!
//! To fix this, we need to add a `#[scale_info(skip_type_params(T))]`
//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
//! `T`.
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
//! }
//! ```
//!
//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it
//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
//! right?
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
//! }
//! ```
//!
//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
//! `BlockNumberFor<T>` should indeed implement `Default`, but `T` implementing `Default` is rather
//! meaningless.
//!
//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
//! work nicely on top of structs that are generic over `T: Config`. These macros are:
//!
//! - [`frame::prelude::DefaultNoBound`]
//! - [`frame::prelude::DebugNoBound`]
//! - [`frame::prelude::PartialEqNoBound`]
//! - [`frame::prelude::EqNoBound`]
//! - [`frame::prelude::CloneNoBound`]
kianenigma marked this conversation as resolved.
Show resolved Hide resolved
//! - [`frame::prelude::PartialOrdNoBound`]
//! - [`frame::prelude::OrdNoBound`]
//!
//! The above traits are almost certainly needed for your tests: To print your type, assert equality
//! or clone it.
//!
//! We can fix the following example by using [`frame::prelude::DefaultNoBound`].
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! # use frame::prelude::*;
//! # #[pallet::config]
//! # pub trait Config: frame_system::Config {}
//! # #[pallet::pallet]
//! # pub struct Pallet<T>(_);
//! #[derive(
//! codec::Encode,
//! codec::Decode,
//! codec::MaxEncodedLen,
//! scale_info::TypeInfo,
//! DefaultNoBound
//! )]
//! #[scale_info(skip_type_params(T))]
//! pub struct NewType<T:Config>(BlockNumberFor<T>);
//!
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
//! }
//! ```
//!
//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
//! is subject to the same trait requirements. The following does not work:
//! ```compile_fail
//! #[frame::pallet]
//! pub mod pallet {
//! use frame::prelude::*;
//! #[pallet::config]
//! pub trait Config: frame_system::Config {
//! type CustomType;
//! }
//! #[pallet::pallet]
//! pub struct Pallet<T>(_);
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
//! }
//! ```
//!
//! But adding the right trait bounds will fix it.
//! ```rust
//! #[frame::pallet]
//! pub mod pallet {
//! use frame::prelude::*;
//! #[pallet::config]
//! pub trait Config: frame_system::Config {
//! type CustomType: codec::FullCodec
//! + codec::MaxEncodedLen
//! + scale_info::TypeInfo
//! + Debug
//! + Default;
//! }
//! #[pallet::pallet]
//! pub struct Pallet<T>(_);
//! #[pallet::storage]
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
//! }
//! ```
kianenigma marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions docs/sdk/src/reference_docs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub mod signed_extensions;
/// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built.
pub mod frame_origin;

/// Learn about the details of what derives are needed for a type to be store-able in `frame`
/// storage.
pub mod frame_storage_derives;

/// Learn about how to write safe and defensive code in your FRAME runtime.
pub mod defensive_programming;

Expand Down
3 changes: 2 additions & 1 deletion substrate/frame/bags-list/src/list/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,8 @@ mod bags {
assert_eq!(bag_1000.tail, Some(4));
assert_eq!(bag_1000.iter().count(), 3);
bag_1000.insert_node_unchecked(node(4, None, None, bag_1000.bag_upper)); // panics in debug
assert_eq!(bag_1000.iter().count(), 3); // in release we expect it to silently ignore the request.
assert_eq!(bag_1000.iter().count(), 3); // in release we expect it to silently ignore the
// request.
});
}

Expand Down
8 changes: 7 additions & 1 deletion substrate/frame/nis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,13 @@ pub mod pallet {
// We ignore this error as it just means the amount we're trying to deposit is
// dust and the beneficiary account doesn't exist.
.or_else(
|e| if e == TokenError::CannotCreate.into() { Ok(()) } else { Err(e) },
|e| {
if e == TokenError::CannotCreate.into() {
Copy link
Member

Choose a reason for hiding this comment

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

New formatter 🙈 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah shit :D

Ok(())
} else {
Err(e)
}
},
)?;
summary.receipts_on_hold.saturating_reduce(on_hold);
}
Expand Down
1 change: 0 additions & 1 deletion substrate/frame/nomination-pools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,6 @@ impl ClaimPermission {
frame_support::PartialEqNoBound,
)]
#[cfg_attr(feature = "std", derive(DefaultNoBound))]
#[codec(mel_bound(T: Config))]
#[scale_info(skip_type_params(T))]
pub struct PoolMember<T: Config> {
/// The identifier of the pool to which `who` belongs.
Expand Down
42 changes: 36 additions & 6 deletions substrate/frame/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,43 @@
//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's
//! > State Transition Function (Runtime) Framework.
//!
//! ## Documentation
//! //! ## Usage
//!
//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
//! The main intended use of this crate is for it to be imported with its preludes:
//!
//! ## WARNING: Experimental
//! ```
//! # use polkadot_sdk_frame as frame;
//! #[frame::pallet]
//! pub mod pallet {
//! # use polkadot_sdk_frame as frame;
//! use frame::prelude::*;
//! // ^^ using the prelude!
//!
//! **This crate and all of its content is experimental, and should not yet be used in production.**
//! #[pallet::config]
//! pub trait Config: frame_system::Config {}
//!
//! #[pallet::pallet]
//! pub struct Pallet<T>(_);
//! }
//!
//! pub mod tests {
//! # use polkadot_sdk_frame as frame;
//! use frame::testing_prelude::*;
//! }
//!
//! pub mod runtime {
//! # use polkadot_sdk_frame as frame;
//! use frame::runtime::prelude::*;
//! }
//! ```
//!
//! See: [`prelude`], [`testing_prelude`] and [`runtime::prelude`].
//!
//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`.
//!
//! ## Documentation
//!
//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
//!
//! ## Underlying dependencies
//!
Expand All @@ -46,9 +76,9 @@
//! In short, this crate only re-exports types and traits from multiple sources. All of these
//! sources are listed (and re-exported again) in [`deps`].
//!
//! ## Usage
//! ## WARNING: Experimental
//!
//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`.
//! **This crate and all of its content is experimental, and should not yet be used in production.**

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg(feature = "experimental")]
Expand Down
2 changes: 0 additions & 2 deletions substrate/frame/state-trie-migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ pub mod pallet {
MaxEncodedLen,
)]
#[scale_info(skip_type_params(MaxKeyLen))]
#[codec(mel_bound())]
pub enum Progress<MaxKeyLen: Get<u32>> {
/// Yet to begin.
ToStart,
Expand All @@ -126,7 +125,6 @@ pub mod pallet {
///
/// It tracks the last top and child keys read.
#[derive(Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq, MaxEncodedLen)]
#[codec(mel_bound(T: Config))]
#[scale_info(skip_type_params(T))]
pub struct MigrationTask<T: Config> {
/// The current top trie migration progress.
Expand Down
12 changes: 12 additions & 0 deletions substrate/frame/support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,18 @@ pub mod pallet_macros {
/// }
/// ```
///
/// ### Value Trait Bounds
///
/// To use a type as the value of a storage type, be it `StorageValue`, `StorageMap` or
/// anything else, you need to meet a number of trait bound constraints.
///
/// See: <https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_storage_derives/index.html>.
///
/// Notably, all value types need to implement `Encode`, `Decode`, `MaxEncodedLen` and
/// `TypeInfo`, and possibly `Default`, if
/// [`ValueQuery`](frame_support::storage::types::ValueQuery) is used, explained in the
/// next section.
///
/// ### QueryKind
///
/// Every storage type mentioned above has a generic type called
Expand Down
19 changes: 2 additions & 17 deletions templates/minimal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,6 @@ A Polkadot SDK based project such as this one consists of:
* 🛠️ Depending on your operating system and Rust version, there might be additional
packages required to compile this template - please take note of the Rust compiler output.

## Customization

In case you would like to change the pallet's name from `pallet-minimal-template` to `pallet-test`,
you would need to implement the following changes:
kianenigma marked this conversation as resolved.
Show resolved Hide resolved
* Change the pallet folder name from `template` to `test` for consistency
* Also for consistency, in `/runtime/src/lib.rs`, change from `pub type Template` to `pub type Test`,
and don't forget to also customize the corresponding comments.
* Change `pallet-minimal-template` to `pallet-test` in the following files:
* `/runtime/Cargo.toml`
* `/runtime/src/lib.rs`
* `/pallets/test/Cargo.toml`
* `/src/lib.rs`
* Change `pallet_minimal_template` to `pallet_test` in the following files:
* `/runtime/src/lib.rs`

### Build

🔨 Use the following command to build the node without launching it:
Expand Down Expand Up @@ -80,8 +65,8 @@ docker run --rm polkadot-sdk-minimal-template --dev
Development chains:

* 🧹 Do not persist the state.
* 💰 Are preconfigured with a genesis state that includes several pre-funded development accounts.
* 🧑‍⚖️ Development accounts are used as `sudo` accounts.
* 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts.
* 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts.

### Connect with the Polkadot-JS Apps Front-End

Expand Down
Loading
Loading