diff --git a/.ai/categories/basics.md b/.ai/categories/basics.md index 2fee44423..c1c7b9628 100644 --- a/.ai/categories/basics.md +++ b/.ai/categories/basics.md @@ -117,362 +117,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Contract Deployment @@ -1514,7 +1158,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/dapps.md b/.ai/categories/dapps.md index 59fc473ca..190eeee1d 100644 --- a/.ai/categories/dapps.md +++ b/.ai/categories/dapps.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Contract Deployment @@ -1767,7 +1411,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/infrastructure.md b/.ai/categories/infrastructure.md index fdb9107eb..9e97ca5b5 100644 --- a/.ai/categories/infrastructure.md +++ b/.ai/categories/infrastructure.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Contract Deployment @@ -2240,7 +1884,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/networks.md b/.ai/categories/networks.md index 32021e250..8d0ab4192 100644 --- a/.ai/categories/networks.md +++ b/.ai/categories/networks.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Contract Deployment @@ -1515,7 +1159,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/parachains.md b/.ai/categories/parachains.md index 87ce8b558..8dc600b26 100644 --- a/.ai/categories/parachains.md +++ b/.ai/categories/parachains.md @@ -380,7 +380,7 @@ To interact with the pallet: - **`batchAll(calls)`**: Dispatch multiple calls, stopping on the first error. - **`asDerivative(index, call)`**: Dispatch a call as a derivative account. - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) + ![](/images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp) You can now test the pallet's functionality by submitting transactions through the interface. @@ -847,362 +847,6 @@ You can now use both collective instances for different governance purposes in y ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Add Smart Contract Functionality @@ -4117,7 +3761,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing @@ -6695,136 +6338,731 @@ This section covers the most common customization patterns you'll encounter: --- -Page Title: Pallet Testing +Page Title: Pallet Unit Testing - Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md - Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/pallet-testing/ -- Summary: Learn how to efficiently test pallets in the Polkadot SDK, ensuring the reliability and security of your pallets operations. +- Summary: Learn how to write comprehensive unit tests for your custom pallets using mock runtimes, ensuring reliability and correctness before deployment. -# Pallet Testing +# Pallet Unit Testing ## Introduction -Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries. +Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. With your mock runtime in place from the [previous guide](/parachains/customize-runtime/pallet-development/mock-runtime/), you can now write comprehensive tests that verify your pallet's behavior in isolation. + +In this guide, you'll learn how to: + +- Structure test modules effectively. +- Test dispatchable functions. +- Verify storage changes. +- Check event emission. +- Test error conditions. +- Use genesis configurations in tests. + +## Prerequisites + +Before you begin, ensure you: + +- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. +- Completed the [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) guide. +- Configured custom counter pallet with mock runtime in `pallets/pallet-custom`. +- Understood the basics of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank}. + +## Understanding FRAME Testing Tools + +[FRAME](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\_blank} provides specialized testing macros and utilities that make pallet testing more efficient: + +### Assertion Macros + +- **[`assert_ok!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_ok.html){target=\_blank}** - Asserts that a dispatchable call succeeds. +- **[`assert_noop!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_noop.html){target=\_blank}** - Asserts that a call fails without changing state (no operation). +- **[`assert_eq!`](https://doc.rust-lang.org/std/macro.assert_eq.html){target=\_blank}** - Standard Rust equality assertion. + +!!!info "`assert_noop!` Explained" + Use `assert_noop!` to ensure the operation fails without any state changes. This is critical for testing error conditions - it verifies both that the error occurs AND that no storage was modified. + +### System Pallet Test Helpers + +The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides useful methods for testing: + +- **[`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank}** - Returns all events emitted during the test. +- **[`System::assert_last_event()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}** - Asserts the last event matches expectations. +- **[`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank}** - Sets the current block number. + +!!!info "Events and Block Number" + Events are not emitted on block 0 (genesis block). If you need to test events, ensure you set the block number to at least 1 using `System::set_block_number(1)`. + +### Origin Types + +- **[`RuntimeOrigin::root()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Root){target=\_blank}** - Root/sudo origin for privileged operations. +- **[`RuntimeOrigin::signed(account)`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Signed){target=\_blank}** - Signed origin from a specific account. +- **[`RuntimeOrigin::none()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.None){target=\_blank}** - No origin (typically fails for most operations). + +Learn more about origins in the [FRAME Origin reference document](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_origin/index.html){target=\_blank}. + +## Create the Tests Module + +Create a new file for your tests within the pallet directory: -To begin unit testing, you must first set up a mock runtime that simulates blockchain behavior, incorporating the necessary pallets. For a deeper understanding, consult the [Mock Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/){target=\_blank} guide. +1. Navigate to your pallet directory: -## Writing Unit Tests + ```bash + cd pallets/pallet-custom/src + ``` -Once the mock runtime is in place, the next step is to write unit tests that evaluate the functionality of your pallet. Unit tests allow you to test specific pallet features in isolation, ensuring that each function behaves correctly under various conditions. These tests typically reside in your pallet module's `test.rs` file. +2. Create a new file named `tests.rs`: -Unit tests in the Polkadot SDK use the Rust testing framework, and the mock runtime you've defined earlier will serve as the test environment. Below are the typical steps involved in writing unit tests for a pallet. + ```bash + touch tests.rs + ``` -The tests confirm that: +3. Open `src/lib.rs` and add the tests module declaration after the mock module: -- **Pallets initialize correctly**: At the start of each test, the system should initialize with block number 0, and the pallets should be in their default states. -- **Pallets modify each other's state**: The second test shows how one pallet can trigger changes in another pallet's internal state, confirming proper cross-pallet interactions. -- **State transitions between blocks are seamless**: By simulating block transitions, the tests validate that the runtime responds correctly to changes in the block number. + ```rust title="src/lib.rs" + #![cfg_attr(not(feature = "std"), no_std)] -Testing pallet interactions within the runtime is critical for ensuring the blockchain behaves as expected under real-world conditions. Writing integration tests allows validation of how pallets function together, preventing issues that might arise when the system is fully assembled. + pub use pallet::*; -This approach provides a comprehensive view of the runtime's functionality, ensuring the blockchain is stable and reliable. + #[cfg(test)] + mod mock; -### Test Initialization + #[cfg(test)] + mod tests; -Each test starts by initializing the runtime environment, typically using the `new_test_ext()` function, which sets up the mock storage and environment. + #[frame::pallet] + pub mod pallet { + // ... existing pallet code + } + ``` + +## Set Up the Test Module + +Open `src/tests.rs` and add the basic structure with necessary imports: + +```rust +use crate::{mock::*, Error, Event}; +use frame::deps::frame_support::{assert_noop, assert_ok}; +use frame::deps::sp_runtime::DispatchError; +``` + +This setup imports: + +- The mock runtime and test utilities from `mock.rs` +- Your pallet's `Error` and `Event` types +- FRAME's assertion macros via `frame::deps` +- `DispatchError` for testing origin checks + +???+ code "Complete Pallet Code Reference" + Here's the complete pallet code that you'll be testing throughout this guide: + + ```rust + #![cfg_attr(not(feature = "std"), no_std)] + + pub use pallet::*; + + #[frame::pallet] + pub mod pallet { + use frame::prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + #[pallet::constant] + type CounterMaxValue: Get; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + CounterValueSet { + new_value: u32, + }, + CounterIncremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + CounterDecremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + } + + #[pallet::error] + pub enum Error { + NoneValue, + Overflow, + Underflow, + CounterMaxValueExceeded, + } + + #[pallet::storage] + pub type CounterValue = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + pub type UserInteractions = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u32, + ValueQuery + >; + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig { + pub initial_counter_value: u32, + pub initial_user_interactions: Vec<(T::AccountId, u32)>, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + CounterValue::::put(self.initial_counter_value); + for (account, count) in &self.initial_user_interactions { + UserInteractions::::insert(account, count); + } + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(0)] + pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { + ensure_root(origin)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + Self::deposit_event(Event::CounterValueSet { new_value }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterIncremented { new_value, who, amount }); + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterDecremented { new_value, who, amount }); + Ok(()) + } + } + } + + ``` + +## Write Your First Test + +Let's start with a simple test to verify the increment function works correctly. + +### Test Basic Increment + +Test that the increment function increases counter value and emits events. ```rust #[test] -fn test_pallet_functionality() { +fn increment_works() { new_test_ext().execute_with(|| { - // Test logic goes here + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); }); } ``` -### Function Call Testing +Run your first test: -Call the pallet's extrinsics or functions to simulate user interaction or internal logic. Use the `assert_ok!` macro to check for successful execution and `assert_err!` to verify that errors are correctly handled. +```bash +cargo test --package pallet-custom increment_works +``` + +You should see: + +``` +running 1 test +test tests::increment_works ... ok +``` + +Congratulations! You've written and run your first pallet test. + +## Test Error Conditions + +Now let's test that our pallet correctly handles errors. Error testing is crucial to ensure your pallet fails safely. + +### Test Overflow Protection + +Test that incrementing at u32::MAX fails with Overflow error. ```rust #[test] -fn it_works_for_valid_input() { - new_test_ext().execute_with(|| { - // Call an extrinsic or function - assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param)); +fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); }); } +``` + +Test overflow protection: + +```bash +cargo test --package pallet-custom increment_fails_on_overflow +``` + +### Test Underflow Protection +Test that decrementing below zero fails with Underflow error. + +```rust #[test] -fn it_fails_for_invalid_input() { - new_test_ext().execute_with(|| { - // Call an extrinsic with invalid input and expect an error - assert_err!( - TemplateModule::some_function(Origin::signed(1), invalid_param), - Error::::InvalidInput +fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow ); }); } ``` -### Storage Testing +Verify underflow protection: + +```bash +cargo test --package pallet-custom decrement_fails_on_underflow +``` + +## Test Access Control + +Verify that origin checks work correctly and unauthorized access is prevented. -After calling a function or extrinsic in your pallet, it's essential to verify that the state changes in the pallet's storage match the expected behavior to ensure data is updated correctly based on the actions taken. +### Test Root-Only Access -The following example shows how to test the storage behavior before and after the function call: +Test that set_counter_value requires root origin and rejects signed origins. ```rust #[test] -fn test_storage_update_on_extrinsic_call() { +fn set_counter_value_requires_root() { new_test_ext().execute_with(|| { - // Check the initial storage state (before the call) - assert_eq!(Something::::get(), None); + let alice = 1u64; - // Dispatch a signed extrinsic, which modifies storage - assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); + // When: non-root user tries to set counter + // Then: should fail with BadOrigin + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(alice), 100), + DispatchError::BadOrigin + ); - // Validate that the storage has been updated as expected (after the call) - assert_eq!(Something::::get(), Some(42)); + // But root should succeed + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); }); } +``` +Test access control: + +```bash +cargo test --package pallet-custom set_counter_value_requires_root ``` -### Event Testing +## Test Event Emission + +Verify that events are emitted correctly with the right data. + +### Test Event Data + +The [`increment_works`](/parachains/customize-runtime/pallet-development/pallet-testing/#test-basic-increment) test (shown earlier) already demonstrates event testing by: -It's also crucial to test the events that your pallet emits during execution. By default, events generated in a pallet using the [`#generate_deposit`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\_blank} macro are stored under the system's event storage key (system/events) as [`EventRecord`](https://paritytech.github.io/polkadot-sdk/master/frame_system/struct.EventRecord.html){target=\_blank} entries. These can be accessed using [`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank} or verified with specific helper methods provided by the system pallet, such as [`assert_has_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_has_event){target=\_blank} and [`assert_last_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}. +1. Setting the block number to 1 to enable event emission. +2. Calling the dispatchable function. +3. Using `System::assert_last_event()` to verify the correct event was emitted with expected data. -Here's an example of testing events in a mock runtime: +This pattern applies to all dispatchables that emit events. For a dedicated event-only test focusing on the `set_counter_value` function: + +Test that set_counter_value updates storage and emits correct event. ```rust #[test] -fn it_emits_events_on_success() { +fn set_counter_value_works() { new_test_ext().execute_with(|| { - // Call an extrinsic or function - assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param)); + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); - // Verify that the expected event was emitted - assert!(System::events().iter().any(|record| { - record.event == Event::TemplateModule(TemplateEvent::SomeEvent) - })); + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); }); } ``` -Some key considerations are: +Run the event test: -- **Block number**: Events are not emitted on the genesis block, so you need to set the block number using [`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank} to ensure events are triggered. -- **Converting events**: Use `.into()` when instantiating your pallet's event to convert it into a generic event type, as required by the system's event storage. +```bash +cargo test --package pallet-custom set_counter_value_works +``` -## Where to Go Next +## Test Genesis Configuration + +Verify that genesis configuration works correctly. + +### Test Genesis Setup + +Test that genesis configuration correctly initializes counter and user interactions. + +```rust +#[test] +fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); +} +``` + +Test genesis configuration: + +```bash +cargo test --package pallet-custom genesis_config_works +``` + +## Run All Tests + +Now run all your tests together: + +```bash +cargo test --package pallet-custom +``` + +You should see all tests passing: + +
+ $ cargo test --package pallet-custom + running 15 tests + test mock::__construct_runtime_integrity_test::runtime_integrity_tests ... ok + test mock::test_genesis_config_builds ... ok + test tests::decrement_fails_on_underflow ... ok + test tests::decrement_tracks_multiple_interactions ... ok + test tests::decrement_works ... ok + test tests::different_users_tracked_separately ... ok + test tests::genesis_config_works ... ok + test tests::increment_fails_on_overflow ... ok + test tests::increment_respects_max_value ... ok + test tests::increment_tracks_multiple_interactions ... ok + test tests::increment_works ... ok + test tests::mixed_increment_and_decrement_works ... ok + test tests::set_counter_value_requires_root ... ok + test tests::set_counter_value_respects_max_value ... ok + test tests::set_counter_value_works ... ok + + test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +
+ +!!!note "Mock Runtime Tests" + You'll notice 2 additional tests from the `mock` module: + + - `mock::__construct_runtime_integrity_test::runtime_integrity_tests` - Auto-generated test that validates runtime construction + - `mock::test_genesis_config_builds` - Validates that genesis configuration builds correctly + + These tests are automatically generated from your mock runtime setup and help ensure the test environment itself is valid. + +Congratulations! You have a well-tested pallet covering the essential testing patterns! + +These tests demonstrate comprehensive coverage including basic operations, error conditions, access control, event emission, state management, and genesis configuration. As you build more complex pallets, you'll apply these same patterns to test additional functionality. + +??? code "Full Test Suite Code" + Here's the complete `tests.rs` file for quick reference: + + ```rust + use crate::{mock::*, Error, Event}; + use frame::deps::frame_support::{assert_noop, assert_ok}; + use frame::deps::sp_runtime::DispatchError; + + #[test] + fn set_counter_value_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); + + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); + }); + } + + #[test] + fn set_counter_value_requires_root() { + new_test_ext().execute_with(|| { + // Attempt to set counter with non-root origin should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(1), 100), + DispatchError::BadOrigin + ); + }); + } + + #[test] + fn set_counter_value_respects_max_value() { + new_test_ext().execute_with(|| { + // Attempt to set counter above max value (1000) should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::root(), 1001), + Error::::CounterMaxValueExceeded + ); + + // Setting to exactly max value should work + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 1000)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn increment_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } + + #[test] + fn increment_tracks_multiple_interactions() { + new_test_ext().execute_with(|| { + let account = 1u64; + + // Increment multiple times + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 20)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 30)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 60); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); + }); + } + + #[test] + fn increment_respects_max_value() { + new_test_ext_with_counter(950).execute_with(|| { + // Incrementing past max value (1000) should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 51), + Error::::CounterMaxValueExceeded + ); + + // Incrementing to exactly max value should work + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 50)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn decrement_works() { + new_test_ext_with_counter(100).execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 2u64; + + // Decrement by 30 + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 30)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check event was emitted + System::assert_last_event( + Event::CounterDecremented { + new_value: 70, + who: account, + amount: 30, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } -- Dive into the full implementation of the [`mock.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/mock.rs){target=\_blank} and [`test.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/tests.rs){target=\_blank} files in the [Solochain Template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/solochain){target=_blank}. + #[test] + fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow + ); + }); + } + + #[test] + fn decrement_tracks_multiple_interactions() { + new_test_ext_with_counter(100).execute_with(|| { + let account = 3u64; + + // Decrement multiple times + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 20)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 2) + assert_eq!(crate::UserInteractions::::get(account), 2); + }); + } + + #[test] + fn mixed_increment_and_decrement_works() { + new_test_ext_with_counter(50).execute_with(|| { + let account = 4u64; + + // Mix of increment and decrement + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 25)); + assert_eq!(crate::CounterValue::::get(), 75); + + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 15)); + assert_eq!(crate::CounterValue::::get(), 60); + + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn different_users_tracked_separately() { + new_test_ext().execute_with(|| { + let account1 = 1u64; + let account2 = 2u64; + + // User 1 increments + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + + // User 2 decrements + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account2), 5)); + + // Check counter value (10 + 10 - 5 = 15) + assert_eq!(crate::CounterValue::::get(), 15); + + // Check user interactions are tracked separately + assert_eq!(crate::UserInteractions::::get(account1), 2); + assert_eq!(crate::UserInteractions::::get(account2), 1); + }); + } + + #[test] + fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); + } + ``` + +## Where to Go Next
-- Guide __Benchmarking__ +- Guide __Add Your Custom Pallet to the Runtime__ --- - Explore methods to measure the performance and execution cost of your pallet. + Your pallet is tested and ready! Learn how to integrate it into your runtime. - [:octicons-arrow-right-24: Reference](/develop/parachains/testing/benchmarking) + [:octicons-arrow-right-24: Integrate](/parachains/customize-runtime/pallet-development/add-to-runtime/)
diff --git a/.ai/categories/polkadot-protocol.md b/.ai/categories/polkadot-protocol.md index 77b27d7a5..ac17b5df7 100644 --- a/.ai/categories/polkadot-protocol.md +++ b/.ai/categories/polkadot-protocol.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Contract Deployment @@ -1515,7 +1159,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/smart-contracts.md b/.ai/categories/smart-contracts.md index c3ad3ee60..3bb863ee9 100644 --- a/.ai/categories/smart-contracts.md +++ b/.ai/categories/smart-contracts.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Block Explorers @@ -3256,7 +2900,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/categories/tooling.md b/.ai/categories/tooling.md index a5d3fcb87..31f2f8aff 100644 --- a/.ai/categories/tooling.md +++ b/.ai/categories/tooling.md @@ -118,362 +118,6 @@ The address mapping system maintains security through several design choices evi All source code references are from the [`address.rs`](https://github.com/paritytech/polkadot-sdk/blob/stable2412/substrate/frame/revive/src/address.rs){target=\_blank} file in the Revive pallet of the Polkadot SDK repository. ---- - -Page Title: Add Pallets to the Runtime - -- Source (raw): https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md -- Canonical (HTML): https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ -- Summary: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
- - --- Page Title: Block Explorers @@ -2804,7 +2448,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/pages/parachains-customize-runtime-add-existing-pallets.md b/.ai/pages/parachains-customize-runtime-add-existing-pallets.md index a1f16b681..4ec0691ba 100644 --- a/.ai/pages/parachains-customize-runtime-add-existing-pallets.md +++ b/.ai/pages/parachains-customize-runtime-add-existing-pallets.md @@ -259,7 +259,7 @@ To interact with the pallet: - **`batchAll(calls)`**: Dispatch multiple calls, stopping on the first error. - **`asDerivative(index, call)`**: Dispatch a call as a derivative account. - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) + ![](/images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp) You can now test the pallet's functionality by submitting transactions through the interface. diff --git a/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md b/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md deleted file mode 100644 index 6068afa42..000000000 --- a/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md +++ /dev/null @@ -1,353 +0,0 @@ ---- -title: Add Pallets to the Runtime -description: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. -categories: Basics, Parachains -url: https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/ ---- - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - [dependencies] - ... - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - ... - ], default-features = false } - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - [dependencies] - ... - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - [features] - default = ["std"] - std = [ - ... - "custom-pallet/std", - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - [package] - name = "parachain-template-runtime" - description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." - version = "0.1.0" - license = "Unlicense" - authors.workspace = true - homepage.workspace = true - repository.workspace = true - edition.workspace = true - publish = false - - [package.metadata.docs.rs] - targets = ["x86_64-unknown-linux-gnu"] - - [build-dependencies] - docify = { workspace = true } - substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - - [dependencies] - codec = { features = ["derive"], workspace = true } - cumulus-pallet-parachain-system.workspace = true - docify = { workspace = true } - hex-literal = { optional = true, workspace = true, default-features = true } - log = { workspace = true } - pallet-parachain-template = { path = "../pallets/template", default-features = false } - polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - ], default-features = false } - scale-info = { features = ["derive"], workspace = true } - serde_json = { workspace = true, default-features = false, features = [ - "alloc", - ] } - smallvec = { workspace = true, default-features = true } - - custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - - [features] - default = ["std"] - std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", - ] - - runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", - ] - - try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", - ] - - # Enable the metadata hash generation. - # - # This is hidden behind a feature because it increases the compile time. - # The wasm binary needs to be compiled twice, once to fetch the metadata, - # generate the metadata hash and then a second time with the - # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` - # extension. - metadata-hash = ["substrate-wasm-builder/metadata-hash"] - - # A convenience feature for enabling things when doing a build - # for an on-chain release. - on-chain-release-build = ["metadata-hash"] - - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - [workspace.package] - license = "MIT-0" - authors = ["Parity Technologies "] - homepage = "https://paritytech.github.io/polkadot-sdk/" - repository = "https://github.com/paritytech/polkadot-sdk-parachain-template.git" - edition = "2021" - - [workspace] - default-members = ["pallets/template", "runtime"] - members = [ - "node", "pallets/custom-pallet", - "pallets/template", - "runtime", - ] - resolver = "2" - - [workspace.dependencies] - parachain-template-runtime = { path = "./runtime", default-features = false } - pallet-parachain-template = { path = "./pallets/template", default-features = false } - clap = { version = "4.5.13" } - color-print = { version = "0.3.4" } - docify = { version = "0.2.9" } - futures = { version = "0.3.31" } - jsonrpsee = { version = "0.24.3" } - log = { version = "0.4.22", default-features = false } - polkadot-sdk = { version = "2503.0.1", default-features = false } - prometheus-endpoint = { version = "0.17.2", default-features = false, package = "substrate-prometheus-endpoint" } - serde = { version = "1.0.214", default-features = false } - codec = { version = "3.7.4", default-features = false, package = "parity-scale-codec" } - cumulus-pallet-parachain-system = { version = "0.20.0", default-features = false } - hex-literal = { version = "0.4.1", default-features = false } - scale-info = { version = "2.11.6", default-features = false } - serde_json = { version = "1.0.132", default-features = false } - smallvec = { version = "1.11.0", default-features = false } - substrate-wasm-builder = { version = "26.0.1", default-features = false } - frame = { version = "0.9.1", default-features = false, package = "polkadot-sdk-frame" } - - [profile.release] - opt-level = 3 - panic = "unwind" - - [profile.production] - codegen-units = 1 - inherits = "release" - lto = true - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - // Local module imports - use super::OriginCaller; - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - /// Configure the pallet template in pallets/template. - impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; - } - - // Configure utility pallet. - impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; - } - // Define counter max value runtime constant. - parameter_types! { - pub const CounterMaxValue: u32 = 500; - } - - // Configure custom pallet. - impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - #[frame_support::runtime] - mod runtime { - #[runtime::runtime] - #[runtime::derive( - ... - )] - pub struct Runtime; - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
diff --git a/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md b/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md index b26d07b1f..1f61c2c61 100644 --- a/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md +++ b/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md @@ -1,133 +1,728 @@ --- -title: Pallet Testing -description: Learn how to efficiently test pallets in the Polkadot SDK, ensuring the reliability and security of your pallets operations. +title: Pallet Unit Testing +description: Learn how to write comprehensive unit tests for your custom pallets using mock runtimes, ensuring reliability and correctness before deployment. categories: Parachains url: https://docs.polkadot.com/parachains/customize-runtime/pallet-development/pallet-testing/ --- -# Pallet Testing +# Pallet Unit Testing ## Introduction -Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries. +Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. With your mock runtime in place from the [previous guide](/parachains/customize-runtime/pallet-development/mock-runtime/), you can now write comprehensive tests that verify your pallet's behavior in isolation. -To begin unit testing, you must first set up a mock runtime that simulates blockchain behavior, incorporating the necessary pallets. For a deeper understanding, consult the [Mock Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/){target=\_blank} guide. +In this guide, you'll learn how to: -## Writing Unit Tests +- Structure test modules effectively. +- Test dispatchable functions. +- Verify storage changes. +- Check event emission. +- Test error conditions. +- Use genesis configurations in tests. -Once the mock runtime is in place, the next step is to write unit tests that evaluate the functionality of your pallet. Unit tests allow you to test specific pallet features in isolation, ensuring that each function behaves correctly under various conditions. These tests typically reside in your pallet module's `test.rs` file. +## Prerequisites -Unit tests in the Polkadot SDK use the Rust testing framework, and the mock runtime you've defined earlier will serve as the test environment. Below are the typical steps involved in writing unit tests for a pallet. +Before you begin, ensure you: -The tests confirm that: +- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. +- Completed the [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) guide. +- Configured custom counter pallet with mock runtime in `pallets/pallet-custom`. +- Understood the basics of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank}. -- **Pallets initialize correctly**: At the start of each test, the system should initialize with block number 0, and the pallets should be in their default states. -- **Pallets modify each other's state**: The second test shows how one pallet can trigger changes in another pallet's internal state, confirming proper cross-pallet interactions. -- **State transitions between blocks are seamless**: By simulating block transitions, the tests validate that the runtime responds correctly to changes in the block number. +## Understanding FRAME Testing Tools -Testing pallet interactions within the runtime is critical for ensuring the blockchain behaves as expected under real-world conditions. Writing integration tests allows validation of how pallets function together, preventing issues that might arise when the system is fully assembled. +[FRAME](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\_blank} provides specialized testing macros and utilities that make pallet testing more efficient: -This approach provides a comprehensive view of the runtime's functionality, ensuring the blockchain is stable and reliable. +### Assertion Macros -### Test Initialization +- **[`assert_ok!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_ok.html){target=\_blank}** - Asserts that a dispatchable call succeeds. +- **[`assert_noop!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_noop.html){target=\_blank}** - Asserts that a call fails without changing state (no operation). +- **[`assert_eq!`](https://doc.rust-lang.org/std/macro.assert_eq.html){target=\_blank}** - Standard Rust equality assertion. -Each test starts by initializing the runtime environment, typically using the `new_test_ext()` function, which sets up the mock storage and environment. +!!!info "`assert_noop!` Explained" + Use `assert_noop!` to ensure the operation fails without any state changes. This is critical for testing error conditions - it verifies both that the error occurs AND that no storage was modified. + +### System Pallet Test Helpers + +The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides useful methods for testing: + +- **[`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank}** - Returns all events emitted during the test. +- **[`System::assert_last_event()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}** - Asserts the last event matches expectations. +- **[`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank}** - Sets the current block number. + +!!!info "Events and Block Number" + Events are not emitted on block 0 (genesis block). If you need to test events, ensure you set the block number to at least 1 using `System::set_block_number(1)`. + +### Origin Types + +- **[`RuntimeOrigin::root()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Root){target=\_blank}** - Root/sudo origin for privileged operations. +- **[`RuntimeOrigin::signed(account)`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Signed){target=\_blank}** - Signed origin from a specific account. +- **[`RuntimeOrigin::none()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.None){target=\_blank}** - No origin (typically fails for most operations). + +Learn more about origins in the [FRAME Origin reference document](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_origin/index.html){target=\_blank}. + +## Create the Tests Module + +Create a new file for your tests within the pallet directory: + +1. Navigate to your pallet directory: + + ```bash + cd pallets/pallet-custom/src + ``` + +2. Create a new file named `tests.rs`: + + ```bash + touch tests.rs + ``` + +3. Open `src/lib.rs` and add the tests module declaration after the mock module: + + ```rust title="src/lib.rs" + #![cfg_attr(not(feature = "std"), no_std)] + + pub use pallet::*; + + #[cfg(test)] + mod mock; + + #[cfg(test)] + mod tests; + + #[frame::pallet] + pub mod pallet { + // ... existing pallet code + } + ``` + +## Set Up the Test Module + +Open `src/tests.rs` and add the basic structure with necessary imports: + +```rust +use crate::{mock::*, Error, Event}; +use frame::deps::frame_support::{assert_noop, assert_ok}; +use frame::deps::sp_runtime::DispatchError; +``` + +This setup imports: + +- The mock runtime and test utilities from `mock.rs` +- Your pallet's `Error` and `Event` types +- FRAME's assertion macros via `frame::deps` +- `DispatchError` for testing origin checks + +???+ code "Complete Pallet Code Reference" + Here's the complete pallet code that you'll be testing throughout this guide: + + ```rust + #![cfg_attr(not(feature = "std"), no_std)] + + pub use pallet::*; + + #[frame::pallet] + pub mod pallet { + use frame::prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + #[pallet::constant] + type CounterMaxValue: Get; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + CounterValueSet { + new_value: u32, + }, + CounterIncremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + CounterDecremented { + new_value: u32, + who: T::AccountId, + amount: u32, + }, + } + + #[pallet::error] + pub enum Error { + NoneValue, + Overflow, + Underflow, + CounterMaxValueExceeded, + } + + #[pallet::storage] + pub type CounterValue = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + pub type UserInteractions = StorageMap< + _, + Blake2_128Concat, + T::AccountId, + u32, + ValueQuery + >; + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig { + pub initial_counter_value: u32, + pub initial_user_interactions: Vec<(T::AccountId, u32)>, + } + + #[pallet::genesis_build] + impl BuildGenesisConfig for GenesisConfig { + fn build(&self) { + CounterValue::::put(self.initial_counter_value); + for (account, count) in &self.initial_user_interactions { + UserInteractions::::insert(account, count); + } + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(0)] + pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { + ensure_root(origin)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + Self::deposit_event(Event::CounterValueSet { new_value }); + Ok(()) + } + + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?; + ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded); + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterIncremented { new_value, who, amount }); + Ok(()) + } + + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + let current_value = CounterValue::::get(); + let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?; + CounterValue::::put(new_value); + UserInteractions::::mutate(&who, |count| { + *count = count.saturating_add(1); + }); + Self::deposit_event(Event::CounterDecremented { new_value, who, amount }); + Ok(()) + } + } + } + + ``` + +## Write Your First Test + +Let's start with a simple test to verify the increment function works correctly. + +### Test Basic Increment + +Test that the increment function increases counter value and emits events. ```rust #[test] -fn test_pallet_functionality() { +fn increment_works() { new_test_ext().execute_with(|| { - // Test logic goes here + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); }); } ``` -### Function Call Testing +Run your first test: + +```bash +cargo test --package pallet-custom increment_works +``` + +You should see: + +``` +running 1 test +test tests::increment_works ... ok +``` + +Congratulations! You've written and run your first pallet test. + +## Test Error Conditions + +Now let's test that our pallet correctly handles errors. Error testing is crucial to ensure your pallet fails safely. -Call the pallet's extrinsics or functions to simulate user interaction or internal logic. Use the `assert_ok!` macro to check for successful execution and `assert_err!` to verify that errors are correctly handled. +### Test Overflow Protection + +Test that incrementing at u32::MAX fails with Overflow error. ```rust #[test] -fn it_works_for_valid_input() { - new_test_ext().execute_with(|| { - // Call an extrinsic or function - assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param)); +fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); }); } +``` + +Test overflow protection: +```bash +cargo test --package pallet-custom increment_fails_on_overflow +``` + +### Test Underflow Protection + +Test that decrementing below zero fails with Underflow error. + +```rust #[test] -fn it_fails_for_invalid_input() { - new_test_ext().execute_with(|| { - // Call an extrinsic with invalid input and expect an error - assert_err!( - TemplateModule::some_function(Origin::signed(1), invalid_param), - Error::::InvalidInput +fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow ); }); } ``` -### Storage Testing +Verify underflow protection: + +```bash +cargo test --package pallet-custom decrement_fails_on_underflow +``` + +## Test Access Control + +Verify that origin checks work correctly and unauthorized access is prevented. -After calling a function or extrinsic in your pallet, it's essential to verify that the state changes in the pallet's storage match the expected behavior to ensure data is updated correctly based on the actions taken. +### Test Root-Only Access -The following example shows how to test the storage behavior before and after the function call: +Test that set_counter_value requires root origin and rejects signed origins. ```rust #[test] -fn test_storage_update_on_extrinsic_call() { +fn set_counter_value_requires_root() { new_test_ext().execute_with(|| { - // Check the initial storage state (before the call) - assert_eq!(Something::::get(), None); + let alice = 1u64; - // Dispatch a signed extrinsic, which modifies storage - assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); + // When: non-root user tries to set counter + // Then: should fail with BadOrigin + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(alice), 100), + DispatchError::BadOrigin + ); - // Validate that the storage has been updated as expected (after the call) - assert_eq!(Something::::get(), Some(42)); + // But root should succeed + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); }); } +``` + +Test access control: +```bash +cargo test --package pallet-custom set_counter_value_requires_root ``` -### Event Testing +## Test Event Emission + +Verify that events are emitted correctly with the right data. + +### Test Event Data -It's also crucial to test the events that your pallet emits during execution. By default, events generated in a pallet using the [`#generate_deposit`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\_blank} macro are stored under the system's event storage key (system/events) as [`EventRecord`](https://paritytech.github.io/polkadot-sdk/master/frame_system/struct.EventRecord.html){target=\_blank} entries. These can be accessed using [`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank} or verified with specific helper methods provided by the system pallet, such as [`assert_has_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_has_event){target=\_blank} and [`assert_last_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}. +The [`increment_works`](/parachains/customize-runtime/pallet-development/pallet-testing/#test-basic-increment) test (shown earlier) already demonstrates event testing by: -Here's an example of testing events in a mock runtime: +1. Setting the block number to 1 to enable event emission. +2. Calling the dispatchable function. +3. Using `System::assert_last_event()` to verify the correct event was emitted with expected data. + +This pattern applies to all dispatchables that emit events. For a dedicated event-only test focusing on the `set_counter_value` function: + +Test that set_counter_value updates storage and emits correct event. ```rust #[test] -fn it_emits_events_on_success() { +fn set_counter_value_works() { new_test_ext().execute_with(|| { - // Call an extrinsic or function - assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param)); + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); - // Verify that the expected event was emitted - assert!(System::events().iter().any(|record| { - record.event == Event::TemplateModule(TemplateEvent::SomeEvent) - })); + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); }); } ``` -Some key considerations are: +Run the event test: -- **Block number**: Events are not emitted on the genesis block, so you need to set the block number using [`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank} to ensure events are triggered. -- **Converting events**: Use `.into()` when instantiating your pallet's event to convert it into a generic event type, as required by the system's event storage. +```bash +cargo test --package pallet-custom set_counter_value_works +``` -## Where to Go Next +## Test Genesis Configuration -- Dive into the full implementation of the [`mock.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/mock.rs){target=\_blank} and [`test.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/tests.rs){target=\_blank} files in the [Solochain Template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/solochain){target=_blank}. +Verify that genesis configuration works correctly. + +### Test Genesis Setup + +Test that genesis configuration correctly initializes counter and user interactions. + +```rust +#[test] +fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); +} +``` + +Test genesis configuration: + +```bash +cargo test --package pallet-custom genesis_config_works +``` + +## Run All Tests + +Now run all your tests together: + +```bash +cargo test --package pallet-custom +``` + +You should see all tests passing: + +
+ $ cargo test --package pallet-custom + running 15 tests + test mock::__construct_runtime_integrity_test::runtime_integrity_tests ... ok + test mock::test_genesis_config_builds ... ok + test tests::decrement_fails_on_underflow ... ok + test tests::decrement_tracks_multiple_interactions ... ok + test tests::decrement_works ... ok + test tests::different_users_tracked_separately ... ok + test tests::genesis_config_works ... ok + test tests::increment_fails_on_overflow ... ok + test tests::increment_respects_max_value ... ok + test tests::increment_tracks_multiple_interactions ... ok + test tests::increment_works ... ok + test tests::mixed_increment_and_decrement_works ... ok + test tests::set_counter_value_requires_root ... ok + test tests::set_counter_value_respects_max_value ... ok + test tests::set_counter_value_works ... ok + + test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +
+ +!!!note "Mock Runtime Tests" + You'll notice 2 additional tests from the `mock` module: + + - `mock::__construct_runtime_integrity_test::runtime_integrity_tests` - Auto-generated test that validates runtime construction + - `mock::test_genesis_config_builds` - Validates that genesis configuration builds correctly + + These tests are automatically generated from your mock runtime setup and help ensure the test environment itself is valid. + +Congratulations! You have a well-tested pallet covering the essential testing patterns! + +These tests demonstrate comprehensive coverage including basic operations, error conditions, access control, event emission, state management, and genesis configuration. As you build more complex pallets, you'll apply these same patterns to test additional functionality. + +??? code "Full Test Suite Code" + Here's the complete `tests.rs` file for quick reference: + + ```rust + use crate::{mock::*, Error, Event}; + use frame::deps::frame_support::{assert_noop, assert_ok}; + use frame::deps::sp_runtime::DispatchError; + + #[test] + fn set_counter_value_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); + + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); + }); + } + + #[test] + fn set_counter_value_requires_root() { + new_test_ext().execute_with(|| { + // Attempt to set counter with non-root origin should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(1), 100), + DispatchError::BadOrigin + ); + }); + } + + #[test] + fn set_counter_value_respects_max_value() { + new_test_ext().execute_with(|| { + // Attempt to set counter above max value (1000) should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::root(), 1001), + Error::::CounterMaxValueExceeded + ); + + // Setting to exactly max value should work + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 1000)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn increment_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } + + #[test] + fn increment_tracks_multiple_interactions() { + new_test_ext().execute_with(|| { + let account = 1u64; + + // Increment multiple times + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 20)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 30)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 60); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); + }); + } + + #[test] + fn increment_respects_max_value() { + new_test_ext_with_counter(950).execute_with(|| { + // Incrementing past max value (1000) should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 51), + Error::::CounterMaxValueExceeded + ); + + // Incrementing to exactly max value should work + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 50)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn decrement_works() { + new_test_ext_with_counter(100).execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 2u64; + + // Decrement by 30 + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 30)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check event was emitted + System::assert_last_event( + Event::CounterDecremented { + new_value: 70, + who: account, + amount: 30, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } + + #[test] + fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow + ); + }); + } + + #[test] + fn decrement_tracks_multiple_interactions() { + new_test_ext_with_counter(100).execute_with(|| { + let account = 3u64; + + // Decrement multiple times + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 20)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 2) + assert_eq!(crate::UserInteractions::::get(account), 2); + }); + } + + #[test] + fn mixed_increment_and_decrement_works() { + new_test_ext_with_counter(50).execute_with(|| { + let account = 4u64; + + // Mix of increment and decrement + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 25)); + assert_eq!(crate::CounterValue::::get(), 75); + + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 15)); + assert_eq!(crate::CounterValue::::get(), 60); + + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn different_users_tracked_separately() { + new_test_ext().execute_with(|| { + let account1 = 1u64; + let account2 = 2u64; + + // User 1 increments + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + + // User 2 decrements + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account2), 5)); + + // Check counter value (10 + 10 - 5 = 15) + assert_eq!(crate::CounterValue::::get(), 15); + + // Check user interactions are tracked separately + assert_eq!(crate::UserInteractions::::get(account1), 2); + assert_eq!(crate::UserInteractions::::get(account2), 1); + }); + } + + #[test] + fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); + } + ``` + +## Where to Go Next
-- Guide __Benchmarking__ +- Guide __Add Your Custom Pallet to the Runtime__ --- - Explore methods to measure the performance and execution cost of your pallet. + Your pallet is tested and ready! Learn how to integrate it into your runtime. - [:octicons-arrow-right-24: Reference](/develop/parachains/testing/benchmarking) + [:octicons-arrow-right-24: Integrate](/parachains/customize-runtime/pallet-development/add-to-runtime/)
diff --git a/.ai/pages/parachains-get-started.md b/.ai/pages/parachains-get-started.md index 3340ae306..d0e1e7d40 100644 --- a/.ai/pages/parachains-get-started.md +++ b/.ai/pages/parachains-get-started.md @@ -49,7 +49,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing diff --git a/.ai/site-index.json b/.ai/site-index.json index 089f9ad41..e3a508617 100644 --- a/.ai/site-index.json +++ b/.ai/site-index.json @@ -1124,12 +1124,12 @@ } ], "stats": { - "chars": 11924, - "words": 1585, + "chars": 11893, + "words": 1580, "headings": 14, - "estimated_token_count_total": 2724 + "estimated_token_count_total": 2714 }, - "hash": "sha256:93d123cbaaccc2515b4a70be8e1327b4f75b1051d16c5e3daf5a2035af7b7ca3", + "hash": "sha256:91ac8b9f927485eaa7b147110a7f5057eea982f9ea9783fe039aae613b05b404", "token_estimator": "heuristic-v1" }, { @@ -1359,58 +1359,6 @@ "hash": "sha256:6297bb5e0809fdd0585d6170054599f7ab4a3ce7c687ad03ae43092057c493b7", "token_estimator": "heuristic-v1" }, - { - "id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", - "title": "Add Pallets to the Runtime", - "slug": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", - "categories": [ - "Basics", - "Parachains" - ], - "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md", - "html_url": "https://docs.polkadot.com/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/", - "preview": "In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain.", - "outline": [ - { - "depth": 2, - "title": "Introduction", - "anchor": "introduction" - }, - { - "depth": 2, - "title": "Add the Pallets as Dependencies", - "anchor": "add-the-pallets-as-dependencies" - }, - { - "depth": 3, - "title": "Update the Runtime Configuration", - "anchor": "update-the-runtime-configuration" - }, - { - "depth": 2, - "title": "Recompile the Runtime", - "anchor": "recompile-the-runtime" - }, - { - "depth": 2, - "title": "Run Your Chain Locally", - "anchor": "run-your-chain-locally" - }, - { - "depth": 2, - "title": "Where to Go Next", - "anchor": "where-to-go-next" - } - ], - "stats": { - "chars": 13091, - "words": 1522, - "headings": 6, - "estimated_token_count_total": 3091 - }, - "hash": "sha256:87add0ae178e4970601a27efccadb58eff1375d19819201034ba2829914f1cd5", - "token_estimator": "heuristic-v1" - }, { "id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "title": "Benchmarking FRAME Pallets", @@ -1716,14 +1664,14 @@ }, { "id": "parachains-customize-runtime-pallet-development-pallet-testing", - "title": "Pallet Testing", + "title": "Pallet Unit Testing", "slug": "parachains-customize-runtime-pallet-development-pallet-testing", "categories": [ "Parachains" ], "raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md", "html_url": "https://docs.polkadot.com/parachains/customize-runtime/pallet-development/pallet-testing/", - "preview": "Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries.", + "preview": "Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. With your mock runtime in place from the [previous guide](/parachains/customize-runtime/pallet-development/mock-runtime/), you can now write comprehensive tests that verify your pallet's behavior in isolation.", "outline": [ { "depth": 2, @@ -1732,28 +1680,98 @@ }, { "depth": 2, - "title": "Writing Unit Tests", - "anchor": "writing-unit-tests" + "title": "Prerequisites", + "anchor": "prerequisites" + }, + { + "depth": 2, + "title": "Understanding FRAME Testing Tools", + "anchor": "understanding-frame-testing-tools" }, { "depth": 3, - "title": "Test Initialization", - "anchor": "test-initialization" + "title": "Assertion Macros", + "anchor": "assertion-macros" }, { "depth": 3, - "title": "Function Call Testing", - "anchor": "function-call-testing" + "title": "System Pallet Test Helpers", + "anchor": "system-pallet-test-helpers" }, { "depth": 3, - "title": "Storage Testing", - "anchor": "storage-testing" + "title": "Origin Types", + "anchor": "origin-types" + }, + { + "depth": 2, + "title": "Create the Tests Module", + "anchor": "create-the-tests-module" + }, + { + "depth": 2, + "title": "Set Up the Test Module", + "anchor": "set-up-the-test-module" + }, + { + "depth": 2, + "title": "Write Your First Test", + "anchor": "write-your-first-test" }, { "depth": 3, - "title": "Event Testing", - "anchor": "event-testing" + "title": "Test Basic Increment", + "anchor": "test-basic-increment" + }, + { + "depth": 2, + "title": "Test Error Conditions", + "anchor": "test-error-conditions" + }, + { + "depth": 3, + "title": "Test Overflow Protection", + "anchor": "test-overflow-protection" + }, + { + "depth": 3, + "title": "Test Underflow Protection", + "anchor": "test-underflow-protection" + }, + { + "depth": 2, + "title": "Test Access Control", + "anchor": "test-access-control" + }, + { + "depth": 3, + "title": "Test Root-Only Access", + "anchor": "test-root-only-access" + }, + { + "depth": 2, + "title": "Test Event Emission", + "anchor": "test-event-emission" + }, + { + "depth": 3, + "title": "Test Event Data", + "anchor": "test-event-data" + }, + { + "depth": 2, + "title": "Test Genesis Configuration", + "anchor": "test-genesis-configuration" + }, + { + "depth": 3, + "title": "Test Genesis Setup", + "anchor": "test-genesis-setup" + }, + { + "depth": 2, + "title": "Run All Tests", + "anchor": "run-all-tests" }, { "depth": 2, @@ -1762,12 +1780,12 @@ } ], "stats": { - "chars": 6892, - "words": 911, - "headings": 7, - "estimated_token_count_total": 1563 + "chars": 25092, + "words": 2533, + "headings": 21, + "estimated_token_count_total": 5673 }, - "hash": "sha256:8568dfa238b9a649a4e6e60510625c2e7879b76a93187b0b8b8dccf6bc467ae6", + "hash": "sha256:5b6975fc79037690c912a0644a0a438212248e984d7fdb35bd6aea820e637965", "token_estimator": "heuristic-v1" }, { @@ -1896,12 +1914,12 @@ } ], "stats": { - "chars": 7941, - "words": 631, + "chars": 7764, + "words": 607, "headings": 9, - "estimated_token_count_total": 2292 + "estimated_token_count_total": 2251 }, - "hash": "sha256:759ed27cf3d473445e33141089b652082c42a2c59eb822d6b506146fd9555e13", + "hash": "sha256:4464114886271689453fe20b026a6d95f5add6a2c5aa53bcf9c22b08415e68dc", "token_estimator": "heuristic-v1" }, { diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml deleted file mode 100644 index de0b6da9e..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml +++ /dev/null @@ -1,102 +0,0 @@ -[package] -name = "parachain-template-runtime" -description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." -version = "0.1.0" -license = "Unlicense" -authors.workspace = true -homepage.workspace = true -repository.workspace = true -edition.workspace = true -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[build-dependencies] -docify = { workspace = true } -substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - -[dependencies] -codec = { features = ["derive"], workspace = true } -cumulus-pallet-parachain-system.workspace = true -docify = { workspace = true } -hex-literal = { optional = true, workspace = true, default-features = true } -log = { workspace = true } -pallet-parachain-template = { path = "../pallets/template", default-features = false } -polkadot-sdk = { workspace = true, features = [ - "pallet-utility", - "cumulus-pallet-aura-ext", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-weight-reclaim", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-utility", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", - "polkadot-parachain-primitives", - "polkadot-runtime-common", - "runtime", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", -], default-features = false } -scale-info = { features = ["derive"], workspace = true } -serde_json = { workspace = true, default-features = false, features = [ - "alloc", -] } -smallvec = { workspace = true, default-features = true } - -custom-pallet = { path = "../pallets/custom-pallet", default-features = false } - -[features] -default = ["std"] -std = [ - "codec/std", - "cumulus-pallet-parachain-system/std", - "log/std", - "pallet-parachain-template/std", - "polkadot-sdk/std", - "scale-info/std", - "serde_json/std", - "substrate-wasm-builder", - "custom-pallet/std", -] - -runtime-benchmarks = [ - "cumulus-pallet-parachain-system/runtime-benchmarks", - "hex-literal", - "pallet-parachain-template/runtime-benchmarks", - "polkadot-sdk/runtime-benchmarks", -] - -try-runtime = [ - "cumulus-pallet-parachain-system/try-runtime", - "pallet-parachain-template/try-runtime", - "polkadot-sdk/try-runtime", -] - -# Enable the metadata hash generation. -# -# This is hidden behind a feature because it increases the compile time. -# The wasm binary needs to be compiled twice, once to fetch the metadata, -# generate the metadata hash and then a second time with the -# `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash` -# extension. -metadata-hash = ["substrate-wasm-builder/metadata-hash"] - -# A convenience feature for enabling things when doing a build -# for an on-chain release. -on-chain-release-build = ["metadata-hash"] diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/build.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/build.rs deleted file mode 100644 index 83200815b..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[cfg(all(feature = "std", feature = "metadata-hash"))] -#[docify::export(template_enable_metadata_hash)] -fn main() { - substrate_wasm_builder::WasmBuilder::init_with_defaults() - .enable_metadata_hash("UNIT", 12) - .build(); -} - -#[cfg(all(feature = "std", not(feature = "metadata-hash")))] -fn main() { - substrate_wasm_builder::WasmBuilder::build_using_defaults(); -} - -/// The wasm builder is deactivated when compiling -/// this crate for wasm to speed up the compilation. -#[cfg(not(feature = "std"))] -fn main() {} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/apis.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/apis.rs deleted file mode 100644 index d01d678be..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/apis.rs +++ /dev/null @@ -1,308 +0,0 @@ -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to - -// External crates imports -use alloc::vec::Vec; - -use polkadot_sdk::*; - -use frame_support::{ - genesis_builder_helper::{build_state, get_preset}, - weights::Weight, -}; -use pallet_aura::Authorities; -use sp_api::impl_runtime_apis; -use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -use sp_version::RuntimeVersion; - -// Local module imports -use super::{ - AccountId, Balance, Block, ConsensusHook, Executive, InherentDataExt, Nonce, ParachainSystem, - Runtime, RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, - SLOT_DURATION, VERSION, -}; - -// we move some impls outside so we can easily use them with `docify`. -impl Runtime { - #[docify::export] - fn impl_slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION) - } - - #[docify::export] - fn impl_can_build_upon( - included_hash: ::Hash, - slot: cumulus_primitives_aura::Slot, - ) -> bool { - ConsensusHook::can_build_upon(included_hash, slot) - } -} - -impl_runtime_apis! { - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - Runtime::impl_slot_duration() - } - - fn authorities() -> Vec { - Authorities::::get().into_inner() - } - } - - impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { - fn can_build_upon( - included_hash: ::Hash, - slot: cumulus_primitives_aura::Slot, - ) -> bool { - Runtime::impl_can_build_upon(included_hash, slot) - } - } - - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> Vec { - Runtime::metadata_versions() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(extrinsic: ::Extrinsic) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents( - block: Block, - data: sp_inherents::InherentData, - ) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Nonce { - System::account_nonce(account) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - TransactionPayment::query_info(uxt, len) - } - fn query_fee_details( - uxt: ::Extrinsic, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_fee_details(uxt, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi - for Runtime - { - fn query_call_info( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::RuntimeDispatchInfo { - TransactionPayment::query_call_info(call, len) - } - fn query_call_fee_details( - call: RuntimeCall, - len: u32, - ) -> pallet_transaction_payment::FeeDetails { - TransactionPayment::query_call_fee_details(call, len) - } - fn query_weight_to_fee(weight: Weight) -> Balance { - TransactionPayment::weight_to_fee(weight) - } - fn query_length_to_fee(length: u32) -> Balance { - TransactionPayment::length_to_fee(length) - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - use super::configs::RuntimeBlockWeights; - - let weight = Executive::try_runtime_upgrade(checks).unwrap(); - (weight, RuntimeBlockWeights::get().max_block) - } - - fn execute_block( - block: Block, - state_root_check: bool, - signature_check: bool, - select: frame_try_runtime::TryStateSelect, - ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. - Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(extra: bool) -> ( - Vec, - Vec, - ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; - use polkadot_sdk::frame_support::traits::StorageInfoTrait; - use frame_system_benchmarking::Pallet as SystemBench; - use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - use super::*; - - let mut list = Vec::::new(); - list_benchmarks!(list, extra); - - let storage_info = AllPalletsWithSystem::storage_info(); - (list, storage_info) - } - - fn dispatch_benchmark( - config: frame_benchmarking::BenchmarkConfig - ) -> Result, alloc::string::String> { - use frame_benchmarking::{BenchmarkError, Benchmarking, BenchmarkBatch}; - use super::*; - - use frame_system_benchmarking::Pallet as SystemBench; - impl frame_system_benchmarking::Config for Runtime { - fn setup_set_code_requirements(code: &Vec) -> Result<(), BenchmarkError> { - ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); - Ok(()) - } - - fn verify_set_code() { - System::assert_last_event(cumulus_pallet_parachain_system::Event::::ValidationFunctionStored.into()); - } - } - - use cumulus_pallet_session_benchmarking::Pallet as SessionBench; - impl cumulus_pallet_session_benchmarking::Config for Runtime {} - - use polkadot_sdk::frame_support::traits::WhitelistedStorageKeys; - let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); - - let mut batches = Vec::::new(); - let params = (&config, &whitelist); - add_benchmarks!(params, batches); - - if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } - Ok(batches) - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(config: Vec) -> sp_genesis_builder::Result { - build_state::(config) - } - - fn get_preset(id: &Option) -> Option> { - get_preset::(id, crate::genesis_config_presets::get_preset) - } - - fn preset_names() -> Vec { - crate::genesis_config_presets::preset_names() - } - } -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/benchmarks.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/benchmarks.rs deleted file mode 100644 index 179187b05..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/benchmarks.rs +++ /dev/null @@ -1,37 +0,0 @@ -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to - -polkadot_sdk::frame_benchmarking::define_benchmarks!( - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_session, SessionBench::] - [pallet_timestamp, Timestamp] - [pallet_message_queue, MessageQueue] - [pallet_sudo, Sudo] - [pallet_collator_selection, CollatorSelection] - [cumulus_pallet_parachain_system, ParachainSystem] - [cumulus_pallet_xcmp_queue, XcmpQueue] - [custom_pallet, CustomPallet] -); diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs deleted file mode 100644 index 035d1c75b..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs +++ /dev/null @@ -1,344 +0,0 @@ -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to - -mod xcm_config; - -use polkadot_sdk::{staging_parachain_info as parachain_info, staging_xcm as xcm, *}; -#[cfg(not(feature = "runtime-benchmarks"))] -use polkadot_sdk::{staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor}; - -// Substrate and Polkadot dependencies -use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; -use frame_support::{ - derive_impl, - dispatch::DispatchClass, - parameter_types, - traits::{ - ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin, VariantCountOf, - }, - weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, -}; -use pallet_xcm::{EnsureXcm, IsVoiceOfBody}; -use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; -use polkadot_runtime_common::{ - xcm_sender::NoPriceForMessageDelivery, BlockHashCount, SlowAdjustingFeeUpdate, -}; -use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_runtime::Perbill; -use sp_version::RuntimeVersion; -use xcm::latest::prelude::BodyId; - -// Local module imports -use super::OriginCaller; -use super::{ - weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}, - AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, ConsensusHook, Hash, - MessageQueue, Nonce, PalletInfo, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, - RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, - System, WeightToFee, XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, EXISTENTIAL_DEPOSIT, HOURS, - MAXIMUM_BLOCK_WEIGHT, MICRO_UNIT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION, -}; -use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin}; - -parameter_types! { - pub const Version: RuntimeVersion = VERSION; - - // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. - // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the - // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize - // the lazy contract deletion. - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub const SS58Prefix: u16 = 42; -} - -/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from -/// [`ParaChainDefaultConfig`](`struct@frame_system::config_preludes::ParaChainDefaultConfig`), -/// but overridden as needed. -#[derive_impl(frame_system::config_preludes::ParaChainDefaultConfig)] -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The block type. - type Block = Block; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; - /// This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -/// Configure the pallet weight reclaim tx. -impl cumulus_pallet_weight_reclaim::Config for Runtime { - type WeightInfo = (); -} - -impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<0>; - type WeightInfo = (); -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = (CollatorSelection,); -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; -} - -impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - /// The type for recording an account's balance. - type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = RuntimeFreezeReason; - type MaxFreezes = VariantCountOf; - type DoneSlashHandler = (); -} - -parameter_types! { - /// Relay Chain `TransactionByteFee` / 10 - pub const TransactionByteFee: Balance = 10 * MICRO_UNIT; -} - -impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightInfo = (); -} - -impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type WeightInfo = (); -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = XcmpQueue; - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; - type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; - type ConsensusHook = ConsensusHook; - type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin: - type QueueChangeHandler = NarrowOriginToSibling; - type QueuePausedQuery = NarrowOriginToSibling; - type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; - type IdleMaxServiceWeight = (); -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - // Enqueue XCMP messages from siblings for later processing. - type XcmpQueue = TransformOrigin; - type MaxInboundSuspended = sp_core::ConstU32<1_000>; - type MaxActiveOutboundChannels = ConstU32<128>; - type MaxPageSize = ConstU32<{ 1 << 16 }>; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); - type PriceForSiblingDelivery = NoPriceForMessageDelivery; -} - -parameter_types! { - pub const Period: u32 = 6 * HOURS; - pub const Offset: u32 = 0; -} - -impl pallet_session::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ValidatorId = ::AccountId; - // we don't have stash and controller, thus we don't need the convert as well. - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionManager = CollatorSelection; - // Essentially just Aura, but let's be pedantic. - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - type DisablingStrategy = (); - type WeightInfo = (); -} - -#[docify::export(aura_config)] -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = ConstU64; -} - -parameter_types! { - pub const PotId: PalletId = PalletId(*b"PotStake"); - pub const SessionLength: BlockNumber = 6 * HOURS; - // StakingAdmin pluralistic body. - pub const StakingAdminBodyId: BodyId = BodyId::Defense; -} - -/// We allow root and the StakingAdmin to execute privileged collator selection operations. -pub type CollatorSelectionUpdateOrigin = EitherOfDiverse< - EnsureRoot, - EnsureXcm>, ->; - -impl pallet_collator_selection::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type UpdateOrigin = CollatorSelectionUpdateOrigin; - type PotId = PotId; - type MaxCandidates = ConstU32<100>; - type MinEligibleCollators = ConstU32<4>; - type MaxInvulnerables = ConstU32<20>; - // should be a multiple of session or things will get inconsistent - type KickThreshold = Period; - type ValidatorId = ::AccountId; - type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ValidatorRegistration = Session; - type WeightInfo = (); -} - -/// Configure the pallet template in pallets/template. -impl pallet_parachain_template::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; -} - -// Configure utility pallet. -impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; - type PalletsOrigin = OriginCaller; - type WeightInfo = pallet_utility::weights::SubstrateWeight; -} - -// Define counter max value runtime constant. -parameter_types! { - pub const CounterMaxValue: u32 = 500; -} - -// Configure custom pallet. -impl custom_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type CounterMaxValue = CounterMaxValue; - type WeightInfo = custom_pallet::weights::SubstrateWeight; -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/xcm_config.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/xcm_config.rs deleted file mode 100644 index 85a513ac8..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/xcm_config.rs +++ /dev/null @@ -1,216 +0,0 @@ -use crate::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, - Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, -}; - -use polkadot_sdk::{ - staging_xcm as xcm, staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor, *, -}; - -use frame_support::{ - parameter_types, - traits::{ConstU32, Contains, Everything, Nothing}, - weights::Weight, -}; -use frame_system::EnsureRoot; -use pallet_xcm::XcmPassthrough; -use polkadot_parachain_primitives::primitives::Sibling; -use polkadot_runtime_common::impls::ToAuthor; -use polkadot_sdk::{ - polkadot_sdk_frame::traits::Disabled, - staging_xcm_builder::{DenyRecursively, DenyThenTry}, -}; -use xcm::latest::prelude::*; -use xcm_builder::{ - AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, -}; -use xcm_executor::XcmExecutor; - -parameter_types! { - pub const RelayLocation: Location = Location::parent(); - pub const RelayNetwork: Option = None; - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - // For the real deployment, it is recommended to set `RelayNetwork` according to the relay chain - // and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`. - pub UniversalLocation: InteriorLocation = Parachain(ParachainInfo::parachain_id().into()).into(); -} - -/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used -/// when determining ownership of accounts for asset transacting and when attempting to use XCM -/// `Transact` in order to determine the dispatch Origin. -pub type LocationToAccountId = ( - // The parent (Relay-chain) origin converts to the parent `AccountId`. - ParentIsPreset, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = FungibleAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 Location into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - -/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, -/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can -/// biases the kind of local `Origin` it will become. -pub type XcmOriginToTransactDispatchOrigin = ( - // Sovereign account converter; this attempts to derive an `AccountId` from the origin location - // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for - // foreign chains who want to have a local sovereign account on this chain which they control. - SovereignSignedViaLocation, - // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when - // recognized. - RelayChainAsNative, - // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when - // recognized. - SiblingParachainAsNative, - // Native signed account converter; this just converts an `AccountId32` origin into a normal - // `RuntimeOrigin::Signed` origin of the same 32-byte value. - SignedAccountId32AsNative, - // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. - XcmPassthrough, -); - -parameter_types! { - // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; -} - -pub struct ParentOrParentsExecutivePlurality; -impl Contains for ParentOrParentsExecutivePlurality { - fn contains(location: &Location) -> bool { - matches!( - location.unpack(), - (1, []) - | ( - 1, - [Plurality { - id: BodyId::Executive, - .. - }] - ) - ) - } -} - -pub type Barrier = TrailingSetTopicAsId< - DenyThenTry< - DenyRecursively, - ( - TakeWeightCredit, - WithComputedOrigin< - ( - AllowTopLevelPaidExecutionFrom, - AllowExplicitUnpaidExecutionFrom, - // ^^^ Parent and its exec plurality get free execution - ), - UniversalLocation, - ConstU32<8>, - >, - ), - >, ->; - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type XcmEventEmitter = PolkadotXcm; - // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = NativeAsset; - type IsTeleporter = (); // Teleporting is disabled. - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = - UsingComponents>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); - type XcmRecorder = PolkadotXcm; -} - -/// Converts a local signed origin into an XCM location. Forms the basis for local origins -/// sending/executing XCMs. -pub type LocalOriginToLocation = SignedToAccountId32; - -/// The means for routing XCM messages which are not for local execution into the right message -/// queues. -pub type XcmRouter = WithUniqueTopic<( - // Two routers - use UMP to communicate with the relay chain: - cumulus_primitives_utility::ParentAsUmp, - // ..and XCMP to communicate with the sibling chains. - XcmpQueue, -)>; - -impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; - type XcmExecuteFilter = Nothing; - // ^ Disable dispatchable execute on the XCM pallet. - // Needs to be `Everything` for local testing. - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Nothing; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - // ^ Override for AdvertisedXcmVersion default - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - type AdminOrigin = EnsureRoot; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - // Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`. - type AuthorizedAliasConsideration = Disabled; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/genesis_config_presets.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/genesis_config_presets.rs deleted file mode 100644 index a17fa8c91..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/genesis_config_presets.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::{ - AccountId, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, PolkadotXcmConfig, - RuntimeGenesisConfig, SessionConfig, SessionKeys, SudoConfig, EXISTENTIAL_DEPOSIT, -}; - -use alloc::{vec, vec::Vec}; - -use polkadot_sdk::{staging_xcm as xcm, *}; - -use cumulus_primitives_core::ParaId; -use frame_support::build_struct_json_patch; -use parachains_common::AuraId; -use serde_json::Value; -use sp_genesis_builder::PresetId; -use sp_keyring::Sr25519Keyring; - -/// The default XCM version to set in genesis config. -const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -/// Parachain id used for genesis config presets of parachain template. -#[docify::export_content] -pub const PARACHAIN_ID: u32 = 1000; - -/// Generate the session keys from individual elements. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn template_session_keys(keys: AuraId) -> SessionKeys { - SessionKeys { aura: keys } -} - -fn testnet_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - root: AccountId, - id: ParaId, -) -> Value { - build_struct_json_patch!(RuntimeGenesisConfig { - balances: BalancesConfig { - balances: endowed_accounts - .iter() - .cloned() - .map(|k| (k, 1u128 << 60)) - .collect::>(), - }, - parachain_info: ParachainInfoConfig { parachain_id: id }, - collator_selection: CollatorSelectionConfig { - invulnerables: invulnerables - .iter() - .cloned() - .map(|(acc, _)| acc) - .collect::>(), - candidacy_bond: EXISTENTIAL_DEPOSIT * 16, - }, - session: SessionConfig { - keys: invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - template_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION) - }, - sudo: SudoConfig { key: Some(root) }, - }) -} - -fn local_testnet_genesis() -> Value { - testnet_genesis( - // initial collators. - vec![ - ( - Sr25519Keyring::Alice.to_account_id(), - Sr25519Keyring::Alice.public().into(), - ), - ( - Sr25519Keyring::Bob.to_account_id(), - Sr25519Keyring::Bob.public().into(), - ), - ], - Sr25519Keyring::well_known() - .map(|k| k.to_account_id()) - .collect(), - Sr25519Keyring::Alice.to_account_id(), - PARACHAIN_ID.into(), - ) -} - -fn development_config_genesis() -> Value { - testnet_genesis( - // initial collators. - vec![ - ( - Sr25519Keyring::Alice.to_account_id(), - Sr25519Keyring::Alice.public().into(), - ), - ( - Sr25519Keyring::Bob.to_account_id(), - Sr25519Keyring::Bob.public().into(), - ), - ], - Sr25519Keyring::well_known() - .map(|k| k.to_account_id()) - .collect(), - Sr25519Keyring::Alice.to_account_id(), - PARACHAIN_ID.into(), - ) -} - -/// Provides the JSON representation of predefined genesis config for given `id`. -pub fn get_preset(id: &PresetId) -> Option> { - let patch = match id.as_ref() { - sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => local_testnet_genesis(), - sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(), - _ => return None, - }; - Some( - serde_json::to_string(&patch) - .expect("serialization to json is expected to work. qed.") - .into_bytes(), - ) -} - -/// List of supported presets. -pub fn preset_names() -> Vec { - vec![ - PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), - PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), - ] -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs deleted file mode 100644 index 0d943404e..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs +++ /dev/null @@ -1,331 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -pub mod apis; -#[cfg(feature = "runtime-benchmarks")] -mod benchmarks; -pub mod configs; -mod genesis_config_presets; -mod weights; - -extern crate alloc; -use alloc::vec::Vec; -use smallvec::smallvec; - -use polkadot_sdk::{staging_parachain_info as parachain_info, *}; - -use sp_runtime::{ - generic, impl_opaque_keys, - traits::{BlakeTwo256, IdentifyAccount, Verify}, - MultiSignature, -}; - -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -use frame_support::weights::{ - constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, - WeightToFeePolynomial, -}; -pub use genesis_config_presets::PARACHAIN_ID; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; - -use weights::ExtrinsicBaseWeight; - -/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; - -/// Some way of identifying an account on the chain. We intentionally make it equivalent -/// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; - -/// Balance of an account. -pub type Balance = u128; - -/// Index of a transaction in the chain. -pub type Nonce = u32; - -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; - -/// An index to a block. -pub type BlockNumber = u32; - -/// The address format for describing accounts. -pub type Address = MultiAddress; - -/// Block header type as expected by this runtime. -pub type Header = generic::Header; - -/// Block type as expected by this runtime. -pub type Block = generic::Block; - -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; - -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; - -/// The extension to the basic transaction logic. -#[docify::export(template_signed_extra)] -pub type TxExtension = cumulus_pallet_weight_reclaim::StorageWeightReclaim< - Runtime, - ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, - frame_metadata_hash_extension::CheckMetadataHash, - ), ->; - -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; - -/// All migrations of the runtime, aside from the ones declared in the pallets. -/// -/// This can be a tuple of types, each implementing `OnRuntimeUpgrade`. -#[allow(unused_parens)] -type Migrations = (); - -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, - Migrations, ->; - -/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the -/// node's balance type. -/// -/// This should typically create a mapping between the following ranges: -/// - `[0, MAXIMUM_BLOCK_WEIGHT]` -/// - `[Balance::min, Balance::max]` -/// -/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: -/// - Setting it to `0` will essentially disable the weight fee. -/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. -pub struct WeightToFee; -impl WeightToFeePolynomial for WeightToFee { - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLI_UNIT: - // in our template, we map to 1/10 of that, or 1/10 MILLI_UNIT - let p = MILLI_UNIT / 10; - let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(p % q, q), - coeff_integer: p / q, - }] - } -} - -/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know -/// the specifics of the runtime. They can then be made to be agnostic over specific formats -/// of data like extrinsics, allowing for them to continue syncing the network through upgrades -/// to even the core data structures. -pub mod opaque { - use super::*; - pub use polkadot_sdk::sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - use polkadot_sdk::sp_runtime::{ - generic, - traits::{BlakeTwo256, Hash as HashT}, - }; - - /// Opaque block header type. - pub type Header = generic::Header; - /// Opaque block type. - pub type Block = generic::Block; - /// Opaque block identifier type. - pub type BlockId = generic::BlockId; - /// Opaque block hash type. - pub type Hash = ::Output; -} - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: alloc::borrow::Cow::Borrowed("parachain-template-runtime"), - impl_name: alloc::borrow::Cow::Borrowed("parachain-template-runtime"), - authoring_version: 1, - spec_version: 1, - impl_version: 0, - apis: apis::RUNTIME_API_VERSIONS, - transaction_version: 1, - system_version: 1, -}; - -#[docify::export] -mod block_times { - /// This determines the average expected block time that we are targeting. Blocks will be - /// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by - /// `pallet_timestamp` which is in turn picked up by `pallet_aura` to implement `fn - /// slot_duration()`. - /// - /// Change this to adjust the block time. - pub const MILLI_SECS_PER_BLOCK: u64 = 6000; - - // NOTE: Currently it is not possible to change the slot duration after the chain has started. - // Attempting to do so will brick block production. - pub const SLOT_DURATION: u64 = MILLI_SECS_PER_BLOCK; -} -pub use block_times::*; - -// Time is measured by number of blocks. -pub const MINUTES: BlockNumber = 60_000 / (MILLI_SECS_PER_BLOCK as BlockNumber); -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; - -// Unit = the base number of indivisible units for balances -pub const UNIT: Balance = 1_000_000_000_000; -pub const MILLI_UNIT: Balance = 1_000_000_000; -pub const MICRO_UNIT: Balance = 1_000_000; - -/// The existential deposit. Set to 1/10 of the Connected Relay Chain. -pub const EXISTENTIAL_DEPOSIT: Balance = MILLI_UNIT; - -/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is -/// used to limit the maximal weight of a single extrinsic. -const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); - -/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by -/// `Operational` extrinsics. -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); - -#[docify::export(max_block_weight)] -/// We allow for 2 seconds of compute with a 6 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), - cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, -); - -#[docify::export] -mod async_backing_params { - /// Maximum number of blocks simultaneously accepted by the Runtime, not yet included - /// into the relay chain. - pub(crate) const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; - /// How many parachain blocks are processed by the relay chain per parent. Limits the - /// number of blocks authored per slot. - pub(crate) const BLOCK_PROCESSING_VELOCITY: u32 = 1; - /// Relay chain slot duration, in milliseconds. - pub(crate) const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; -} -pub(crate) use async_backing_params::*; - -#[docify::export] -/// Aura consensus hook -type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, ->; - -/// The version information used to identify this runtime when compiled natively. -#[cfg(feature = "std")] -pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } -} - -// Create the runtime by composing the FRAME pallets that were previously configured. -#[frame_support::runtime] -mod runtime { - #[runtime::runtime] - #[runtime::derive( - RuntimeCall, - RuntimeEvent, - RuntimeError, - RuntimeOrigin, - RuntimeFreezeReason, - RuntimeHoldReason, - RuntimeSlashReason, - RuntimeLockId, - RuntimeTask, - RuntimeViewFunction - )] - pub struct Runtime; - - #[runtime::pallet_index(0)] - pub type System = frame_system; - #[runtime::pallet_index(1)] - pub type ParachainSystem = cumulus_pallet_parachain_system; - #[runtime::pallet_index(2)] - pub type Timestamp = pallet_timestamp; - #[runtime::pallet_index(3)] - pub type ParachainInfo = parachain_info; - #[runtime::pallet_index(4)] - pub type WeightReclaim = cumulus_pallet_weight_reclaim; - - // Monetary stuff. - #[runtime::pallet_index(10)] - pub type Balances = pallet_balances; - #[runtime::pallet_index(11)] - pub type TransactionPayment = pallet_transaction_payment; - - // Governance - #[runtime::pallet_index(15)] - pub type Sudo = pallet_sudo; - - // Collator support. The order of these 4 are important and shall not change. - #[runtime::pallet_index(20)] - pub type Authorship = pallet_authorship; - #[runtime::pallet_index(21)] - pub type CollatorSelection = pallet_collator_selection; - #[runtime::pallet_index(22)] - pub type Session = pallet_session; - #[runtime::pallet_index(23)] - pub type Aura = pallet_aura; - #[runtime::pallet_index(24)] - pub type AuraExt = cumulus_pallet_aura_ext; - - // XCM helpers. - #[runtime::pallet_index(30)] - pub type XcmpQueue = cumulus_pallet_xcmp_queue; - #[runtime::pallet_index(31)] - pub type PolkadotXcm = pallet_xcm; - #[runtime::pallet_index(32)] - pub type CumulusXcm = cumulus_pallet_xcm; - #[runtime::pallet_index(33)] - pub type MessageQueue = pallet_message_queue; - - // Template - #[runtime::pallet_index(50)] - pub type TemplatePallet = pallet_parachain_template; - - #[runtime::pallet_index(51)] - pub type Utility = pallet_utility; - - #[runtime::pallet_index(52)] - pub type CustomPallet = custom_pallet; -} - -#[docify::export(register_validate_block)] -cumulus_pallet_parachain_system::register_validate_block! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/block_weights.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/block_weights.rs deleted file mode 100644 index d38703407..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/block_weights.rs +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -pub mod constants { - use polkadot_sdk::*; - - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Importing a block with 0 Extrinsics. - pub const BlockExecutionWeight: Weight = - Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000), 0); - } - - #[cfg(test)] - mod test_weights { - use polkadot_sdk::*; - - use frame_support::weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::BlockExecutionWeight::get(); - - // At least 100 µs. - assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 100 µs." - ); - // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); - } - } -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/extrinsic_weights.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/extrinsic_weights.rs deleted file mode 100644 index 685a20af6..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -pub mod constants { - use polkadot_sdk::*; - - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Executing a NO-OP `System::remarks` Extrinsic. - pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000), 0); - } - - #[cfg(test)] - mod test_weights { - use polkadot_sdk::*; - - use frame_support::weights::constants; - - /// Checks that the weight exists and is sane. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::ExtrinsicBaseWeight::get(); - - // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); - // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); - } - } -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/mod.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/mod.rs deleted file mode 100644 index b473d49e2..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -//! Expose the auto generated weight files. - -pub mod block_weights; -pub mod extrinsic_weights; -pub mod paritydb_weights; -pub mod rocksdb_weights; - -pub use block_weights::constants::BlockExecutionWeight; -pub use extrinsic_weights::constants::ExtrinsicBaseWeight; -pub use rocksdb_weights::constants::RocksDbWeight; diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/paritydb_weights.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/paritydb_weights.rs deleted file mode 100644 index d97a2752b..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -pub mod constants { - use polkadot_sdk::*; - - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights - /// are available for brave runtime engineers who may want to try this out as default. - pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use polkadot_sdk::*; - - use super::constants::ParityDbWeight as W; - use frame_support::weights::constants; - - /// Checks that all weights exist and have sane values. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/rocksdb_weights.rs b/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/rocksdb_weights.rs deleted file mode 100644 index 2c7c73107..000000000 --- a/.snippets/code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,67 +0,0 @@ -// 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. - -pub mod constants { - use polkadot_sdk::*; - - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout - /// the runtime. - pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use polkadot_sdk::*; - - use super::constants::RocksDbWeight as W; - use frame_support::weights::constants; - - /// Checks that all weights exist and have sane values. - // NOTE: If this test fails but you are sure that the generated values are fine, - // you can delete it. - #[test] - fn sane() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp b/images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp similarity index 100% rename from images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp rename to images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp diff --git a/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp b/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp deleted file mode 100644 index 68454857a..000000000 Binary files a/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp and /dev/null differ diff --git a/llms-full.jsonl b/llms-full.jsonl index 4c48cef28..3f7016143 100644 --- a/llms-full.jsonl +++ b/llms-full.jsonl @@ -143,8 +143,8 @@ {"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 9, "depth": 2, "title": "Run Your Chain Locally", "anchor": "run-your-chain-locally", "start_char": 8968, "end_char": 9494, "estimated_token_count": 141, "token_estimator": "heuristic-v1", "text": "## Run Your Chain Locally\n\nNow that you've added the pallet to your runtime, you can launch your parachain locally to test the new functionality using the [Polkadot Omni Node](https://crates.io/crates/polkadot-omni-node){target=\\_blank}. For instructions on setting up the Polkadot Omni Node and [Polkadot Chain Spec Builder](https://crates.io/crates/staging-chain-spec-builder){target=\\_blank}, refer to the [Set Up a Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/){target=\\_blank} guide."} {"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 10, "depth": 3, "title": "Generate a Chain Specification", "anchor": "generate-a-chain-specification", "start_char": 9494, "end_char": 10049, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### Generate a Chain Specification\n\nCreate a new chain specification file with the updated runtime by running the following command from your project's root directory using the `chain-spec-builder` tool:\n\n```bash\nchain-spec-builder create -t development \\\n--relay-chain paseo \\\n--para-id 1000 \\\n--runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \\\nnamed-preset development\n```\n\nThis command generates a chain specification file, `chain_spec.json`, for your parachain with the updated runtime."} {"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 11, "depth": 3, "title": "Start the Parachain Node", "anchor": "start-the-parachain-node", "start_char": 10049, "end_char": 10333, "estimated_token_count": 59, "token_estimator": "heuristic-v1", "text": "### Start the Parachain Node\n\nLaunch the parachain using the Polkadot Omni Node with the generated chain specification by running the following command:\n\n```bash\npolkadot-omni-node --chain ./chain_spec.json --dev\n```\n\nVerify the node starts successfully and begins producing blocks."} -{"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 12, "depth": 3, "title": "Interact with the Pallet", "anchor": "interact-with-the-pallet", "start_char": 10333, "end_char": 11331, "estimated_token_count": 283, "token_estimator": "heuristic-v1", "text": "### Interact with the Pallet\n\nUse the Polkadot.js Apps interface to verify you can interact with the new pallet.\n\nTo interact with the pallet:\n\n1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\\_blank}.\n2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`.\n3. Go to the **Developer** > **Extrinsics** tab.\n4. In the **submit the following extrinsic** section, locate **utility** in the pallet dropdown.\n5. Verify you can see the available extrinsics, such as:\n - **`batch(calls)`**: Dispatch multiple calls in a single transaction.\n - **`batchAll(calls)`**: Dispatch multiple calls, stopping on the first error.\n - **`asDerivative(index, call)`**: Dispatch a call as a derivative account.\n\n ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp)\n\nYou can now test the pallet's functionality by submitting transactions through the interface."} -{"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 13, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11331, "end_char": 11924, "estimated_token_count": 151, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Add Multiple Pallet Instances__\n\n ---\n\n Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime.\n\n [:octicons-arrow-right-24: Get Started](/parachains/customize-runtime/add-pallet-instances/)\n\n- Guide __Make a Custom Pallet__\n\n ---\n\n Learn how to create custom pallets using FRAME.\n\n [:octicons-arrow-right-24: Get Started](/parachains/customize-runtime/pallet-development/create-a-pallet/)\n\n
"} +{"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 12, "depth": 3, "title": "Interact with the Pallet", "anchor": "interact-with-the-pallet", "start_char": 10333, "end_char": 11300, "estimated_token_count": 273, "token_estimator": "heuristic-v1", "text": "### Interact with the Pallet\n\nUse the Polkadot.js Apps interface to verify you can interact with the new pallet.\n\nTo interact with the pallet:\n\n1. Navigate to [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\\_blank}.\n2. Ensure you're connected to your local node at `ws://127.0.0.1:9944`.\n3. Go to the **Developer** > **Extrinsics** tab.\n4. In the **submit the following extrinsic** section, locate **utility** in the pallet dropdown.\n5. Verify you can see the available extrinsics, such as:\n - **`batch(calls)`**: Dispatch multiple calls in a single transaction.\n - **`batchAll(calls)`**: Dispatch multiple calls, stopping on the first error.\n - **`asDerivative(index, call)`**: Dispatch a call as a derivative account.\n\n ![](/images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp)\n\nYou can now test the pallet's functionality by submitting transactions through the interface."} +{"page_id": "parachains-customize-runtime-add-existing-pallets", "page_title": "Add an Existing Pallet to the Runtime", "index": 13, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11300, "end_char": 11893, "estimated_token_count": 151, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Add Multiple Pallet Instances__\n\n ---\n\n Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime.\n\n [:octicons-arrow-right-24: Get Started](/parachains/customize-runtime/add-pallet-instances/)\n\n- Guide __Make a Custom Pallet__\n\n ---\n\n Learn how to create custom pallets using FRAME.\n\n [:octicons-arrow-right-24: Get Started](/parachains/customize-runtime/pallet-development/create-a-pallet/)\n\n
"} {"page_id": "parachains-customize-runtime-add-pallet-instances", "page_title": "Add Multiple Pallet Instances", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 33, "end_char": 1429, "estimated_token_count": 257, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nThe [Polkadot SDK Parachain Template](https://github.com/paritytech/polkadot-sdk-parachain-template){target=\\_blank} provides a solid foundation for building custom parachains. While most pallets are typically included as single instances within a runtime, some scenarios benefit from running multiple instances of the same pallet with different configurations. This approach lets you reuse pallet logic without reimplementing it, enabling diverse functionality from a single codebase.\n\nFor example, you could create multiple governance councils with different voting rules, or several token systems with distinct parameters. The Polkadot SDK makes this possible through instantiable pallets, which allow multiple independent instances of the same pallet to coexist within a runtime.\n\nThis guide demonstrates how to add and configure multiple instances of a pallet to your runtime using [`pallet-collective`](https://paritytech.github.io/polkadot-sdk/master/pallet_collective/index.html){target=\\_blank} as a practical example. The same process applies to other instantiable pallets.\n\nIn this guide, you'll learn how to:\n\n- Identify instantiable pallets and understand their structure.\n- Configure multiple instances of the same pallet with unique parameters.\n- Register multiple pallet instances in your runtime.\n- Run your parachain locally to test multiple pallet instances."} {"page_id": "parachains-customize-runtime-add-pallet-instances", "page_title": "Add Multiple Pallet Instances", "index": 1, "depth": 2, "title": "Check Prerequisites", "anchor": "check-prerequisites", "start_char": 1429, "end_char": 1724, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "## Check Prerequisites\n\nBefore you begin, ensure you have:\n\n- A working [Polkadot SDK development environment](/parachains/launch-a-parachain/choose-a-template){target=\\_blank}.\n- Basic understanding of [adding pallets to a runtime](/parachains/customize-runtime/add-a-pallet){target=\\_blank}."} {"page_id": "parachains-customize-runtime-add-pallet-instances", "page_title": "Add Multiple Pallet Instances", "index": 2, "depth": 2, "title": "Understanding Instantiable Pallets", "anchor": "understanding-instantiable-pallets", "start_char": 1724, "end_char": 2025, "estimated_token_count": 46, "token_estimator": "heuristic-v1", "text": "## Understanding Instantiable Pallets\n\nNot all pallets support multiple instances. Instantiable pallets are specifically designed to allow multiple independent copies within the same runtime. These pallets include an additional generic parameter `I` that creates a unique identity for each instance."} @@ -182,12 +182,6 @@ {"page_id": "parachains-customize-runtime-add-smart-contract-functionality", "page_title": "Add Smart Contract Functionality", "index": 13, "depth": 2, "title": "pallet-contracts (Legacy)", "anchor": "pallet-contracts-legacy", "start_char": 5720, "end_char": 6051, "estimated_token_count": 81, "token_estimator": "heuristic-v1", "text": "## pallet-contracts (Legacy)\n\n[`pallet-contracts`](https://docs.rs/pallet-contracts/latest/pallet_contracts/index.html#contracts-pallet){target=\\_blank} is the original Wasm-based smart contract pallet for Polkadot SDK chains. While still functional, it's considered legacy as development efforts have shifted to `pallet-revive`."} {"page_id": "parachains-customize-runtime-add-smart-contract-functionality", "page_title": "Add Smart Contract Functionality", "index": 14, "depth": 3, "title": "Implementation Example", "anchor": "implementation-example", "start_char": 6051, "end_char": 6304, "estimated_token_count": 59, "token_estimator": "heuristic-v1", "text": "### Implementation Example\n\nFor reference, Astar's implementation of [`pallet-contracts`](https://github.com/AstarNetwork/Astar/blob/b6f7a408d31377130c3713ed52941a06b5436402/runtime/astar/src/lib.rs#L693){target=\\_blank} demonstrates production usage."} {"page_id": "parachains-customize-runtime-add-smart-contract-functionality", "page_title": "Add Smart Contract Functionality", "index": 15, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 6304, "end_char": 6655, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Add a Pallet to the Runtime__\n\n ---\n\n Learn the step-by-step process for integrating Polkadot SDK pallets into your blockchain's runtime.\n\n [:octicons-arrow-right-24: Get Started](/parachains/customize-runtime/add-existing-pallets/)\n\n
"} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 30, "end_char": 866, "estimated_token_count": 192, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nIn previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain.\n\nThis tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction."} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 1, "depth": 2, "title": "Add the Pallets as Dependencies", "anchor": "add-the-pallets-as-dependencies", "start_char": 866, "end_char": 8510, "estimated_token_count": 1856, "token_estimator": "heuristic-v1", "text": "## Add the Pallets as Dependencies\n\nFirst, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps:\n\n1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line:\n\n ```toml hl_lines=\"4\" title=\"runtime/Cargo.toml\"\n [dependencies]\n ...\n polkadot-sdk = { workspace = true, features = [\n \"pallet-utility\",\n ...\n ], default-features = false }\n ```\n\n2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line:\n\n ```toml hl_lines=\"3\" title=\"Cargo.toml\"\n [dependencies]\n ...\n custom-pallet = { path = \"../pallets/custom-pallet\", default-features = false }\n ```\n\n3. In the `[features]` section, add the custom pallet to the `std` feature list:\n\n ```toml hl_lines=\"5\" title=\"Cargo.toml\"\n [features]\n default = [\"std\"]\n std = [\n ...\n \"custom-pallet/std\",\n ...\n ]\n ```\n\n3. Save the changes and close the `Cargo.toml` file.\n\n Once you have saved your file, it should look like the following:\n\n ???- code \"runtime/Cargo.toml\"\n \n ```rust title=\"runtime/Cargo.toml\"\n [package]\n name = \"parachain-template-runtime\"\n description = \"A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk.\"\n version = \"0.1.0\"\n license = \"Unlicense\"\n authors.workspace = true\n homepage.workspace = true\n repository.workspace = true\n edition.workspace = true\n publish = false\n\n [package.metadata.docs.rs]\n targets = [\"x86_64-unknown-linux-gnu\"]\n\n [build-dependencies]\n docify = { workspace = true }\n substrate-wasm-builder = { optional = true, workspace = true, default-features = true }\n\n [dependencies]\n codec = { features = [\"derive\"], workspace = true }\n cumulus-pallet-parachain-system.workspace = true\n docify = { workspace = true }\n hex-literal = { optional = true, workspace = true, default-features = true }\n log = { workspace = true }\n pallet-parachain-template = { path = \"../pallets/template\", default-features = false }\n polkadot-sdk = { workspace = true, features = [\n \"pallet-utility\",\n \"cumulus-pallet-aura-ext\",\n \"cumulus-pallet-session-benchmarking\",\n \"cumulus-pallet-weight-reclaim\",\n \"cumulus-pallet-xcm\",\n \"cumulus-pallet-xcmp-queue\",\n \"cumulus-primitives-aura\",\n \"cumulus-primitives-core\",\n \"cumulus-primitives-utility\",\n \"pallet-aura\",\n \"pallet-authorship\",\n \"pallet-balances\",\n \"pallet-collator-selection\",\n \"pallet-message-queue\",\n \"pallet-session\",\n \"pallet-sudo\",\n \"pallet-timestamp\",\n \"pallet-transaction-payment\",\n \"pallet-transaction-payment-rpc-runtime-api\",\n \"pallet-xcm\",\n \"parachains-common\",\n \"polkadot-parachain-primitives\",\n \"polkadot-runtime-common\",\n \"runtime\",\n \"staging-parachain-info\",\n \"staging-xcm\",\n \"staging-xcm-builder\",\n \"staging-xcm-executor\",\n ], default-features = false }\n scale-info = { features = [\"derive\"], workspace = true }\n serde_json = { workspace = true, default-features = false, features = [\n \"alloc\",\n ] }\n smallvec = { workspace = true, default-features = true }\n\n custom-pallet = { path = \"../pallets/custom-pallet\", default-features = false }\n\n [features]\n default = [\"std\"]\n std = [\n \"codec/std\",\n \"cumulus-pallet-parachain-system/std\",\n \"log/std\",\n \"pallet-parachain-template/std\",\n \"polkadot-sdk/std\",\n \"scale-info/std\",\n \"serde_json/std\",\n \"substrate-wasm-builder\",\n \"custom-pallet/std\",\n ]\n\n runtime-benchmarks = [\n \"cumulus-pallet-parachain-system/runtime-benchmarks\",\n \"hex-literal\",\n \"pallet-parachain-template/runtime-benchmarks\",\n \"polkadot-sdk/runtime-benchmarks\",\n ]\n\n try-runtime = [\n \"cumulus-pallet-parachain-system/try-runtime\",\n \"pallet-parachain-template/try-runtime\",\n \"polkadot-sdk/try-runtime\",\n ]\n\n # Enable the metadata hash generation.\n #\n # This is hidden behind a feature because it increases the compile time.\n # The wasm binary needs to be compiled twice, once to fetch the metadata,\n # generate the metadata hash and then a second time with the\n # `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash`\n # extension.\n metadata-hash = [\"substrate-wasm-builder/metadata-hash\"]\n\n # A convenience feature for enabling things when doing a build\n # for an on-chain release.\n on-chain-release-build = [\"metadata-hash\"]\n\n ```\n\nUpdate your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps:\n\n1. Open the `./Cargo.toml` file and locate the `[workspace]` section. \n \n Make sure the `custom-pallet` is a member of the workspace:\n\n ```toml hl_lines=\"4\" title=\"Cargo.toml\"\n [workspace]\n default-members = [\"pallets/template\", \"runtime\"]\n members = [\n \"node\", \"pallets/custom-pallet\",\n \"pallets/template\",\n \"runtime\",\n ]\n ```\n\n???- code \"./Cargo.toml\"\n\n ```rust title=\"./Cargo.toml\"\n [workspace.package]\n license = \"MIT-0\"\n authors = [\"Parity Technologies \"]\n homepage = \"https://paritytech.github.io/polkadot-sdk/\"\n repository = \"https://github.com/paritytech/polkadot-sdk-parachain-template.git\"\n edition = \"2021\"\n\n [workspace]\n default-members = [\"pallets/template\", \"runtime\"]\n members = [\n \"node\", \"pallets/custom-pallet\",\n \"pallets/template\",\n \"runtime\",\n ]\n resolver = \"2\"\n\n [workspace.dependencies]\n parachain-template-runtime = { path = \"./runtime\", default-features = false }\n pallet-parachain-template = { path = \"./pallets/template\", default-features = false }\n clap = { version = \"4.5.13\" }\n color-print = { version = \"0.3.4\" }\n docify = { version = \"0.2.9\" }\n futures = { version = \"0.3.31\" }\n jsonrpsee = { version = \"0.24.3\" }\n log = { version = \"0.4.22\", default-features = false }\n polkadot-sdk = { version = \"2503.0.1\", default-features = false }\n prometheus-endpoint = { version = \"0.17.2\", default-features = false, package = \"substrate-prometheus-endpoint\" }\n serde = { version = \"1.0.214\", default-features = false }\n codec = { version = \"3.7.4\", default-features = false, package = \"parity-scale-codec\" }\n cumulus-pallet-parachain-system = { version = \"0.20.0\", default-features = false }\n hex-literal = { version = \"0.4.1\", default-features = false }\n scale-info = { version = \"2.11.6\", default-features = false }\n serde_json = { version = \"1.0.132\", default-features = false }\n smallvec = { version = \"1.11.0\", default-features = false }\n substrate-wasm-builder = { version = \"26.0.1\", default-features = false }\n frame = { version = \"0.9.1\", default-features = false, package = \"polkadot-sdk-frame\" }\n\n [profile.release]\n opt-level = 3\n panic = \"unwind\"\n\n [profile.production]\n codegen-units = 1\n inherits = \"release\"\n lto = true\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 2, "depth": 3, "title": "Update the Runtime Configuration", "anchor": "update-the-runtime-configuration", "start_char": 8510, "end_char": 10415, "estimated_token_count": 406, "token_estimator": "heuristic-v1", "text": "### Update the Runtime Configuration\n\nConfigure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets:\n\n1. Add the `OriginCaller` import:\n\n ```rust title=\"mod.rs\" hl_lines=\"8\"\n // Local module imports\n use super::OriginCaller;\n ...\n ```\n\n2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file:\n\n ```rust title=\"mod.rs\" hl_lines=\"8-25\"\n ...\n /// Configure the pallet template in pallets/template.\n impl pallet_parachain_template::Config for Runtime {\n type RuntimeEvent = RuntimeEvent;\n type WeightInfo = pallet_parachain_template::weights::SubstrateWeight;\n }\n\n // Configure utility pallet.\n impl pallet_utility::Config for Runtime {\n type RuntimeEvent = RuntimeEvent;\n type RuntimeCall = RuntimeCall;\n type PalletsOrigin = OriginCaller;\n type WeightInfo = pallet_utility::weights::SubstrateWeight;\n }\n // Define counter max value runtime constant.\n parameter_types! {\n pub const CounterMaxValue: u32 = 500;\n }\n\n // Configure custom pallet.\n impl custom_pallet::Config for Runtime {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = CounterMaxValue;\n }\n ```\n\n3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets:\n\n ```rust hl_lines=\"9-14\" title=\"lib.rs\"\n #[frame_support::runtime]\n mod runtime {\n #[runtime::runtime]\n #[runtime::derive(\n ...\n )]\n pub struct Runtime;\n #[runtime::pallet_index(51)]\n pub type Utility = pallet_utility;\n\n #[runtime::pallet_index(52)]\n pub type CustomPallet = custom_pallet;\n }\n ```"} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 3, "depth": 2, "title": "Recompile the Runtime", "anchor": "recompile-the-runtime", "start_char": 10415, "end_char": 10864, "estimated_token_count": 89, "token_estimator": "heuristic-v1", "text": "## Recompile the Runtime\n\nAfter adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory):\n\n```bash\ncargo build --release\n```\n\nThis command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment."} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 4, "depth": 2, "title": "Run Your Chain Locally", "anchor": "run-your-chain-locally", "start_char": 10864, "end_char": 12339, "estimated_token_count": 365, "token_estimator": "heuristic-v1", "text": "## Run Your Chain Locally\n\nLaunch your parachain locally and start producing blocks:\n\n!!!tip\n Generated chain TestNet specifications include development accounts \"Alice\" and \"Bob.\" These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\\_blank} to view the development accounts for your chain.\n\n1. Create a new chain specification file with the updated runtime:\n\n ```bash\n chain-spec-builder create -t development \\\n --relay-chain paseo \\\n --para-id 1000 \\\n --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \\\n named-preset development\n ```\n\n2. Start the omni node with the generated chain specification:\n\n ```bash\n polkadot-omni-node --chain ./chain_spec.json --dev\n ```\n\n3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets:\n\n - Utility pallet\n\n ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp)\n \n\n - Custom pallet\n\n ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp)"} -{"page_id": "parachains-customize-runtime-pallet-development-add-pallet-to-runtime", "page_title": "Add Pallets to the Runtime", "index": 5, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 12339, "end_char": 13091, "estimated_token_count": 183, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Tutorial __Deploy on Paseo TestNet__\n\n ---\n\n Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment.\n\n [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/)\n\n- Tutorial __Pallet Benchmarking (Optional)__\n\n ---\n\n Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance.\n\n [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/)\n\n
"} {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 16, "end_char": 1205, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nBenchmarking is a critical component of developing efficient and secure blockchain runtimes. In the Polkadot ecosystem, accurately benchmarking your custom pallets ensures that each extrinsic has a precise [weight](/reference/glossary/#weight){target=\\_blank}, representing its computational and storage demands. This process is vital for maintaining the blockchain's performance and preventing potential vulnerabilities, such as Denial of Service (DoS) attacks.\n\nThe Polkadot SDK leverages the [FRAME](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\\_blank} benchmarking framework, offering tools to measure and assign weights to extrinsics. These weights help determine the maximum number of transactions or system-level calls processed within a block. This guide covers how to use FRAME's [benchmarking framework](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\\_blank}, from setting up your environment to writing and running benchmarks for your custom pallets. You'll understand how to generate accurate weights by the end, ensuring your runtime remains performant and secure."} {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 1, "depth": 2, "title": "The Case for Benchmarking", "anchor": "the-case-for-benchmarking", "start_char": 1205, "end_char": 1999, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "## The Case for Benchmarking\n\nBenchmarking helps validate that the required execution time for different functions is within reasonable boundaries to ensure your blockchain runtime can handle transactions efficiently and securely. By accurately measuring the weight of each extrinsic, you can prevent service interruptions caused by computationally intensive calls that exceed block time limits. Without benchmarking, runtime performance could be vulnerable to DoS attacks, where malicious users exploit functions with unoptimized weights.\n\nBenchmarking also ensures predictable transaction fees. Weights derived from benchmark tests accurately reflect the resource usage of function calls, allowing fair fee calculation. This approach discourages abuse while maintaining network reliability."} {"page_id": "parachains-customize-runtime-pallet-development-benchmark-pallet", "page_title": "Benchmarking FRAME Pallets", "index": 2, "depth": 3, "title": "Benchmarking and Weight", "anchor": "benchmarking-and-weight", "start_char": 1999, "end_char": 3665, "estimated_token_count": 321, "token_estimator": "heuristic-v1", "text": "### Benchmarking and Weight \n\nIn Polkadot SDK-based chains, weight quantifies the computational effort needed to process transactions. This weight includes factors such as:\n\n- Computational complexity.\n- Storage complexity (proof size).\n- Database reads and writes.\n- Hardware specifications.\n\nBenchmarking uses real-world testing to simulate worst-case scenarios for extrinsics. The framework generates a linear model for weight calculation by running multiple iterations with varied parameters. These worst-case weights ensure blocks remain within execution limits, enabling the runtime to maintain throughput under varying loads. Excess fees can be refunded if a call uses fewer resources than expected, offering users a fair cost model.\n \nBecause weight is a generic unit of measurement based on computation time for a specific physical machine, the weight of any function can change based on the specifications of hardware used for benchmarking. By modeling the expected weight of each runtime function, the blockchain can calculate the number of transactions or system-level calls it can execute within a certain period.\n\nWithin FRAME, each function call that is dispatched must have a `#[pallet::weight]` annotation that can return the expected weight for the worst-case scenario execution of that function given its inputs:\n\n```rust hl_lines=\"2\"\n#[pallet::call_index(0)]\n#[pallet::weight(T::WeightInfo::do_something())]\npub fn do_something(origin: OriginFor) -> DispatchResultWithPostInfo { Ok(()) }\n```\n\nThe `WeightInfo` file is automatically generated during benchmarking. Based on these tests, this file provides accurate weights for each extrinsic."} @@ -236,13 +230,27 @@ {"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 10, "depth": 2, "title": "Verify Mock Compilation", "anchor": "verify-mock-compilation", "start_char": 7931, "end_char": 10853, "estimated_token_count": 564, "token_estimator": "heuristic-v1", "text": "## Verify Mock Compilation\n\nBefore proceeding to write tests, ensure your mock runtime compiles correctly:\n\n```bash\ncargo test --package pallet-custom --lib\n```\n\nThis command compiles the test code (including the mock and genesis configuration) without running tests yet. Address any compilation errors before continuing.\n\n??? code \"Complete mock runtime script\"\n\n Here's the complete `mock.rs` file for reference:\n\n ```rust title=\"src/mock.rs\"\n use crate as pallet_custom;\n use frame::{\n deps::{\n frame_support::{ derive_impl, traits::ConstU32 },\n sp_io,\n sp_runtime::{ traits::IdentityLookup, BuildStorage },\n },\n prelude::*,\n };\n\n type Block = frame_system::mocking::MockBlock;\n\n // Configure a mock runtime to test the pallet.\n frame::deps::frame_support::construct_runtime!(\n pub enum Test\n {\n System: frame_system,\n CustomPallet: pallet_custom,\n }\n );\n\n #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]\n impl frame_system::Config for Test {\n type Block = Block;\n type AccountId = u64;\n type Lookup = IdentityLookup;\n }\n\n impl pallet_custom::Config for Test {\n type RuntimeEvent = RuntimeEvent;\n type CounterMaxValue = ConstU32<1000>;\n }\n\n // Build genesis storage according to the mock runtime.\n pub fn new_test_ext() -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: 0,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with a specific initial counter value\n pub fn new_test_ext_with_counter(initial_value: u32) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: vec![],\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n\n // Helper function to create a test externalities with initial user interactions\n pub fn new_test_ext_with_interactions(\n initial_value: u32,\n interactions: Vec<(u64, u32)>\n ) -> sp_io::TestExternalities {\n let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap();\n\n (pallet_custom::GenesisConfig:: {\n initial_counter_value: initial_value,\n initial_user_interactions: interactions,\n })\n .assimilate_storage(&mut t)\n .unwrap();\n\n t.into()\n }\n ```"} {"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 11, "depth": 2, "title": "Key Takeaways", "anchor": "key-takeaways", "start_char": 10853, "end_char": 11416, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "## Key Takeaways\n\nYou've successfully created a mock runtime with a genesis configuration for your custom pallet. You can now:\n\n- Test your pallet without a full runtime.\n- Set initial blockchain state for different test scenarios.\n- Create different genesis setups for various testing needs.\n- Use this minimal setup to test all pallet functionality.\n\nThe mock runtime with a genesis configuration is essential for test-driven development, enabling you to verify logic under different initial conditions before integrating it into the actual parachain runtime."} {"page_id": "parachains-customize-runtime-pallet-development-mock-runtime", "page_title": "Mock Your Runtime", "index": 12, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 11416, "end_char": 11766, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Pallet Unit Testing__\n\n ---\n\n Learn to write comprehensive unit tests for your pallet using the mock runtime you just created.\n\n [:octicons-arrow-right-24: Continue](/parachains/customize-runtime/pallet-development/pallet-testing/)\n\n
"} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 18, "end_char": 672, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nUnit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries.\n\nTo begin unit testing, you must first set up a mock runtime that simulates blockchain behavior, incorporating the necessary pallets. For a deeper understanding, consult the [Mock Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/){target=\\_blank} guide."} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 1, "depth": 2, "title": "Writing Unit Tests", "anchor": "writing-unit-tests", "start_char": 672, "end_char": 2195, "estimated_token_count": 285, "token_estimator": "heuristic-v1", "text": "## Writing Unit Tests\n\nOnce the mock runtime is in place, the next step is to write unit tests that evaluate the functionality of your pallet. Unit tests allow you to test specific pallet features in isolation, ensuring that each function behaves correctly under various conditions. These tests typically reside in your pallet module's `test.rs` file.\n\nUnit tests in the Polkadot SDK use the Rust testing framework, and the mock runtime you've defined earlier will serve as the test environment. Below are the typical steps involved in writing unit tests for a pallet.\n\nThe tests confirm that:\n\n- **Pallets initialize correctly**: At the start of each test, the system should initialize with block number 0, and the pallets should be in their default states.\n- **Pallets modify each other's state**: The second test shows how one pallet can trigger changes in another pallet's internal state, confirming proper cross-pallet interactions.\n- **State transitions between blocks are seamless**: By simulating block transitions, the tests validate that the runtime responds correctly to changes in the block number.\n\nTesting pallet interactions within the runtime is critical for ensuring the blockchain behaves as expected under real-world conditions. Writing integration tests allows validation of how pallets function together, preventing issues that might arise when the system is fully assembled.\n\nThis approach provides a comprehensive view of the runtime's functionality, ensuring the blockchain is stable and reliable."} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 2, "depth": 3, "title": "Test Initialization", "anchor": "test-initialization", "start_char": 2195, "end_char": 2507, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### Test Initialization\n\nEach test starts by initializing the runtime environment, typically using the `new_test_ext()` function, which sets up the mock storage and environment.\n\n```rust\n#[test]\nfn test_pallet_functionality() {\n new_test_ext().execute_with(|| {\n // Test logic goes here\n });\n}\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 3, "depth": 3, "title": "Function Call Testing", "anchor": "function-call-testing", "start_char": 2507, "end_char": 3280, "estimated_token_count": 167, "token_estimator": "heuristic-v1", "text": "### Function Call Testing\n\nCall the pallet's extrinsics or functions to simulate user interaction or internal logic. Use the `assert_ok!` macro to check for successful execution and `assert_err!` to verify that errors are correctly handled.\n\n```rust\n#[test]\nfn it_works_for_valid_input() {\n new_test_ext().execute_with(|| {\n // Call an extrinsic or function\n assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param));\n });\n}\n\n#[test]\nfn it_fails_for_invalid_input() {\n new_test_ext().execute_with(|| {\n // Call an extrinsic with invalid input and expect an error\n assert_err!(\n TemplateModule::some_function(Origin::signed(1), invalid_param),\n Error::::InvalidInput\n );\n });\n}\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 4, "depth": 3, "title": "Storage Testing", "anchor": "storage-testing", "start_char": 3280, "end_char": 4129, "estimated_token_count": 190, "token_estimator": "heuristic-v1", "text": "### Storage Testing\n\nAfter calling a function or extrinsic in your pallet, it's essential to verify that the state changes in the pallet's storage match the expected behavior to ensure data is updated correctly based on the actions taken.\n\nThe following example shows how to test the storage behavior before and after the function call:\n\n```rust\n#[test]\nfn test_storage_update_on_extrinsic_call() {\n new_test_ext().execute_with(|| {\n // Check the initial storage state (before the call)\n assert_eq!(Something::::get(), None);\n\n // Dispatch a signed extrinsic, which modifies storage\n assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42));\n\n // Validate that the storage has been updated as expected (after the call)\n assert_eq!(Something::::get(), Some(42));\n });\n}\n\n```"} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 5, "depth": 3, "title": "Event Testing", "anchor": "event-testing", "start_char": 4129, "end_char": 6150, "estimated_token_count": 519, "token_estimator": "heuristic-v1", "text": "### Event Testing\n\nIt's also crucial to test the events that your pallet emits during execution. By default, events generated in a pallet using the [`#generate_deposit`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\\_blank} macro are stored under the system's event storage key (system/events) as [`EventRecord`](https://paritytech.github.io/polkadot-sdk/master/frame_system/struct.EventRecord.html){target=\\_blank} entries. These can be accessed using [`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\\_blank} or verified with specific helper methods provided by the system pallet, such as [`assert_has_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_has_event){target=\\_blank} and [`assert_last_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\\_blank}.\n\nHere's an example of testing events in a mock runtime:\n\n```rust\n#[test]\nfn it_emits_events_on_success() {\n new_test_ext().execute_with(|| {\n // Call an extrinsic or function\n assert_ok!(TemplateModule::some_function(Origin::signed(1), valid_param));\n\n // Verify that the expected event was emitted\n assert!(System::events().iter().any(|record| {\n record.event == Event::TemplateModule(TemplateEvent::SomeEvent)\n }));\n });\n}\n```\n\nSome key considerations are:\n\n- **Block number**: Events are not emitted on the genesis block, so you need to set the block number using [`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\\_blank} to ensure events are triggered.\n- **Converting events**: Use `.into()` when instantiating your pallet's event to convert it into a generic event type, as required by the system's event storage."} -{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Testing", "index": 6, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 6150, "end_char": 6892, "estimated_token_count": 211, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n- Dive into the full implementation of the [`mock.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/mock.rs){target=\\_blank} and [`test.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/tests.rs){target=\\_blank} files in the [Solochain Template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/solochain){target=_blank}.\n\n
\n\n- Guide __Benchmarking__\n\n ---\n\n Explore methods to measure the performance and execution cost of your pallet.\n\n [:octicons-arrow-right-24: Reference](/develop/parachains/testing/benchmarking)\n\n
"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 23, "end_char": 686, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nUnit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. With your mock runtime in place from the [previous guide](/parachains/customize-runtime/pallet-development/mock-runtime/), you can now write comprehensive tests that verify your pallet's behavior in isolation.\n\nIn this guide, you'll learn how to:\n\n- Structure test modules effectively.\n- Test dispatchable functions.\n- Verify storage changes.\n- Check event emission.\n- Test error conditions.\n- Use genesis configurations in tests."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 686, "end_char": 1149, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you:\n\n- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide.\n- Completed the [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) guide.\n- Configured custom counter pallet with mock runtime in `pallets/pallet-custom`.\n- Understood the basics of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 2, "depth": 2, "title": "Understanding FRAME Testing Tools", "anchor": "understanding-frame-testing-tools", "start_char": 1149, "end_char": 1389, "estimated_token_count": 51, "token_estimator": "heuristic-v1", "text": "## Understanding FRAME Testing Tools\n\n[FRAME](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\\_blank} provides specialized testing macros and utilities that make pallet testing more efficient:"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 3, "depth": 3, "title": "Assertion Macros", "anchor": "assertion-macros", "start_char": 1389, "end_char": 2134, "estimated_token_count": 203, "token_estimator": "heuristic-v1", "text": "### Assertion Macros\n\n- **[`assert_ok!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_ok.html){target=\\_blank}** - Asserts that a dispatchable call succeeds.\n- **[`assert_noop!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_noop.html){target=\\_blank}** - Asserts that a call fails without changing state (no operation).\n- **[`assert_eq!`](https://doc.rust-lang.org/std/macro.assert_eq.html){target=\\_blank}** - Standard Rust equality assertion.\n\n!!!info \"`assert_noop!` Explained\"\n Use `assert_noop!` to ensure the operation fails without any state changes. This is critical for testing error conditions - it verifies both that the error occurs AND that no storage was modified."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 4, "depth": 3, "title": "System Pallet Test Helpers", "anchor": "system-pallet-test-helpers", "start_char": 2134, "end_char": 3130, "estimated_token_count": 279, "token_estimator": "heuristic-v1", "text": "### System Pallet Test Helpers\n\nThe [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\\_blank} pallet provides useful methods for testing:\n\n- **[`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\\_blank}** - Returns all events emitted during the test.\n- **[`System::assert_last_event()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\\_blank}** - Asserts the last event matches expectations.\n- **[`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\\_blank}** - Sets the current block number.\n\n!!!info \"Events and Block Number\"\n Events are not emitted on block 0 (genesis block). If you need to test events, ensure you set the block number to at least 1 using `System::set_block_number(1)`."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 5, "depth": 3, "title": "Origin Types", "anchor": "origin-types", "start_char": 3130, "end_char": 3921, "estimated_token_count": 230, "token_estimator": "heuristic-v1", "text": "### Origin Types\n\n- **[`RuntimeOrigin::root()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Root){target=\\_blank}** - Root/sudo origin for privileged operations.\n- **[`RuntimeOrigin::signed(account)`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Signed){target=\\_blank}** - Signed origin from a specific account.\n- **[`RuntimeOrigin::none()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.None){target=\\_blank}** - No origin (typically fails for most operations).\n\nLearn more about origins in the [FRAME Origin reference document](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_origin/index.html){target=\\_blank}."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 6, "depth": 2, "title": "Create the Tests Module", "anchor": "create-the-tests-module", "start_char": 3921, "end_char": 4528, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Create the Tests Module\n\nCreate a new file for your tests within the pallet directory:\n\n1. Navigate to your pallet directory:\n\n ```bash\n cd pallets/pallet-custom/src\n ```\n\n2. Create a new file named `tests.rs`:\n\n ```bash\n touch tests.rs\n ```\n\n3. Open `src/lib.rs` and add the tests module declaration after the mock module:\n\n ```rust title=\"src/lib.rs\"\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[cfg(test)]\n mod mock;\n\n #[cfg(test)]\n mod tests;\n\n #[frame::pallet]\n pub mod pallet {\n // ... existing pallet code\n }\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 7, "depth": 2, "title": "Set Up the Test Module", "anchor": "set-up-the-test-module", "start_char": 4528, "end_char": 9206, "estimated_token_count": 1011, "token_estimator": "heuristic-v1", "text": "## Set Up the Test Module\n\nOpen `src/tests.rs` and add the basic structure with necessary imports:\n\n```rust\nuse crate::{mock::*, Error, Event};\nuse frame::deps::frame_support::{assert_noop, assert_ok};\nuse frame::deps::sp_runtime::DispatchError;\n```\n\nThis setup imports:\n\n- The mock runtime and test utilities from `mock.rs`\n- Your pallet's `Error` and `Event` types\n- FRAME's assertion macros via `frame::deps`\n- `DispatchError` for testing origin checks\n\n???+ code \"Complete Pallet Code Reference\"\n Here's the complete pallet code that you'll be testing throughout this guide:\n\n ```rust\n #![cfg_attr(not(feature = \"std\"), no_std)]\n\n pub use pallet::*;\n\n #[frame::pallet]\n pub mod pallet {\n use frame::prelude::*;\n\n #[pallet::pallet]\n pub struct Pallet(_);\n\n #[pallet::config]\n pub trait Config: frame_system::Config {\n type RuntimeEvent: From> + IsType<::RuntimeEvent>;\n\n #[pallet::constant]\n type CounterMaxValue: Get;\n }\n\n #[pallet::event]\n #[pallet::generate_deposit(pub(super) fn deposit_event)]\n pub enum Event {\n CounterValueSet {\n new_value: u32,\n },\n CounterIncremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n CounterDecremented {\n new_value: u32,\n who: T::AccountId,\n amount: u32,\n },\n }\n\n #[pallet::error]\n pub enum Error {\n NoneValue,\n Overflow,\n Underflow,\n CounterMaxValueExceeded,\n }\n\n #[pallet::storage]\n pub type CounterValue = StorageValue<_, u32, ValueQuery>;\n\n #[pallet::storage]\n pub type UserInteractions = StorageMap<\n _,\n Blake2_128Concat,\n T::AccountId,\n u32,\n ValueQuery\n >;\n\n #[pallet::genesis_config]\n #[derive(DefaultNoBound)]\n pub struct GenesisConfig {\n pub initial_counter_value: u32,\n pub initial_user_interactions: Vec<(T::AccountId, u32)>,\n }\n\n #[pallet::genesis_build]\n impl BuildGenesisConfig for GenesisConfig {\n fn build(&self) {\n CounterValue::::put(self.initial_counter_value);\n for (account, count) in &self.initial_user_interactions {\n UserInteractions::::insert(account, count);\n }\n }\n }\n\n #[pallet::call]\n impl Pallet {\n #[pallet::call_index(0)]\n #[pallet::weight(0)]\n pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult {\n ensure_root(origin)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n Self::deposit_event(Event::CounterValueSet { new_value });\n Ok(())\n }\n\n #[pallet::call_index(1)]\n #[pallet::weight(0)]\n pub fn increment(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_add(amount).ok_or(Error::::Overflow)?;\n ensure!(new_value <= T::CounterMaxValue::get(), Error::::CounterMaxValueExceeded);\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n Self::deposit_event(Event::CounterIncremented { new_value, who, amount });\n Ok(())\n }\n\n #[pallet::call_index(2)]\n #[pallet::weight(0)]\n pub fn decrement(origin: OriginFor, amount: u32) -> DispatchResult {\n let who = ensure_signed(origin)?;\n let current_value = CounterValue::::get();\n let new_value = current_value.checked_sub(amount).ok_or(Error::::Underflow)?;\n CounterValue::::put(new_value);\n UserInteractions::::mutate(&who, |count| {\n *count = count.saturating_add(1);\n });\n Self::deposit_event(Event::CounterDecremented { new_value, who, amount });\n Ok(())\n }\n }\n }\n\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 8, "depth": 2, "title": "Write Your First Test", "anchor": "write-your-first-test", "start_char": 9206, "end_char": 9314, "estimated_token_count": 22, "token_estimator": "heuristic-v1", "text": "## Write Your First Test\n\nLet's start with a simple test to verify the increment function works correctly."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 9, "depth": 3, "title": "Test Basic Increment", "anchor": "test-basic-increment", "start_char": 9314, "end_char": 10392, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "### Test Basic Increment\n\nTest that the increment function increases counter value and emits events.\n\n```rust\n#[test]\nfn increment_works() {\n new_test_ext().execute_with(|| {\n // Set block number to 1 so events are registered\n System::set_block_number(1);\n\n let account = 1u64;\n\n // Increment by 50\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50));\n assert_eq!(crate::CounterValue::::get(), 50);\n\n // Check event was emitted\n System::assert_last_event(\n Event::CounterIncremented {\n new_value: 50,\n who: account,\n amount: 50,\n }\n .into(),\n );\n\n // Check user interactions were tracked\n assert_eq!(crate::UserInteractions::::get(account), 1);\n });\n}\n```\n\nRun your first test:\n\n```bash\ncargo test --package pallet-custom increment_works\n```\n\nYou should see:\n\n```\nrunning 1 test\ntest tests::increment_works ... ok\n```\n\nCongratulations! You've written and run your first pallet test."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 10, "depth": 2, "title": "Test Error Conditions", "anchor": "test-error-conditions", "start_char": 10392, "end_char": 10537, "estimated_token_count": 28, "token_estimator": "heuristic-v1", "text": "## Test Error Conditions\n\nNow let's test that our pallet correctly handles errors. Error testing is crucial to ensure your pallet fails safely."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 11, "depth": 3, "title": "Test Overflow Protection", "anchor": "test-overflow-protection", "start_char": 10537, "end_char": 11052, "estimated_token_count": 113, "token_estimator": "heuristic-v1", "text": "### Test Overflow Protection\n\nTest that incrementing at u32::MAX fails with Overflow error.\n\n```rust\n#[test]\nfn increment_fails_on_overflow() {\n new_test_ext_with_counter(u32::MAX).execute_with(|| {\n // Attempt to increment when at max u32 should fail\n assert_noop!(\n CustomPallet::increment(RuntimeOrigin::signed(1), 1),\n Error::::Overflow\n );\n });\n}\n```\n\nTest overflow protection:\n\n```bash\ncargo test --package pallet-custom increment_fails_on_overflow\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 12, "depth": 3, "title": "Test Underflow Protection", "anchor": "test-underflow-protection", "start_char": 11052, "end_char": 11564, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### Test Underflow Protection\n\nTest that decrementing below zero fails with Underflow error.\n\n```rust\n#[test]\nfn decrement_fails_on_underflow() {\n new_test_ext_with_counter(10).execute_with(|| {\n // Attempt to decrement below zero should fail\n assert_noop!(\n CustomPallet::decrement(RuntimeOrigin::signed(1), 11),\n Error::::Underflow\n );\n });\n}\n```\n\nVerify underflow protection:\n\n```bash\ncargo test --package pallet-custom decrement_fails_on_underflow\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 13, "depth": 2, "title": "Test Access Control", "anchor": "test-access-control", "start_char": 11564, "end_char": 11668, "estimated_token_count": 17, "token_estimator": "heuristic-v1", "text": "## Test Access Control\n\nVerify that origin checks work correctly and unauthorized access is prevented."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 14, "depth": 3, "title": "Test Root-Only Access", "anchor": "test-root-only-access", "start_char": 11668, "end_char": 12433, "estimated_token_count": 164, "token_estimator": "heuristic-v1", "text": "### Test Root-Only Access\n\nTest that set_counter_value requires root origin and rejects signed origins.\n\n```rust\n#[test]\nfn set_counter_value_requires_root() {\n new_test_ext().execute_with(|| {\n let alice = 1u64;\n\n // When: non-root user tries to set counter\n // Then: should fail with BadOrigin\n assert_noop!(\n CustomPallet::set_counter_value(RuntimeOrigin::signed(alice), 100),\n DispatchError::BadOrigin\n );\n\n // But root should succeed\n assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100));\n assert_eq!(crate::CounterValue::::get(), 100);\n });\n}\n```\n\nTest access control:\n\n```bash\ncargo test --package pallet-custom set_counter_value_requires_root\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 15, "depth": 2, "title": "Test Event Emission", "anchor": "test-event-emission", "start_char": 12433, "end_char": 12520, "estimated_token_count": 16, "token_estimator": "heuristic-v1", "text": "## Test Event Emission\n\nVerify that events are emitted correctly with the right data."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 16, "depth": 3, "title": "Test Event Data", "anchor": "test-event-data", "start_char": 12520, "end_char": 13700, "estimated_token_count": 264, "token_estimator": "heuristic-v1", "text": "### Test Event Data\n\nThe [`increment_works`](/parachains/customize-runtime/pallet-development/pallet-testing/#test-basic-increment) test (shown earlier) already demonstrates event testing by:\n\n1. Setting the block number to 1 to enable event emission.\n2. Calling the dispatchable function.\n3. Using `System::assert_last_event()` to verify the correct event was emitted with expected data.\n\nThis pattern applies to all dispatchables that emit events. For a dedicated event-only test focusing on the `set_counter_value` function:\n\nTest that set_counter_value updates storage and emits correct event.\n\n```rust\n#[test]\nfn set_counter_value_works() {\n new_test_ext().execute_with(|| {\n // Set block number to 1 so events are registered\n System::set_block_number(1);\n\n // Set counter to 100\n assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100));\n assert_eq!(crate::CounterValue::::get(), 100);\n\n // Check event was emitted\n System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into());\n });\n}\n```\n\nRun the event test:\n\n```bash\ncargo test --package pallet-custom set_counter_value_works\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 17, "depth": 2, "title": "Test Genesis Configuration", "anchor": "test-genesis-configuration", "start_char": 13700, "end_char": 13783, "estimated_token_count": 12, "token_estimator": "heuristic-v1", "text": "## Test Genesis Configuration\n\nVerify that genesis configuration works correctly."} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 18, "depth": 3, "title": "Test Genesis Setup", "anchor": "test-genesis-setup", "start_char": 13783, "end_char": 14402, "estimated_token_count": 160, "token_estimator": "heuristic-v1", "text": "### Test Genesis Setup\n\nTest that genesis configuration correctly initializes counter and user interactions.\n\n```rust\n#[test]\nfn genesis_config_works() {\n new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| {\n // Check initial counter value\n assert_eq!(crate::CounterValue::::get(), 42);\n\n // Check initial user interactions\n assert_eq!(crate::UserInteractions::::get(1), 5);\n assert_eq!(crate::UserInteractions::::get(2), 10);\n });\n}\n```\n\nTest genesis configuration:\n\n```bash\ncargo test --package pallet-custom genesis_config_works\n```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 19, "depth": 2, "title": "Run All Tests", "anchor": "run-all-tests", "start_char": 14402, "end_char": 24742, "estimated_token_count": 2250, "token_estimator": "heuristic-v1", "text": "## Run All Tests\n\nNow run all your tests together:\n\n```bash\ncargo test --package pallet-custom\n```\n\nYou should see all tests passing:\n\n
\n $ cargo test --package pallet-custom\n running 15 tests\n test mock::__construct_runtime_integrity_test::runtime_integrity_tests ... ok\n test mock::test_genesis_config_builds ... ok\n test tests::decrement_fails_on_underflow ... ok\n test tests::decrement_tracks_multiple_interactions ... ok\n test tests::decrement_works ... ok\n test tests::different_users_tracked_separately ... ok\n test tests::genesis_config_works ... ok\n test tests::increment_fails_on_overflow ... ok\n test tests::increment_respects_max_value ... ok\n test tests::increment_tracks_multiple_interactions ... ok\n test tests::increment_works ... ok\n test tests::mixed_increment_and_decrement_works ... ok\n test tests::set_counter_value_requires_root ... ok\n test tests::set_counter_value_respects_max_value ... ok\n test tests::set_counter_value_works ... ok\n \n test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\n
\n\n!!!note \"Mock Runtime Tests\"\n You'll notice 2 additional tests from the `mock` module:\n\n - `mock::__construct_runtime_integrity_test::runtime_integrity_tests` - Auto-generated test that validates runtime construction\n - `mock::test_genesis_config_builds` - Validates that genesis configuration builds correctly\n\n These tests are automatically generated from your mock runtime setup and help ensure the test environment itself is valid.\n\nCongratulations! You have a well-tested pallet covering the essential testing patterns!\n\nThese tests demonstrate comprehensive coverage including basic operations, error conditions, access control, event emission, state management, and genesis configuration. As you build more complex pallets, you'll apply these same patterns to test additional functionality.\n\n??? code \"Full Test Suite Code\"\n Here's the complete `tests.rs` file for quick reference:\n\n ```rust\n use crate::{mock::*, Error, Event};\n use frame::deps::frame_support::{assert_noop, assert_ok};\n use frame::deps::sp_runtime::DispatchError;\n\n #[test]\n fn set_counter_value_works() {\n new_test_ext().execute_with(|| {\n // Set block number to 1 so events are registered\n System::set_block_number(1);\n\n // Set counter to 100\n assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100));\n assert_eq!(crate::CounterValue::::get(), 100);\n\n // Check event was emitted\n System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into());\n });\n }\n\n #[test]\n fn set_counter_value_requires_root() {\n new_test_ext().execute_with(|| {\n // Attempt to set counter with non-root origin should fail\n assert_noop!(\n CustomPallet::set_counter_value(RuntimeOrigin::signed(1), 100),\n DispatchError::BadOrigin\n );\n });\n }\n\n #[test]\n fn set_counter_value_respects_max_value() {\n new_test_ext().execute_with(|| {\n // Attempt to set counter above max value (1000) should fail\n assert_noop!(\n CustomPallet::set_counter_value(RuntimeOrigin::root(), 1001),\n Error::::CounterMaxValueExceeded\n );\n\n // Setting to exactly max value should work\n assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 1000));\n assert_eq!(crate::CounterValue::::get(), 1000);\n });\n }\n\n #[test]\n fn increment_works() {\n new_test_ext().execute_with(|| {\n // Set block number to 1 so events are registered\n System::set_block_number(1);\n\n let account = 1u64;\n\n // Increment by 50\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50));\n assert_eq!(crate::CounterValue::::get(), 50);\n\n // Check event was emitted\n System::assert_last_event(\n Event::CounterIncremented {\n new_value: 50,\n who: account,\n amount: 50,\n }\n .into(),\n );\n\n // Check user interactions were tracked\n assert_eq!(crate::UserInteractions::::get(account), 1);\n });\n }\n\n #[test]\n fn increment_tracks_multiple_interactions() {\n new_test_ext().execute_with(|| {\n let account = 1u64;\n\n // Increment multiple times\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10));\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 20));\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 30));\n\n // Check counter value\n assert_eq!(crate::CounterValue::::get(), 60);\n\n // Check user interactions were tracked (should be 3)\n assert_eq!(crate::UserInteractions::::get(account), 3);\n });\n }\n\n #[test]\n fn increment_fails_on_overflow() {\n new_test_ext_with_counter(u32::MAX).execute_with(|| {\n // Attempt to increment when at max u32 should fail\n assert_noop!(\n CustomPallet::increment(RuntimeOrigin::signed(1), 1),\n Error::::Overflow\n );\n });\n }\n\n #[test]\n fn increment_respects_max_value() {\n new_test_ext_with_counter(950).execute_with(|| {\n // Incrementing past max value (1000) should fail\n assert_noop!(\n CustomPallet::increment(RuntimeOrigin::signed(1), 51),\n Error::::CounterMaxValueExceeded\n );\n\n // Incrementing to exactly max value should work\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 50));\n assert_eq!(crate::CounterValue::::get(), 1000);\n });\n }\n\n #[test]\n fn decrement_works() {\n new_test_ext_with_counter(100).execute_with(|| {\n // Set block number to 1 so events are registered\n System::set_block_number(1);\n\n let account = 2u64;\n\n // Decrement by 30\n assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 30));\n assert_eq!(crate::CounterValue::::get(), 70);\n\n // Check event was emitted\n System::assert_last_event(\n Event::CounterDecremented {\n new_value: 70,\n who: account,\n amount: 30,\n }\n .into(),\n );\n\n // Check user interactions were tracked\n assert_eq!(crate::UserInteractions::::get(account), 1);\n });\n }\n\n #[test]\n fn decrement_fails_on_underflow() {\n new_test_ext_with_counter(10).execute_with(|| {\n // Attempt to decrement below zero should fail\n assert_noop!(\n CustomPallet::decrement(RuntimeOrigin::signed(1), 11),\n Error::::Underflow\n );\n });\n }\n\n #[test]\n fn decrement_tracks_multiple_interactions() {\n new_test_ext_with_counter(100).execute_with(|| {\n let account = 3u64;\n\n // Decrement multiple times\n assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 10));\n assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 20));\n\n // Check counter value\n assert_eq!(crate::CounterValue::::get(), 70);\n\n // Check user interactions were tracked (should be 2)\n assert_eq!(crate::UserInteractions::::get(account), 2);\n });\n }\n\n #[test]\n fn mixed_increment_and_decrement_works() {\n new_test_ext_with_counter(50).execute_with(|| {\n let account = 4u64;\n\n // Mix of increment and decrement\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 25));\n assert_eq!(crate::CounterValue::::get(), 75);\n\n assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 15));\n assert_eq!(crate::CounterValue::::get(), 60);\n\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10));\n assert_eq!(crate::CounterValue::::get(), 70);\n\n // Check user interactions were tracked (should be 3)\n assert_eq!(crate::UserInteractions::::get(account), 3);\n });\n }\n\n #[test]\n fn different_users_tracked_separately() {\n new_test_ext().execute_with(|| {\n let account1 = 1u64;\n let account2 = 2u64;\n\n // User 1 increments\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10));\n assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10));\n\n // User 2 decrements\n assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account2), 5));\n\n // Check counter value (10 + 10 - 5 = 15)\n assert_eq!(crate::CounterValue::::get(), 15);\n\n // Check user interactions are tracked separately\n assert_eq!(crate::UserInteractions::::get(account1), 2);\n assert_eq!(crate::UserInteractions::::get(account2), 1);\n });\n }\n\n #[test]\n fn genesis_config_works() {\n new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| {\n // Check initial counter value\n assert_eq!(crate::CounterValue::::get(), 42);\n\n // Check initial user interactions\n assert_eq!(crate::UserInteractions::::get(1), 5);\n assert_eq!(crate::UserInteractions::::get(2), 10);\n });\n }\n ```"} +{"page_id": "parachains-customize-runtime-pallet-development-pallet-testing", "page_title": "Pallet Unit Testing", "index": 20, "depth": 2, "title": "Where to Go Next", "anchor": "where-to-go-next", "start_char": 24742, "end_char": 25092, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "## Where to Go Next\n\n
\n\n- Guide __Add Your Custom Pallet to the Runtime__\n\n ---\n\n Your pallet is tested and ready! Learn how to integrate it into your runtime.\n\n [:octicons-arrow-right-24: Integrate](/parachains/customize-runtime/pallet-development/add-to-runtime/)\n\n
"} {"page_id": "parachains-customize-runtime", "page_title": "Overview of FRAME", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 26, "end_char": 754, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nA blockchain runtime is more than just a fixed set of rules—it's a dynamic foundation that you can shape to match your specific needs. With Polkadot SDK's [FRAME (Framework for Runtime Aggregation of Modularized Entities)](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\\_blank}, customizing your runtime is straightforward and modular. Instead of building everything from scratch, you combine pre-built pallets with your own custom logic to create a runtime suited to your blockchain's purpose.\n\nThis overview explains how runtime customization works, introduces the building blocks you'll use, and guides you through the key patterns for extending your runtime."} {"page_id": "parachains-customize-runtime", "page_title": "Overview of FRAME", "index": 1, "depth": 2, "title": "Understanding Your Runtime", "anchor": "understanding-your-runtime", "start_char": 754, "end_char": 1533, "estimated_token_count": 158, "token_estimator": "heuristic-v1", "text": "## Understanding Your Runtime\n\nThe runtime is the core logic of your blockchain—it processes transactions, manages state, and enforces the rules that govern your network. When a transaction arrives at your blockchain, the [`frame_executive`](https://paritytech.github.io/polkadot-sdk/master/frame_executive/index.html){target=\\_blank} pallet receives it and routes it to the appropriate pallet for execution.\n\nThink of your runtime as a collection of specialized modules, each handling a different aspect of your blockchain. Need token balances? Use the Balances pallet. Want governance? Add the Governance pallets. Need something custom? Create your own pallet. By mixing and matching these modules, you build a runtime that's efficient, secure, and tailored to your use case."} {"page_id": "parachains-customize-runtime", "page_title": "Overview of FRAME", "index": 2, "depth": 2, "title": "Runtime Architecture", "anchor": "runtime-architecture", "start_char": 1533, "end_char": 2085, "estimated_token_count": 121, "token_estimator": "heuristic-v1", "text": "## Runtime Architecture\n\nThe following diagram shows how FRAME components work together to form your runtime:\n\n![](/images/parachains/customize-runtime/index/frame-overview-01.webp)\n\nThe main components are:\n\n- **`frame_executive`**: Routes all incoming transactions to the correct pallet for execution.\n- **Pallets**: Domain-specific modules that implement your blockchain's features and business logic.\n- **`frame_system`**: Provides core runtime primitives and storage.\n- **`frame_support`**: Utilities and macros that simplify pallet development."} @@ -255,12 +263,12 @@ {"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 0, "depth": 2, "title": "Quick Start Guides", "anchor": "quick-start-guides", "start_char": 186, "end_char": 1576, "estimated_token_count": 388, "token_estimator": "heuristic-v1", "text": "## Quick Start Guides\n\nQuick start guides help developers set up and interact with the Polkadot parachain ecosystem using various tools and frameworks.\n\n| Tutorial | Tools | Description |\n| :--------------------------------------------------------------------------------------------: | :----------------------------: | :---------------------------------------------------------------------: |\n| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK | Learn how to set up and run the Polkadot SDK Parachain Template locally |\n| [Launch a Local Parachain](/parachains/testing/run-a-parachain-network/) | Zombienet, Chopsticks | Set up a local development environment for testing |\n| [Connect to Polkadot](/chain-interactions/query-on-chain-data/query-sdks/) | Polkadot.js, Substrate Connect | Connect your application to Polkadot networks |\n| [Fork an Existing Parachain](/parachains/testing/fork-a-parachain/) | Chopsticks | Create a local fork of a live parachain for testing |"} {"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 1, "depth": 2, "title": "Launch a Simple Parachain", "anchor": "launch-a-simple-parachain", "start_char": 1576, "end_char": 2570, "estimated_token_count": 301, "token_estimator": "heuristic-v1", "text": "## Launch a Simple Parachain\n\nLearn the fundamentals of launching and deploying a parachain to the Polkadot network.\n\n| Tutorial | Description |\n| :--------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------: |\n| [Set Up the Parachain Template](/parachains/launch-a-parachain/set-up-the-parachain-template/) | Polkadot SDK |\n| [Deploy to Polkadot](/parachains/launch-a-parachain/deploy-to-polkadot/) | Step-by-step tutorial to deploying your parachain to Polkadot |\n| [Obtain Coretime](/parachains/launch-a-parachain/obtain-coretime/) | Learn how to acquire blockspace using Polkadot's coretime model (RegionX) |"} {"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 2, "depth": 2, "title": "Customize Your Runtime", "anchor": "customize-your-runtime", "start_char": 2570, "end_char": 3540, "estimated_token_count": 294, "token_estimator": "heuristic-v1", "text": "## Customize Your Runtime\n\nBuild custom functionality for your parachain by composing and creating pallets.\n\n| Tutorial | Description |\n| :-------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------: |\n| [Add Existing Pallets to the Runtime](/parachains/customize-runtime/add-existing-pallets/) | Integrate pre-built pallets from the FRAME ecosystem |\n| [Add Multiple Instances of a Pallet](/parachains/customize-runtime/add-pallet-instances/) | Configure and use multiple instances of the same pallet |\n| [Add Smart Contract Functionality](/parachains/customize-runtime/add-smart-contract-functionality/) | Enable smart contract capabilities using Contracts or EVM pallets |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 3, "depth": 3, "title": "Pallet Development", "anchor": "pallet-development", "start_char": 3540, "end_char": 4877, "estimated_token_count": 369, "token_estimator": "heuristic-v1", "text": "### Pallet Development\n\nDeep dive into creating and managing custom pallets for your parachain.\n\n| Tutorial | Description |\n| :--------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------: |\n| [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic |\n| [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing |\n| [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic |\n| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime |\n| [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 4, "depth": 2, "title": "Testing", "anchor": "testing", "start_char": 4877, "end_char": 5501, "estimated_token_count": 209, "token_estimator": "heuristic-v1", "text": "## Testing\n\nTest your parachain in various environments before production deployment.\n\n| Tutorial | Description |\n| :---------------------------------------------------------------------: | :-----------------------------------------------------: |\n| [Fork a Parachain](/parachains/testing/fork-a-parachain/) | Use Chopsticks to create a local fork for testing |\n| [Run a Parachain Network](/parachains/testing/run-a-parachain-network/) | Launch a complete parachain test network with Zombienet |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 5, "depth": 2, "title": "Runtime Upgrades and Maintenance", "anchor": "runtime-upgrades-and-maintenance", "start_char": 5501, "end_char": 6290, "estimated_token_count": 231, "token_estimator": "heuristic-v1", "text": "## Runtime Upgrades and Maintenance\n\nManage your parachain's lifecycle with forkless upgrades and maintenance operations.\n\n| Tutorial | Description |\n| :-----------------------------------------------------------------------: | :--------------------------------------------------: |\n| [Runtime Upgrades](/parachains/runtime-maintenance/runtime-upgrades/) | Perform forkless runtime upgrades via governance |\n| [Storage Migrations](/parachains/runtime-maintenance/storage-migrations/) | Safely migrate storage when updating runtime logic |\n| [Unlock Parachains](/parachains/runtime-maintenance/unlock-parachains/) | Understand parachain lifecycle and unlock mechanisms |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 6, "depth": 2, "title": "Interoperability", "anchor": "interoperability", "start_char": 6290, "end_char": 7079, "estimated_token_count": 251, "token_estimator": "heuristic-v1", "text": "## Interoperability\n\nConfigure your parachain for cross-chain communication using XCM (Cross-Consensus Messaging).\n\n| Tutorial | Description |\n| :--------------------------------------------------------------------------------------------------------: | :----------------------------------------------------: |\n| [Open HRMP Channels Between Parachains](/parachains/interoperability/channels-between-parachains/) | Establish communication channels with other parachains |\n| [Open HRMP Channels with System Parachains](/parachains/interoperability/channels-with-system-parachains/) | Connect with Asset Hub and other system parachains |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 7, "depth": 2, "title": "Integrations", "anchor": "integrations", "start_char": 7079, "end_char": 7708, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Integrations\n\nIntegrate your parachain with essential ecosystem tools and services.\n\n| Tutorial | Description |\n| :--------------------------------------------: | :----------------------------------------------------: |\n| [Wallets](/parachains/integrations/wallets/) | Integrate wallet support for user interactions |\n| [Indexers](/parachains/integrations/indexers/) | Set up indexing solutions for querying blockchain data |\n| [Oracles](/parachains/integrations/oracles/) | Connect your parachain to off-chain data sources |"} -{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 8, "depth": 2, "title": "Additional Resources", "anchor": "additional-resources", "start_char": 7708, "end_char": 7941, "estimated_token_count": 60, "token_estimator": "heuristic-v1", "text": "## Additional Resources\n\n- [Polkadot SDK Documentation](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html)\n- [Polkadot Wiki - Parachains](https://wiki.polkadot.network/docs/learn-parachains/)"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 3, "depth": 3, "title": "Pallet Development", "anchor": "pallet-development", "start_char": 3540, "end_char": 4700, "estimated_token_count": 328, "token_estimator": "heuristic-v1", "text": "### Pallet Development\n\nDeep dive into creating and managing custom pallets for your parachain.\n\n| Tutorial | Description |\n| :--------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------: |\n| [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic |\n| [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing |\n| [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic |\n| [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking |"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 4, "depth": 2, "title": "Testing", "anchor": "testing", "start_char": 4700, "end_char": 5324, "estimated_token_count": 209, "token_estimator": "heuristic-v1", "text": "## Testing\n\nTest your parachain in various environments before production deployment.\n\n| Tutorial | Description |\n| :---------------------------------------------------------------------: | :-----------------------------------------------------: |\n| [Fork a Parachain](/parachains/testing/fork-a-parachain/) | Use Chopsticks to create a local fork for testing |\n| [Run a Parachain Network](/parachains/testing/run-a-parachain-network/) | Launch a complete parachain test network with Zombienet |"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 5, "depth": 2, "title": "Runtime Upgrades and Maintenance", "anchor": "runtime-upgrades-and-maintenance", "start_char": 5324, "end_char": 6113, "estimated_token_count": 231, "token_estimator": "heuristic-v1", "text": "## Runtime Upgrades and Maintenance\n\nManage your parachain's lifecycle with forkless upgrades and maintenance operations.\n\n| Tutorial | Description |\n| :-----------------------------------------------------------------------: | :--------------------------------------------------: |\n| [Runtime Upgrades](/parachains/runtime-maintenance/runtime-upgrades/) | Perform forkless runtime upgrades via governance |\n| [Storage Migrations](/parachains/runtime-maintenance/storage-migrations/) | Safely migrate storage when updating runtime logic |\n| [Unlock Parachains](/parachains/runtime-maintenance/unlock-parachains/) | Understand parachain lifecycle and unlock mechanisms |"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 6, "depth": 2, "title": "Interoperability", "anchor": "interoperability", "start_char": 6113, "end_char": 6902, "estimated_token_count": 251, "token_estimator": "heuristic-v1", "text": "## Interoperability\n\nConfigure your parachain for cross-chain communication using XCM (Cross-Consensus Messaging).\n\n| Tutorial | Description |\n| :--------------------------------------------------------------------------------------------------------: | :----------------------------------------------------: |\n| [Open HRMP Channels Between Parachains](/parachains/interoperability/channels-between-parachains/) | Establish communication channels with other parachains |\n| [Open HRMP Channels with System Parachains](/parachains/interoperability/channels-with-system-parachains/) | Connect with Asset Hub and other system parachains |"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 7, "depth": 2, "title": "Integrations", "anchor": "integrations", "start_char": 6902, "end_char": 7531, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Integrations\n\nIntegrate your parachain with essential ecosystem tools and services.\n\n| Tutorial | Description |\n| :--------------------------------------------: | :----------------------------------------------------: |\n| [Wallets](/parachains/integrations/wallets/) | Integrate wallet support for user interactions |\n| [Indexers](/parachains/integrations/indexers/) | Set up indexing solutions for querying blockchain data |\n| [Oracles](/parachains/integrations/oracles/) | Connect your parachain to off-chain data sources |"} +{"page_id": "parachains-get-started", "page_title": "Get Started with Parachain Development", "index": 8, "depth": 2, "title": "Additional Resources", "anchor": "additional-resources", "start_char": 7531, "end_char": 7764, "estimated_token_count": 60, "token_estimator": "heuristic-v1", "text": "## Additional Resources\n\n- [Polkadot SDK Documentation](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html)\n- [Polkadot Wiki - Parachains](https://wiki.polkadot.network/docs/learn-parachains/)"} {"page_id": "parachains-install-polkadot-sdk", "page_title": "Install Polkadot SDK", "index": 0, "depth": 2, "title": "Install Dependencies: macOS", "anchor": "install-dependencies-macos", "start_char": 495, "end_char": 656, "estimated_token_count": 28, "token_estimator": "heuristic-v1", "text": "## Install Dependencies: macOS\n\nYou can install Rust and set up a Substrate development environment on Apple macOS computers with Intel or Apple M1 processors."} {"page_id": "parachains-install-polkadot-sdk", "page_title": "Install Polkadot SDK", "index": 1, "depth": 3, "title": "Before You Begin {: #before-you-begin-mac-os }", "anchor": "before-you-begin-before-you-begin-mac-os", "start_char": 656, "end_char": 1113, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### Before You Begin {: #before-you-begin-mac-os }\n\nBefore you install Rust and set up your development environment on macOS, verify that your computer meets the following basic requirements:\n\n- Operating system version is 10.7 Lion or later.\n- Processor speed of at least 2 GHz. Note that 3 GHz is recommended.\n- Memory of at least 8 GB RAM. Note that 16 GB is recommended.\n- Storage of at least 10 GB of available space.\n- Broadband Internet connection."} {"page_id": "parachains-install-polkadot-sdk", "page_title": "Install Polkadot SDK", "index": 2, "depth": 3, "title": "Install Homebrew", "anchor": "install-homebrew", "start_char": 1113, "end_char": 1964, "estimated_token_count": 206, "token_estimator": "heuristic-v1", "text": "### Install Homebrew\n\nIn most cases, you should use Homebrew to install and manage packages on macOS computers. If you don't already have Homebrew installed on your local computer, you should download and install it before continuing.\n\nTo install Homebrew:\n\n1. Open the Terminal application.\n2. Download and install Homebrew by running the following command:\n\n ```bash\n /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n ```\n\n3. Verify Homebrew has been successfully installed by running the following command:\n\n ```bash\n brew --version\n ```\n\n The command displays output similar to the following:\n\n
\n brew --version\n Homebrew 4.3.15\n
"} diff --git a/llms.txt b/llms.txt index 79e3f1ff7..8606f37ab 100644 --- a/llms.txt +++ b/llms.txt @@ -6,14 +6,13 @@ This directory lists URLs for raw Markdown pages that complement the rendered pages on the documentation site. Use these Markdown files to retain semantic context when prompting models while avoiding passing HTML elements. ## Metadata -- Documentation pages: 88 +- Documentation pages: 87 - Categories: 11 ## Docs This section lists documentation pages by category. Each entry links to a raw markdown version of the page and includes a short description. A page may appear in multiple categories. Docs: Basics -- [Add Pallets to the Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md): Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - [Overview of FRAME](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime.md): Learn how Polkadot SDK’s FRAME framework simplifies blockchain development with modular pallets and support libraries for efficient runtime design. - [Get Started with Parachain Development](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-get-started.md): Practical examples and tutorials for building and deploying Polkadot parachains, covering everything from launch to customization and cross-chain messaging. - [Install Polkadot SDK](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-install-polkadot-sdk.md): Install all required Polkadot SDK dependencies, set up the SDK itself, and verify that it runs correctly on your machine. @@ -68,11 +67,10 @@ Docs: Parachains - [Add an Existing Pallet to the Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-add-existing-pallets.md): Learn how to include and configure pallets in a Polkadot SDK-based runtime, from adding dependencies to implementing necessary traits. - [Add Multiple Pallet Instances](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-add-pallet-instances.md): Learn how to implement multiple instances of the same pallet in your Polkadot SDK-based runtime, from adding dependencies to configuring unique instances. - [Add Smart Contract Functionality](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-add-smart-contract-functionality.md): Add smart contract capabilities to your Polkadot SDK-based blockchain. Explore PVM, EVM, and Wasm integration for enhanced chain functionality. -- [Add Pallets to the Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-add-pallet-to-runtime.md): Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. - [Benchmarking FRAME Pallets](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-benchmark-pallet.md): Learn how to use FRAME's benchmarking framework to measure extrinsic execution costs and provide accurate weights for on-chain computations. - [Create a Custom Pallet](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-create-a-pallet.md): Learn how to create custom pallets using FRAME, allowing for flexible, modular, and scalable blockchain development. Follow the step-by-step guide. - [Mock Your Runtime](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-mock-runtime.md): Learn how to create a mock runtime environment for testing your custom pallets in isolation, enabling comprehensive unit testing before runtime integration. -- [Pallet Testing](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md): Learn how to efficiently test pallets in the Polkadot SDK, ensuring the reliability and security of your pallets operations. +- [Pallet Unit Testing](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime-pallet-development-pallet-testing.md): Learn how to write comprehensive unit tests for your custom pallets using mock runtimes, ensuring reliability and correctness before deployment. - [Overview of FRAME](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-customize-runtime.md): Learn how Polkadot SDK’s FRAME framework simplifies blockchain development with modular pallets and support libraries for efficient runtime design. - [Get Started with Parachain Development](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-get-started.md): Practical examples and tutorials for building and deploying Polkadot parachains, covering everything from launch to customization and cross-chain messaging. - [Opening HRMP Channels Between Parachains](https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/parachains-interoperability-channels-between-parachains.md): Learn how to open HRMP channels between parachains on Polkadot. Discover the step-by-step process for establishing uni- and bidirectional communication. diff --git a/parachains/customize-runtime/add-existing-pallets.md b/parachains/customize-runtime/add-existing-pallets.md index 7dee7ce61..d1a6b020f 100644 --- a/parachains/customize-runtime/add-existing-pallets.md +++ b/parachains/customize-runtime/add-existing-pallets.md @@ -259,7 +259,7 @@ To interact with the pallet: - **`batchAll(calls)`**: Dispatch multiple calls, stopping on the first error. - **`asDerivative(index, call)`**: Dispatch a call as a derivative account. - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) + ![](/images/parachains/customize-runtime/add-existing-pallets/add-pallets-01.webp) You can now test the pallet's functionality by submitting transactions through the interface. diff --git a/parachains/customize-runtime/pallet-development/.nav.yml b/parachains/customize-runtime/pallet-development/.nav.yml index a6c7e9399..dd7abe926 100644 --- a/parachains/customize-runtime/pallet-development/.nav.yml +++ b/parachains/customize-runtime/pallet-development/.nav.yml @@ -2,5 +2,4 @@ nav: - 'Create a Custom Pallet': create-a-pallet.md - 'Mock Your Runtime': mock-runtime.md - 'Pallet Unit Testing': pallet-testing.md - - 'Add a Custom Pallet to Your Runtime': add-pallet-to-runtime.md - 'Benchmark a Custom Pallet': benchmark-pallet.md \ No newline at end of file diff --git a/parachains/customize-runtime/pallet-development/add-pallet-to-runtime.md b/parachains/customize-runtime/pallet-development/add-pallet-to-runtime.md deleted file mode 100644 index 3aa7939c6..000000000 --- a/parachains/customize-runtime/pallet-development/add-pallet-to-runtime.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: Add Pallets to the Runtime -description: Add pallets to your runtime for custom functionality. Learn to configure and integrate pallets in Polkadot SDK-based blockchains. -tutorial_badge: Beginner -categories: Basics, Parachains ---- - -# Add Pallets to the Runtime - -## Introduction - -In previous tutorials, you learned how to [create a custom pallet](/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/){target=\_blank} and [test it](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank}. The next step is to include this pallet in your runtime, integrating it into the core logic of your blockchain. - -This tutorial will guide you through adding two pallets to your runtime: the custom pallet you previously developed and the [utility pallet](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/index.html){target=\_blank}. This standard Polkadot SDK pallet provides powerful dispatch functionality. The utility pallet offers, for example, batch dispatch, a stateless operation that enables executing multiple calls in a single transaction. - -## Add the Pallets as Dependencies - -First, you'll update the runtime's `Cargo.toml` file to include the Utility pallet and your custom pallets as dependencies for the runtime. Follow these steps: - -1. Open the `runtime/Cargo.toml` file and locate the `[dependencies]` section. Add pallet-utility as one of the features for the `polkadot-sdk` dependency with the following line: - - ```toml hl_lines="4" title="runtime/Cargo.toml" - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/runtime/Cargo.toml:19:19' - ... - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml:26:27' - ... - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml:55:55' - ``` - -2. In the same `[dependencies]` section, add the custom pallet that you built from scratch with the following line: - - ```toml hl_lines="3" title="Cargo.toml" - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/runtime/Cargo.toml:19:19' - ... - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/runtime/Cargo.toml:30:30' - ``` - -3. In the `[features]` section, add the custom pallet to the `std` feature list: - - ```toml hl_lines="5" title="Cargo.toml" - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/runtime/Cargo.toml:32:34' - ... - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/runtime/Cargo.toml:43:43' - ... - ] - ``` - -3. Save the changes and close the `Cargo.toml` file. - - Once you have saved your file, it should look like the following: - - ???- code "runtime/Cargo.toml" - - ```rust title="runtime/Cargo.toml" - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/Cargo.toml' - ``` - -Update your root parachain template's `Cargo.toml` file to include your custom pallet as a dependency. Follow these steps: - -1. Open the `./Cargo.toml` file and locate the `[workspace]` section. - - Make sure the `custom-pallet` is a member of the workspace: - - ```toml hl_lines="4" title="Cargo.toml" - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/Cargo.toml:8:14' - ``` - -???- code "./Cargo.toml" - - ```rust title="./Cargo.toml" - --8<-- 'https://raw.githubusercontent.com/papermoonio/zero-to-hero-tutorial/refs/heads/v0.0.4-complete-tutorial/Cargo.toml' - ``` - - -### Update the Runtime Configuration - -Configure the pallets by implementing their `Config` trait and update the runtime macro to include the new pallets: - -1. Add the `OriginCaller` import: - - ```rust title="mod.rs" hl_lines="8" - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs:59:60' - ... - ``` - -2. Implement the [`Config`](https://paritytech.github.io/polkadot-sdk/master/pallet_utility/pallet/trait.Config.html){target=\_blank} trait for both pallets at the end of the `runtime/src/config/mod.rs` file: - - ```rust title="mod.rs" hl_lines="8-25" - ... - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs:320:332' - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/configs/mod.rs:334:342' - } - ``` - -3. Locate the `#[frame_support::runtime]` macro in the `runtime/src/lib.rs` file and add the pallets: - - ```rust hl_lines="9-14" title="lib.rs" - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs:256:259' - ... - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs:270:271' - - --8<-- 'code/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/src/lib.rs:320:324' - } - ``` - -## Recompile the Runtime - -After adding and configuring your pallets in the runtime, the next step is to ensure everything is set up correctly. To do this, recompile the runtime with the following command (make sure you're in the project's root directory): - -```bash -cargo build --release -``` - -This command ensures the runtime compiles without errors, validates the pallet configurations, and prepares the build for subsequent testing or deployment. - -## Run Your Chain Locally - -Launch your parachain locally and start producing blocks: - -!!!tip - Generated chain TestNet specifications include development accounts "Alice" and "Bob." These accounts are pre-funded with native parachain currency, allowing you to sign and send TestNet transactions. Take a look at the [Polkadot.js Accounts section](https://polkadot.js.org/apps/#/accounts){target=\_blank} to view the development accounts for your chain. - -1. Create a new chain specification file with the updated runtime: - - ```bash - chain-spec-builder create -t development \ - --relay-chain paseo \ - --para-id 1000 \ - --runtime ./target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ - named-preset development - ``` - -2. Start the omni node with the generated chain specification: - - ```bash - polkadot-omni-node --chain ./chain_spec.json --dev - ``` - -3. Verify you can interact with the new pallets using the [Polkadot.js Apps](https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/extrinsics){target=\_blank} interface. Navigate to the **Extrinsics** tab and check that you can see both pallets: - - - Utility pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-01.webp) - - - - Custom pallet - - ![](/images/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/add-pallets-to-runtime-02.webp) - -## Where to Go Next - -
- -- Tutorial __Deploy on Paseo TestNet__ - - --- - - Deploy your Polkadot SDK blockchain on Paseo! Follow this step-by-step guide for a seamless journey to a successful TestNet deployment. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/) - -- Tutorial __Pallet Benchmarking (Optional)__ - - --- - - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. - - [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/) - -
diff --git a/parachains/customize-runtime/pallet-development/pallet-testing.md b/parachains/customize-runtime/pallet-development/pallet-testing.md index 6dc75eb5e..1bc102974 100644 --- a/parachains/customize-runtime/pallet-development/pallet-testing.md +++ b/parachains/customize-runtime/pallet-development/pallet-testing.md @@ -1,86 +1,611 @@ --- -title: Pallet Testing -description: Learn how to efficiently test pallets in the Polkadot SDK, ensuring the reliability and security of your pallets operations. +title: Pallet Unit Testing +description: Learn how to write comprehensive unit tests for your custom pallets using mock runtimes, ensuring reliability and correctness before deployment. categories: Parachains --- -# Pallet Testing +# Pallet Unit Testing ## Introduction -Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. The Polkadot SDK offers a set of APIs to create a test environment to simulate runtime and mock transaction execution for extrinsics and queries. +Unit testing in the Polkadot SDK helps ensure that the functions provided by a pallet behave as expected. It also confirms that data and events associated with a pallet are processed correctly during interactions. With your mock runtime in place from the [previous guide](/parachains/customize-runtime/pallet-development/mock-runtime/), you can now write comprehensive tests that verify your pallet's behavior in isolation. -To begin unit testing, you must first set up a mock runtime that simulates blockchain behavior, incorporating the necessary pallets. For a deeper understanding, consult the [Mock Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/){target=\_blank} guide. +In this guide, you'll learn how to: -## Writing Unit Tests +- Structure test modules effectively. +- Test dispatchable functions. +- Verify storage changes. +- Check event emission. +- Test error conditions. +- Use genesis configurations in tests. -Once the mock runtime is in place, the next step is to write unit tests that evaluate the functionality of your pallet. Unit tests allow you to test specific pallet features in isolation, ensuring that each function behaves correctly under various conditions. These tests typically reside in your pallet module's `test.rs` file. +## Prerequisites -Unit tests in the Polkadot SDK use the Rust testing framework, and the mock runtime you've defined earlier will serve as the test environment. Below are the typical steps involved in writing unit tests for a pallet. +Before you begin, ensure you: -The tests confirm that: +- Completed the [Make a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) guide. +- Completed the [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) guide. +- Configured custom counter pallet with mock runtime in `pallets/pallet-custom`. +- Understood the basics of [Rust testing](https://doc.rust-lang.org/book/ch11-00-testing.html){target=\_blank}. -- **Pallets initialize correctly**: At the start of each test, the system should initialize with block number 0, and the pallets should be in their default states. -- **Pallets modify each other's state**: The second test shows how one pallet can trigger changes in another pallet's internal state, confirming proper cross-pallet interactions. -- **State transitions between blocks are seamless**: By simulating block transitions, the tests validate that the runtime responds correctly to changes in the block number. +## Understanding FRAME Testing Tools -Testing pallet interactions within the runtime is critical for ensuring the blockchain behaves as expected under real-world conditions. Writing integration tests allows validation of how pallets function together, preventing issues that might arise when the system is fully assembled. +[FRAME](/reference/glossary/#frame-framework-for-runtime-aggregation-of-modularized-entities){target=\_blank} provides specialized testing macros and utilities that make pallet testing more efficient: -This approach provides a comprehensive view of the runtime's functionality, ensuring the blockchain is stable and reliable. +### Assertion Macros -### Test Initialization +- **[`assert_ok!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_ok.html){target=\_blank}** - Asserts that a dispatchable call succeeds. +- **[`assert_noop!`](https://paritytech.github.io/polkadot-sdk/master/frame_support/macro.assert_noop.html){target=\_blank}** - Asserts that a call fails without changing state (no operation). +- **[`assert_eq!`](https://doc.rust-lang.org/std/macro.assert_eq.html){target=\_blank}** - Standard Rust equality assertion. -Each test starts by initializing the runtime environment, typically using the `new_test_ext()` function, which sets up the mock storage and environment. +!!!info "`assert_noop!` Explained" + Use `assert_noop!` to ensure the operation fails without any state changes. This is critical for testing error conditions - it verifies both that the error occurs AND that no storage was modified. + +### System Pallet Test Helpers + +The [`frame_system`](https://paritytech.github.io/polkadot-sdk/master/frame_system/index.html){target=\_blank} pallet provides useful methods for testing: + +- **[`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank}** - Returns all events emitted during the test. +- **[`System::assert_last_event()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}** - Asserts the last event matches expectations. +- **[`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank}** - Sets the current block number. + +!!!info "Events and Block Number" + Events are not emitted on block 0 (genesis block). If you need to test events, ensure you set the block number to at least 1 using `System::set_block_number(1)`. + +### Origin Types + +- **[`RuntimeOrigin::root()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Root){target=\_blank}** - Root/sudo origin for privileged operations. +- **[`RuntimeOrigin::signed(account)`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.Signed){target=\_blank}** - Signed origin from a specific account. +- **[`RuntimeOrigin::none()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/enum.RawOrigin.html#variant.None){target=\_blank}** - No origin (typically fails for most operations). + +Learn more about origins in the [FRAME Origin reference document](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/reference_docs/frame_origin/index.html){target=\_blank}. + +## Create the Tests Module + +Create a new file for your tests within the pallet directory: + +1. Navigate to your pallet directory: + + ```bash + cd pallets/pallet-custom/src + ``` + +2. Create a new file named `tests.rs`: + + ```bash + touch tests.rs + ``` + +3. Open `src/lib.rs` and add the tests module declaration after the mock module: + + ```rust title="src/lib.rs" + #![cfg_attr(not(feature = "std"), no_std)] + + pub use pallet::*; + + #[cfg(test)] + mod mock; + + #[cfg(test)] + mod tests; + + #[frame::pallet] + pub mod pallet { + // ... existing pallet code + } + ``` + +## Set Up the Test Module + +Open `src/tests.rs` and add the basic structure with necessary imports: + +```rust +use crate::{mock::*, Error, Event}; +use frame::deps::frame_support::{assert_noop, assert_ok}; +use frame::deps::sp_runtime::DispatchError; +``` + +This setup imports: + +- The mock runtime and test utilities from `mock.rs` +- Your pallet's `Error` and `Event` types +- FRAME's assertion macros via `frame::deps` +- `DispatchError` for testing origin checks + +???+ code "Complete Pallet Code Reference" + Here's the complete pallet code that you'll be testing throughout this guide: + + ```rust + ---8<-- 'code/parachains/customize-runtime/pallet-development/create-a-pallet/lib-complete.rs' + ``` + +## Write Your First Test + +Let's start with a simple test to verify the increment function works correctly. + +### Test Basic Increment + +Test that the increment function increases counter value and emits events. + +```rust +#[test] +fn increment_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); +} +``` + +Run your first test: + +```bash +cargo test --package pallet-custom increment_works +``` + +You should see: + +``` +running 1 test +test tests::increment_works ... ok +``` + +Congratulations! You've written and run your first pallet test. + +## Test Error Conditions + +Now let's test that our pallet correctly handles errors. Error testing is crucial to ensure your pallet fails safely. + +### Test Overflow Protection + +Test that incrementing at u32::MAX fails with Overflow error. ```rust ---8<-- 'code/parachains/customize-runtime/pallet-development/pallet-testing/test-initialization.rs' +#[test] +fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); + }); +} +``` + +Test overflow protection: + +```bash +cargo test --package pallet-custom increment_fails_on_overflow ``` -### Function Call Testing +### Test Underflow Protection -Call the pallet's extrinsics or functions to simulate user interaction or internal logic. Use the `assert_ok!` macro to check for successful execution and `assert_err!` to verify that errors are correctly handled. +Test that decrementing below zero fails with Underflow error. ```rust ---8<-- 'code/parachains/customize-runtime/pallet-development/pallet-testing/function-call-testing.rs' +#[test] +fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow + ); + }); +} ``` -### Storage Testing +Verify underflow protection: + +```bash +cargo test --package pallet-custom decrement_fails_on_underflow +``` + +## Test Access Control + +Verify that origin checks work correctly and unauthorized access is prevented. -After calling a function or extrinsic in your pallet, it's essential to verify that the state changes in the pallet's storage match the expected behavior to ensure data is updated correctly based on the actions taken. +### Test Root-Only Access -The following example shows how to test the storage behavior before and after the function call: +Test that set_counter_value requires root origin and rejects signed origins. ```rust ---8<-- 'code/parachains/customize-runtime/pallet-development/pallet-testing/storage-testing.rs' +#[test] +fn set_counter_value_requires_root() { + new_test_ext().execute_with(|| { + let alice = 1u64; + + // When: non-root user tries to set counter + // Then: should fail with BadOrigin + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(alice), 100), + DispatchError::BadOrigin + ); + + // But root should succeed + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); + }); +} ``` -### Event Testing +Test access control: + +```bash +cargo test --package pallet-custom set_counter_value_requires_root +``` + +## Test Event Emission + +Verify that events are emitted correctly with the right data. + +### Test Event Data -It's also crucial to test the events that your pallet emits during execution. By default, events generated in a pallet using the [`#generate_deposit`](https://paritytech.github.io/polkadot-sdk/master/frame_support/pallet_macros/attr.generate_deposit.html){target=\_blank} macro are stored under the system's event storage key (system/events) as [`EventRecord`](https://paritytech.github.io/polkadot-sdk/master/frame_system/struct.EventRecord.html){target=\_blank} entries. These can be accessed using [`System::events()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.events){target=\_blank} or verified with specific helper methods provided by the system pallet, such as [`assert_has_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_has_event){target=\_blank} and [`assert_last_event`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.assert_last_event){target=\_blank}. +The [`increment_works`](/parachains/customize-runtime/pallet-development/pallet-testing/#test-basic-increment) test (shown earlier) already demonstrates event testing by: -Here's an example of testing events in a mock runtime: +1. Setting the block number to 1 to enable event emission. +2. Calling the dispatchable function. +3. Using `System::assert_last_event()` to verify the correct event was emitted with expected data. + +This pattern applies to all dispatchables that emit events. For a dedicated event-only test focusing on the `set_counter_value` function: + +Test that set_counter_value updates storage and emits correct event. ```rust ---8<-- 'code/parachains/customize-runtime/pallet-development/pallet-testing/event-testing.rs' +#[test] +fn set_counter_value_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); + + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); + }); +} ``` -Some key considerations are: +Run the event test: -- **Block number**: Events are not emitted on the genesis block, so you need to set the block number using [`System::set_block_number()`](https://paritytech.github.io/polkadot-sdk/master/frame_system/pallet/struct.Pallet.html#method.set_block_number){target=\_blank} to ensure events are triggered. -- **Converting events**: Use `.into()` when instantiating your pallet's event to convert it into a generic event type, as required by the system's event storage. +```bash +cargo test --package pallet-custom set_counter_value_works +``` -## Where to Go Next +## Test Genesis Configuration + +Verify that genesis configuration works correctly. + +### Test Genesis Setup + +Test that genesis configuration correctly initializes counter and user interactions. + +```rust +#[test] +fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); +} +``` -- Dive into the full implementation of the [`mock.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/mock.rs){target=\_blank} and [`test.rs`](https://github.com/paritytech/polkadot-sdk/blob/master/templates/solochain/pallets/template/src/tests.rs){target=\_blank} files in the [Solochain Template](https://github.com/paritytech/polkadot-sdk/tree/master/templates/solochain){target=_blank}. +Test genesis configuration: + +```bash +cargo test --package pallet-custom genesis_config_works +``` + +## Run All Tests + +Now run all your tests together: + +```bash +cargo test --package pallet-custom +``` + +You should see all tests passing: + +
+ $ cargo test --package pallet-custom + running 15 tests + test mock::__construct_runtime_integrity_test::runtime_integrity_tests ... ok + test mock::test_genesis_config_builds ... ok + test tests::decrement_fails_on_underflow ... ok + test tests::decrement_tracks_multiple_interactions ... ok + test tests::decrement_works ... ok + test tests::different_users_tracked_separately ... ok + test tests::genesis_config_works ... ok + test tests::increment_fails_on_overflow ... ok + test tests::increment_respects_max_value ... ok + test tests::increment_tracks_multiple_interactions ... ok + test tests::increment_works ... ok + test tests::mixed_increment_and_decrement_works ... ok + test tests::set_counter_value_requires_root ... ok + test tests::set_counter_value_respects_max_value ... ok + test tests::set_counter_value_works ... ok + + test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +
+ +!!!note "Mock Runtime Tests" + You'll notice 2 additional tests from the `mock` module: + + - `mock::__construct_runtime_integrity_test::runtime_integrity_tests` - Auto-generated test that validates runtime construction + - `mock::test_genesis_config_builds` - Validates that genesis configuration builds correctly + + These tests are automatically generated from your mock runtime setup and help ensure the test environment itself is valid. + +Congratulations! You have a well-tested pallet covering the essential testing patterns! + +These tests demonstrate comprehensive coverage including basic operations, error conditions, access control, event emission, state management, and genesis configuration. As you build more complex pallets, you'll apply these same patterns to test additional functionality. + +??? code "Full Test Suite Code" + Here's the complete `tests.rs` file for quick reference: + + ```rust + use crate::{mock::*, Error, Event}; + use frame::deps::frame_support::{assert_noop, assert_ok}; + use frame::deps::sp_runtime::DispatchError; + + #[test] + fn set_counter_value_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + // Set counter to 100 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 100)); + assert_eq!(crate::CounterValue::::get(), 100); + + // Check event was emitted + System::assert_last_event(Event::CounterValueSet { new_value: 100 }.into()); + }); + } + + #[test] + fn set_counter_value_requires_root() { + new_test_ext().execute_with(|| { + // Attempt to set counter with non-root origin should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(1), 100), + DispatchError::BadOrigin + ); + }); + } + + #[test] + fn set_counter_value_respects_max_value() { + new_test_ext().execute_with(|| { + // Attempt to set counter above max value (1000) should fail + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::root(), 1001), + Error::::CounterMaxValueExceeded + ); + + // Setting to exactly max value should work + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 1000)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn increment_works() { + new_test_ext().execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 1u64; + + // Increment by 50 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 50)); + assert_eq!(crate::CounterValue::::get(), 50); + + // Check event was emitted + System::assert_last_event( + Event::CounterIncremented { + new_value: 50, + who: account, + amount: 50, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } + + #[test] + fn increment_tracks_multiple_interactions() { + new_test_ext().execute_with(|| { + let account = 1u64; + + // Increment multiple times + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 20)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 30)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 60); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn increment_fails_on_overflow() { + new_test_ext_with_counter(u32::MAX).execute_with(|| { + // Attempt to increment when at max u32 should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 1), + Error::::Overflow + ); + }); + } + + #[test] + fn increment_respects_max_value() { + new_test_ext_with_counter(950).execute_with(|| { + // Incrementing past max value (1000) should fail + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 51), + Error::::CounterMaxValueExceeded + ); + + // Incrementing to exactly max value should work + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 50)); + assert_eq!(crate::CounterValue::::get(), 1000); + }); + } + + #[test] + fn decrement_works() { + new_test_ext_with_counter(100).execute_with(|| { + // Set block number to 1 so events are registered + System::set_block_number(1); + + let account = 2u64; + + // Decrement by 30 + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 30)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check event was emitted + System::assert_last_event( + Event::CounterDecremented { + new_value: 70, + who: account, + amount: 30, + } + .into(), + ); + + // Check user interactions were tracked + assert_eq!(crate::UserInteractions::::get(account), 1); + }); + } + + #[test] + fn decrement_fails_on_underflow() { + new_test_ext_with_counter(10).execute_with(|| { + // Attempt to decrement below zero should fail + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 11), + Error::::Underflow + ); + }); + } + + #[test] + fn decrement_tracks_multiple_interactions() { + new_test_ext_with_counter(100).execute_with(|| { + let account = 3u64; + + // Decrement multiple times + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 10)); + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 20)); + + // Check counter value + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 2) + assert_eq!(crate::UserInteractions::::get(account), 2); + }); + } + + #[test] + fn mixed_increment_and_decrement_works() { + new_test_ext_with_counter(50).execute_with(|| { + let account = 4u64; + + // Mix of increment and decrement + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 25)); + assert_eq!(crate::CounterValue::::get(), 75); + + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account), 15)); + assert_eq!(crate::CounterValue::::get(), 60); + + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account), 10)); + assert_eq!(crate::CounterValue::::get(), 70); + + // Check user interactions were tracked (should be 3) + assert_eq!(crate::UserInteractions::::get(account), 3); + }); + } + + #[test] + fn different_users_tracked_separately() { + new_test_ext().execute_with(|| { + let account1 = 1u64; + let account2 = 2u64; + + // User 1 increments + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(account1), 10)); + + // User 2 decrements + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(account2), 5)); + + // Check counter value (10 + 10 - 5 = 15) + assert_eq!(crate::CounterValue::::get(), 15); + + // Check user interactions are tracked separately + assert_eq!(crate::UserInteractions::::get(account1), 2); + assert_eq!(crate::UserInteractions::::get(account2), 1); + }); + } + + #[test] + fn genesis_config_works() { + new_test_ext_with_interactions(42, vec![(1, 5), (2, 10)]).execute_with(|| { + // Check initial counter value + assert_eq!(crate::CounterValue::::get(), 42); + + // Check initial user interactions + assert_eq!(crate::UserInteractions::::get(1), 5); + assert_eq!(crate::UserInteractions::::get(2), 10); + }); + } + ``` + +## Where to Go Next
-- Guide __Benchmarking__ +- Guide __Add Your Custom Pallet to the Runtime__ --- - Explore methods to measure the performance and execution cost of your pallet. + Your pallet is tested and ready! Learn how to integrate it into your runtime. - [:octicons-arrow-right-24: Reference](/develop/parachains/testing/benchmarking) + [:octicons-arrow-right-24: Integrate](/parachains/customize-runtime/pallet-development/add-to-runtime/) -
\ No newline at end of file + diff --git a/parachains/get-started.md b/parachains/get-started.md index a1f2d12fd..19d8f0a11 100644 --- a/parachains/get-started.md +++ b/parachains/get-started.md @@ -48,7 +48,6 @@ Deep dive into creating and managing custom pallets for your parachain. | [Create a Custom Pallet](/parachains/customize-runtime/pallet-development/create-a-pallet/) | Build a pallet from scratch with custom logic | | [Mock Your Runtime](/parachains/customize-runtime/pallet-development/mock-runtime/) | Set up a mock runtime environment for testing | | [Pallet Unit Testing](/parachains/customize-runtime/pallet-development/pallet-testing/) | Write comprehensive tests for your pallet logic | -| [Add Your Custom Pallet to the Runtime](/parachains/customize-runtime/pallet-development/add-pallet-to-runtime/) | Integrate your custom pallet into your parachain runtime | | [Benchmark the Custom Pallet](/parachains/customize-runtime/pallet-development/benchmark-pallet/) | Measure and optimize pallet performance with benchmarking | ## Testing