From 1f42a610af12b772f210070cb06c0e1c21c4399d Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Thu, 2 Jan 2025 08:45:09 -0300 Subject: [PATCH 1/9] wip: benchmarking --- .../pallet-benchmarking/benchmarks.rs | 37 ++++ .../zero-to-hero/pallet-benchmarking/lib.rs | 193 +++++++++++++++++ .../pallet-benchmarking/pallet-cargo.toml | 36 ++++ .../pallet-benchmarking/runtime-cargo.toml | 199 ++++++++++++++++++ .../parachains/zero-to-hero/.pages | 1 + .../zero-to-hero/pallet-benchmarking.md | 80 +++++++ 6 files changed, 546 insertions(+) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml create mode 100644 tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs new file mode 100644 index 000000000..48dbd73eb --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs @@ -0,0 +1,37 @@ +// 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 + +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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs new file mode 100644 index 000000000..72584bbad --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs @@ -0,0 +1,193 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + // Configuration trait for the pallet + #[pallet::config] + pub trait Config: frame_system::Config { + // Defines the event type for the pallet + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + // Defines the maximum value the counter can hold + #[pallet::constant] + type CounterMaxValue: Get; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// The counter value has been set to a new value by Root. + CounterValueSet { + /// The new value set. + counter_value: u32, + }, + /// A user has successfully incremented the counter. + CounterIncremented { + /// The new value set. + counter_value: u32, + /// The account who incremented the counter. + who: T::AccountId, + /// The amount by which the counter was incremented. + incremented_amount: u32, + }, + /// A user has successfully decremented the counter. + CounterDecremented { + /// The new value set. + counter_value: u32, + /// The account who decremented the counter. + who: T::AccountId, + /// The amount by which the counter was decremented. + decremented_amount: u32, + }, + } + + /// Storage for the current value of the counter. + #[pallet::storage] + pub type CounterValue = StorageValue<_, u32>; + + /// Storage map to track the number of interactions performed by each account. + #[pallet::storage] + pub type UserInteractions = StorageMap<_, Twox64Concat, T::AccountId, u32>; + + #[pallet::error] + pub enum Error { + /// The counter value exceeds the maximum allowed value. + CounterValueExceedsMax, + /// The counter value cannot be decremented below zero. + CounterValueBelowZero, + /// Overflow occurred in the counter. + CounterOverflow, + /// Overflow occurred in user interactions. + UserInteractionOverflow, + } + + #[pallet::call] + impl Pallet { + /// Set the value of the counter. + /// + /// The dispatch origin of this call must be _Root_. + /// + /// - `new_value`: The new value to set for the counter. + /// + /// Emits `CounterValueSet` event when successful. + #[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::::CounterValueExceedsMax + ); + + CounterValue::::put(new_value); + + Self::deposit_event(Event::::CounterValueSet { + counter_value: new_value, + }); + + Ok(()) + } + + /// Increment the counter by a specified amount. + /// + /// This function can be called by any signed account. + /// + /// - `amount_to_increment`: The amount by which to increment the counter. + /// + /// Emits `CounterIncremented` event when successful. + #[pallet::call_index(1)] + #[pallet::weight(0)] + pub fn increment(origin: OriginFor, amount_to_increment: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + + let current_value = CounterValue::::get().unwrap_or(0); + + let new_value = current_value + .checked_add(amount_to_increment) + .ok_or(Error::::CounterOverflow)?; + + ensure!( + new_value <= T::CounterMaxValue::get(), + Error::::CounterValueExceedsMax + ); + + CounterValue::::put(new_value); + + UserInteractions::::try_mutate(&who, |interactions| -> Result<_, Error> { + let new_interactions = interactions + .unwrap_or(0) + .checked_add(1) + .ok_or(Error::::UserInteractionOverflow)?; + *interactions = Some(new_interactions); // Store the new value + + Ok(()) + })?; + + Self::deposit_event(Event::::CounterIncremented { + counter_value: new_value, + who, + incremented_amount: amount_to_increment, + }); + + Ok(()) + } + + /// Decrement the counter by a specified amount. + /// + /// This function can be called by any signed account. + /// + /// - `amount_to_decrement`: The amount by which to decrement the counter. + /// + /// Emits `CounterDecremented` event when successful. + #[pallet::call_index(2)] + #[pallet::weight(0)] + pub fn decrement(origin: OriginFor, amount_to_decrement: u32) -> DispatchResult { + let who = ensure_signed(origin)?; + + let current_value = CounterValue::::get().unwrap_or(0); + + let new_value = current_value + .checked_sub(amount_to_decrement) + .ok_or(Error::::CounterValueBelowZero)?; + + CounterValue::::put(new_value); + + UserInteractions::::try_mutate(&who, |interactions| -> Result<_, Error> { + let new_interactions = interactions + .unwrap_or(0) + .checked_add(1) + .ok_or(Error::::UserInteractionOverflow)?; + *interactions = Some(new_interactions); // Store the new value + + Ok(()) + })?; + + Self::deposit_event(Event::::CounterDecremented { + counter_value: new_value, + who, + decremented_amount: amount_to_decrement, + }); + + Ok(()) + } + } +} \ No newline at end of file diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml new file mode 100644 index 000000000..f010864cd --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "custom-pallet" +version = "0.1.0" +license.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true + +[dependencies] +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +frame-support.workspace = true +frame-system.workspace = true +frame-benchmarking.workspace = true + +[dev-dependencies] +sp-core = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-runtime = { workspace = true, default-features = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "frame-benchmarking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml new file mode 100644 index 000000000..6670d8153 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml @@ -0,0 +1,199 @@ +[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] +substrate-wasm-builder = { optional = true, workspace = true, default-features = true } +docify = { workspace = true } + +[dependencies] +codec = { features = ["derive"], workspace = true } +hex-literal = { optional = true, workspace = true, default-features = true } +log = { workspace = true } +scale-info = { features = ["derive"], workspace = true } +smallvec = { workspace = true, default-features = true } +docify = { workspace = true } +serde_json = { workspace = true, default-features = false } +pallet-parachain-template.workspace = true +frame-benchmarking = { optional = true, workspace = true } +frame-executive.workspace = true +frame-metadata-hash-extension.workspace = true +frame-support = { features = ["experimental"], workspace = true } +frame-system.workspace = true +frame-system-benchmarking = { optional = true, workspace = true } +frame-system-rpc-runtime-api.workspace = true +frame-try-runtime = { optional = true, workspace = true } +pallet-aura.workspace = true +pallet-authorship.workspace = true +pallet-balances.workspace = true +pallet-message-queue.workspace = true +pallet-session.workspace = true +pallet-sudo.workspace = true +pallet-timestamp.workspace = true +pallet-transaction-payment.workspace = true +pallet-transaction-payment-rpc-runtime-api.workspace = true +sp-api.workspace = true +sp-block-builder.workspace = true +sp-consensus-aura.workspace = true +sp-core.workspace = true +sp-genesis-builder.workspace = true +sp-inherents.workspace = true +sp-offchain.workspace = true +sp-runtime.workspace = true +sp-session.workspace = true +sp-transaction-pool.workspace = true +sp-version.workspace = true +pallet-xcm.workspace = true +polkadot-parachain-primitives.workspace = true +polkadot-runtime-common.workspace = true +xcm.workspace = true +xcm-builder.workspace = true +xcm-executor.workspace = true +cumulus-pallet-aura-ext.workspace = true +cumulus-pallet-parachain-system.workspace = true +cumulus-pallet-session-benchmarking.workspace = true +cumulus-pallet-xcm.workspace = true +cumulus-pallet-xcmp-queue.workspace = true +cumulus-primitives-aura.workspace = true +cumulus-primitives-core.workspace = true +cumulus-primitives-utility.workspace = true +cumulus-primitives-storage-weight-reclaim.workspace = true +pallet-collator-selection.workspace = true +parachains-common.workspace = true +parachain-info.workspace = true +pallet-utility = { version = "38.0.0", default-features = false } +custom-pallet = { path = "../pallets/custom-pallet", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-session-benchmarking/std", + "cumulus-pallet-xcm/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-primitives-aura/std", + "cumulus-primitives-core/std", + "cumulus-primitives-storage-weight-reclaim/std", + "cumulus-primitives-utility/std", + "frame-benchmarking?/std", + "frame-executive/std", + "frame-metadata-hash-extension/std", + "frame-support/std", + "frame-system-benchmarking?/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "frame-try-runtime?/std", + "log/std", + "pallet-aura/std", + "pallet-authorship/std", + "pallet-balances/std", + "pallet-collator-selection/std", + "pallet-message-queue/std", + "pallet-parachain-template/std", + "pallet-session/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-xcm/std", + "parachain-info/std", + "parachains-common/std", + "polkadot-parachain-primitives/std", + "polkadot-runtime-common/std", + "scale-info/std", + "serde_json/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/std", + "sp-core/std", + "sp-genesis-builder/std", + "sp-inherents/std", + "sp-offchain/std", + "sp-runtime/std", + "sp-session/std", + "sp-transaction-pool/std", + "sp-version/std", + "substrate-wasm-builder", + "xcm-builder/std", + "xcm-executor/std", + "xcm/std", + "pallet-utility/std", + "custom-pallet/std", +] + +runtime-benchmarks = [ + "cumulus-pallet-parachain-system/runtime-benchmarks", + "cumulus-pallet-session-benchmarking/runtime-benchmarks", + "cumulus-pallet-xcmp-queue/runtime-benchmarks", + "cumulus-primitives-core/runtime-benchmarks", + "cumulus-primitives-utility/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "hex-literal", + "pallet-balances/runtime-benchmarks", + "pallet-collator-selection/runtime-benchmarks", + "pallet-message-queue/runtime-benchmarks", + "pallet-parachain-template/runtime-benchmarks", + "pallet-sudo/runtime-benchmarks", + "pallet-timestamp/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", + "polkadot-runtime-common/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", + "custom-pallet/runtime-benchmarks", +] + +try-runtime = [ + "cumulus-pallet-aura-ext/try-runtime", + "cumulus-pallet-parachain-system/try-runtime", + "cumulus-pallet-xcm/try-runtime", + "cumulus-pallet-xcmp-queue/try-runtime", + "frame-executive/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-aura/try-runtime", + "pallet-authorship/try-runtime", + "pallet-balances/try-runtime", + "pallet-collator-selection/try-runtime", + "pallet-message-queue/try-runtime", + "pallet-parachain-template/try-runtime", + "pallet-session/try-runtime", + "pallet-sudo/try-runtime", + "pallet-timestamp/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-xcm/try-runtime", + "parachain-info/try-runtime", + "polkadot-runtime-common/try-runtime", + "sp-runtime/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/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages b/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages index f6ac6e1c4..b209fd5cb 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages @@ -4,6 +4,7 @@ nav: - 'Set Up a Template': set-up-a-template.md - 'Build a Custom Pallet': build-custom-pallet.md - 'Pallet Unit Testing': pallet-unit-testing.md + - 'Pallet Benchmarking': pallet-benchmarking.md - 'Add Pallets to the Runtime': add-pallets-to-runtime.md - 'Deploy to Paseo TestNet': deploy-to-testnet.md - 'Obtain Coretime': obtain-coretime.md \ No newline at end of file diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md new file mode 100644 index 000000000..c25f9bea0 --- /dev/null +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -0,0 +1,80 @@ +--- +title: Pallet Benchmarking +description: TODO +--- + +## Introduction + +After implementing and testing your pallet with a mock runtime, the next crucial step is benchmarking. Benchmarking assigns precise [weight](/polkadot-protocol/glossary/#weight){target=\_blank} to each extrinsic, measuring their computational and storage costs. These derived weights enable accurate fee calculation and resource allocation within the runtime. +This tutorial demonstrates how to: + +- Configure your development environment for benchmarking +- Create and implement benchmark tests for your extrinsics +- Apply benchmark results to your pallet's extrinsics + +For comprehensive information about benchmarking concepts, refer to the [Benchmarking](/develop/parachains/testing/benchmarking/){target=\_blank} guide. + +--- + +## Environment Setup + +Follow these steps to prepare your environment for pallet benchmarking: + +1. Install the `frame-omni-bencher` command-line tool: + + ```bash + cargo install frame-omni-bencher + ``` + +2. Update your pallet's `Cargo.toml` file in the `pallets/custom-pallet` directory with the following modifications: + 1. Add the [`frame-benchmarking`](https://docs.rs/frame-benchmarking/latest/frame_benchmarking/){target=\_blank} dependency: + + ```toml hl_lines="3" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:10:10' + ... + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:15:15' + ``` + + 2. Enable benchmarking in the `std` features: + ```toml hl_lines="6" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:24:30' + ``` + + 3. Add the `runtime-benchmarks` feature flag: + ```toml + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:31:36' + ``` + + ??? "View complete `Cargo.toml` file:" + ```toml + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml' + ``` + +3. Add your pallet to the runtime's benchmark configuration: + 1. Register your pallet in `runtime/src/benchmarks.rs`: + ```rust hl_lines="11" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs:26:37' + ``` + + 2. Enable runtime benchmarking for your pallet in `runtime/Cargo.toml`: + ```toml hl_lines="25" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml:136:161' + ``` + +4. Set up the benchmarking module in your pallet: + 1. Create a new `benchmarking.rs` file in your pallet directory: + ```bash + touch benchmarking.rs + ``` + + 2. Add the benchmarking module to your pallet. In the pallet `lib.rs` file add the following: + ```rust hl_lines="9-10" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs:1:12' + ``` + +## Implement Benchmark Tests + + + + + From 2a1486b1e10b682359aa69a74095ac8309267e36 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Fri, 3 Jan 2025 09:49:13 -0300 Subject: [PATCH 2/9] Add execute benchmarking --- .../pallet-benchmarking/benchmarking.rs | 58 +++++++++++++++++++ .../pallet-benchmarking/pallet-cargo.toml | 4 +- .../zero-to-hero/pallet-benchmarking.md | 58 +++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs new file mode 100644 index 000000000..880be495e --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs @@ -0,0 +1,58 @@ +//! Benchmarking setup for pallet-template +#![cfg(feature = "runtime-benchmarks")] + +use super::{Pallet as CustomPallet, *}; +use frame_benchmarking::v2::*; +use frame_support::assert_ok; + +#[benchmarks] +mod benchmarks { + use super::*; + #[cfg(test)] + use crate::pallet::Pallet as CustomPallet; + use frame_system::RawOrigin; + + #[benchmark] + fn set_counter_value() { + let caller: T::AccountId = whitelisted_caller(); + + #[extrinsic_call] + set_counter_value(RawOrigin::Root, 5); + + assert_eq!(CounterValue::::get(), Some(5u32.into())); + } + + #[benchmark] + fn increment() { + let caller: T::AccountId = whitelisted_caller(); + + assert_ok!(CustomPallet::::set_counter_value( + RawOrigin::Root.into(), + 5u32 + )); + + #[extrinsic_call] + increment(RawOrigin::Signed(caller.clone()), 1); + + assert_eq!(CounterValue::::get(), Some(6u32.into())); + assert_eq!(UserInteractions::::get(caller), 1u32.into()); + } + + #[benchmark] + fn decrement() { + let caller: T::AccountId = whitelisted_caller(); + + assert_ok!(CustomPallet::::set_counter_value( + RawOrigin::Root.into(), + 5u32 + )); + + #[extrinsic_call] + decrement(RawOrigin::Signed(caller.clone()), 1); + + assert_eq!(CounterValue::::get(), Some(4u32.into())); + assert_eq!(UserInteractions::::get(caller), 1u32.into()); + } + + impl_benchmark_test_suite!(CustomPallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml index f010864cd..333c4d512 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml @@ -12,7 +12,7 @@ codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } frame-support.workspace = true frame-system.workspace = true -frame-benchmarking.workspace = true +frame-benchmarking = { optional = true, workspace = true } [dev-dependencies] sp-core = { workspace = true, default-features = true } @@ -26,7 +26,7 @@ std = [ "frame-support/std", "frame-system/std", "scale-info/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index c25f9bea0..4cf100382 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -74,7 +74,65 @@ Follow these steps to prepare your environment for pallet benchmarking: ## Implement Benchmark Tests +When writing benchmarking tests for your pallet, you'll create specialized test functions for each extrinsic, similar to unit tests. These tests use the mock runtime you created earlier for testing, allowing you to leverage its utility functions. +Every benchmark test must follow a three-step pattern: +1. **Setup** - perform any necessary setup before calling the extrinsic. This might include creating accounts, setting initial states, or preparing test data +2. **Execute the extrinsic** - execute the actual extrinsic using the `#[extrinsic_call]` macro. This must be a single line that calls your extrinsic function with the origin as its first argument +3. **Verification** - check that the extrinsic worked correctly within the benchmark context by checking the expected state changes +Check the following example on how to benchmark the `set_counter_value` extrinsic: + +```rust +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs:15:23' +``` + +Now, implement the complete set of benchmark tests. Copy the following content in the `benchmarking.rs` file: + +```rust +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs' +``` + +!!!note + The `#[benchmark]` macro marks these functions as benchmark tests, while the `#[extrinsic_call]` macro specifically identifies which line contains the extrinsic being measured. For more information check the [frame_benchmarking](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\_blank} rust docs. + +## Execute the Benchmarking + +After you set up your environment and implemented the benchmarking test suit, you have to execute them. To do that, follow these steps: + +1. Build your runtime again, but this time with the feature `runtime-benchmarks` enabled: + + ```bash + cargo build --features runtime-benchmarks --release + ``` + +2. Create a `weights.rs` file in your pallet's `src/` dir: + + ```bash + touch weights.rs + ``` + +3. Before executing the benchmarking cli, you will need to download a template file that will help you autogenerate the weights for your extrinsics. Execute the following command: + + ```bash + mkdir ./pallets/benchmarking && \ + curl https://raw.githubusercontent.com/paritytech/polkadot-sdk/refs/tags/polkadot-stable2412/substrate/.maintain/frame-weight-template.hbs \ + --output ./pallets/benchmarking/frame-weight-template.hbs + ``` + +4. Run the benchmarking cli: + + ```bash + frame-omni-bencher v1 benchmark pallet \ + --runtime target/release/wbuild/parachain-template-runtime/parachain_template_runtime.compact.compressed.wasm \ + --pallet "custom_pallet" \ + --extrinsic "" \ + --template ./pallets/benchmarking/frame-weight-template.hbs \ + --output ./pallets/custom-pallet/src/weights.rs + ``` + +After that, the `weights.rs` file should have the autogenerated code with the necessary information to be added to the extrinsics. + +## Add Benchmarking Weights to the Pallet From 4d29ad8ee745ecdb7817cd6b71777f8d6d015267 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Fri, 3 Jan 2025 11:05:51 -0300 Subject: [PATCH 3/9] Pallet benchmarking ready --- .../zero-to-hero/pallet-benchmarking/lib.rs | 14 +- .../zero-to-hero/pallet-benchmarking/mock.rs | 53 +++ .../zero-to-hero/pallet-benchmarking/mod.rs | 332 ++++++++++++++++++ .../zero-to-hero/pallet-benchmarking.md | 78 +++- 4 files changed, 467 insertions(+), 10 deletions(-) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs index 72584bbad..204c38bd1 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs @@ -11,6 +11,9 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod weights; +use crate::weights::WeightInfo; + #[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; @@ -29,6 +32,9 @@ pub mod pallet { // Defines the maximum value the counter can hold #[pallet::constant] type CounterMaxValue: Get; + + /// A type representing the weights required by the dispatchables of this pallet. + type WeightInfo: WeightInfo; } #[pallet::event] @@ -89,7 +95,7 @@ pub mod pallet { /// /// Emits `CounterValueSet` event when successful. #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::set_counter_value())] pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { ensure_root(origin)?; @@ -115,7 +121,7 @@ pub mod pallet { /// /// Emits `CounterIncremented` event when successful. #[pallet::call_index(1)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::increment())] pub fn increment(origin: OriginFor, amount_to_increment: u32) -> DispatchResult { let who = ensure_signed(origin)?; @@ -159,7 +165,7 @@ pub mod pallet { /// /// Emits `CounterDecremented` event when successful. #[pallet::call_index(2)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::decrement())] pub fn decrement(origin: OriginFor, amount_to_decrement: u32) -> DispatchResult { let who = ensure_signed(origin)?; @@ -190,4 +196,4 @@ pub mod pallet { Ok(()) } } -} \ No newline at end of file +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs new file mode 100644 index 000000000..98ac7c05f --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs @@ -0,0 +1,53 @@ +use crate as custom_pallet; +use frame_support::{derive_impl, parameter_types}; +use sp_runtime::BuildStorage; + +type Block = frame_system::mocking::MockBlock; + +#[frame_support::runtime] +mod runtime { + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Test; + + #[runtime::pallet_index(0)] + pub type System = frame_system::Pallet; + + #[runtime::pallet_index(1)] + pub type CustomPallet = custom_pallet::Pallet; +} + +// System pallet configuration +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type Block = Block; +} + +// Custom pallet configuration +parameter_types! { + pub const CounterMaxValue: u32 = 10; +} + +impl custom_pallet::Config for Test { + type RuntimeEvent = RuntimeEvent; + type CounterMaxValue = CounterMaxValue; + type WeightInfo = custom_pallet::weights::SubstrateWeight; +} + +// Test externalities initialization +pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::::default() + .build_storage() + .unwrap() + .into() +} \ No newline at end of file diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs new file mode 100644 index 000000000..00170db05 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs @@ -0,0 +1,332 @@ +// 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; + +// 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 OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +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; +} + +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>; +} + +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; +} + +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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index 4cf100382..54eacea5c 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -99,21 +99,23 @@ Now, implement the complete set of benchmark tests. Copy the following content i ## Execute the Benchmarking -After you set up your environment and implemented the benchmarking test suit, you have to execute them. To do that, follow these steps: +After implementing your benchmark test suite, you'll need to execute the tests and generate the weights for your extrinsics. This process involves building your runtime with benchmarking features enabled and using the `frame-omni-bencher` CLI tool. To do that, follow these steps: -1. Build your runtime again, but this time with the feature `runtime-benchmarks` enabled: +1. Build your runtime with the `runtime-benchmarks` feature enabled: ```bash cargo build --features runtime-benchmarks --release ``` -2. Create a `weights.rs` file in your pallet's `src/` dir: + This special build includes all the necessary benchmarking code that's normally excluded from production builds. + +2. Create a `weights.rs` file in your pallet's `src/` directory. This file will store the auto-generated weight calculations: ```bash touch weights.rs ``` -3. Before executing the benchmarking cli, you will need to download a template file that will help you autogenerate the weights for your extrinsics. Execute the following command: +3. Before running the benchmarking tool, you'll need a template file that defines how weight information should be formatted. Download the official template from the Polkadot SDK repository: ```bash mkdir ./pallets/benchmarking && \ @@ -121,7 +123,7 @@ After you set up your environment and implemented the benchmarking test suit, yo --output ./pallets/benchmarking/frame-weight-template.hbs ``` -4. Run the benchmarking cli: +4. Execute the benchmarking process using the `frame-omni-bencher` CLI: ```bash frame-omni-bencher v1 benchmark pallet \ @@ -132,7 +134,71 @@ After you set up your environment and implemented the benchmarking test suit, yo --output ./pallets/custom-pallet/src/weights.rs ``` -After that, the `weights.rs` file should have the autogenerated code with the necessary information to be added to the extrinsics. +When the benchmarking process completes, your `weights.rs` file will contain auto-generated code with weight calculations for each of your pallet's extrinsics. These weights help ensure fair and accurate fee calculations when your pallet is used in a production environment. ## Add Benchmarking Weights to the Pallet +After generating the weight calculations, you need to integrate these weights into your pallet's code. This integration ensures your pallet properly accounts for computational costs in its extrinsics. + +First, add the necessary module imports to your pallet. These imports make the weights available to your code: + +```rust hl_lines="4-5" +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs:11:15' +``` + +Next, update your pallet's `Config` trait to include weight information. Define the `WeightInfo` type: + +```rust hl_lines="11-12" +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs:26:38' +``` + +Now you can assign weights to your extrinsics. Here's how to add weight calculations to the `set_counter_value` function: + +```rust hl_lines="2" +#[pallet::call_index(0)] +#[pallet::weight(T::WeightInfo::set_counter_value())] +pub fn set_counter_value(origin: OriginFor, new_value: u32) -> DispatchResult { + ensure_root(origin)?; + + ensure!( + new_value <= T::CounterMaxValue::get(), + Error::::CounterValueExceedsMax + ); + + CounterValue::::put(new_value); + + Self::deposit_event(Event::::CounterValueSet { + counter_value: new_value, + }); + + Ok(()) +} +``` + +For testing purposes, you need to implement the weight calculations in your mock runtime. Open `custom-pallet/src/mock.rs` and add: + +```rust hl_lines="4" +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs:41:45' +``` + +Finally, configure the actual weight values in your production runtime. In `runtime/src/config/mod.rs`, add: + +```rust hl_lines="5" +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs:327:332' +``` + +Your pallet is now complete with full testing and benchmarking support, ready for production use. + +## Where to Go Next + +
+ +- Tutorial __Add Pallets to the Runtime__ + + --- + + Enhance your runtime with custom functionality! Learn how to add, configure, and integrate pallets in Polkadot SDK-based blockchains. + + [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime/) + +
\ No newline at end of file From ce9c9a8742f512cec7bcb827a68a3ccf1e46fe21 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Fri, 3 Jan 2025 11:12:02 -0300 Subject: [PATCH 4/9] Update description --- .../parachains/zero-to-hero/pallet-benchmarking.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index 54eacea5c..e4fafe011 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -1,11 +1,12 @@ --- title: Pallet Benchmarking -description: TODO +description: Learn how to benchmark Polkadot SDK-based pallets, assigning precise weights to extrinsics for accurate fee calculation and runtime optimization. --- ## Introduction -After implementing and testing your pallet with a mock runtime, the next crucial step is benchmarking. Benchmarking assigns precise [weight](/polkadot-protocol/glossary/#weight){target=\_blank} to each extrinsic, measuring their computational and storage costs. These derived weights enable accurate fee calculation and resource allocation within the runtime. +After implementing and testing your pallet with a mock runtime in the [Pallet Unit Testing +](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank} tutorial, the next crucial step is benchmarking. Benchmarking assigns precise [weight](/polkadot-protocol/glossary/#weight){target=\_blank} to each extrinsic, measuring their computational and storage costs. These derived weights enable accurate fee calculation and resource allocation within the runtime. This tutorial demonstrates how to: - Configure your development environment for benchmarking From fecd95faf9ed4801d3b2a38f3e9b546063f1497c Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Fri, 3 Jan 2025 11:14:26 -0300 Subject: [PATCH 5/9] Update where to go next from Pallet Testing --- .../parachains/zero-to-hero/pallet-unit-testing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing.md index 936026d7a..2c0d36512 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing.md @@ -163,12 +163,12 @@ After running the test suite, you should see the following output in your termin
-- Tutorial __Add Pallets to the Runtime__ +- Tutorial __Pallet Benchmarking__ --- - Enhance your runtime with custom functionality! Learn how to add, configure, and integrate pallets in Polkadot SDK-based blockchains. + 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/add-pallets-to-runtime/) + [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/)
\ No newline at end of file From cd28b805d59f0a699d207fa9044522132f1f3c22 Mon Sep 17 00:00:00 2001 From: 0xLucca <95830307+0xLucca@users.noreply.github.com> Date: Wed, 8 Jan 2025 08:57:20 -0300 Subject: [PATCH 6/9] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nicolás Hussein <80422357+nhussein11@users.noreply.github.com> --- .../parachains/zero-to-hero/pallet-benchmarking.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index e4fafe011..659d5d72f 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -7,6 +7,7 @@ description: Learn how to benchmark Polkadot SDK-based pallets, assigning precis After implementing and testing your pallet with a mock runtime in the [Pallet Unit Testing ](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank} tutorial, the next crucial step is benchmarking. Benchmarking assigns precise [weight](/polkadot-protocol/glossary/#weight){target=\_blank} to each extrinsic, measuring their computational and storage costs. These derived weights enable accurate fee calculation and resource allocation within the runtime. + This tutorial demonstrates how to: - Configure your development environment for benchmarking @@ -21,7 +22,7 @@ For comprehensive information about benchmarking concepts, refer to the [Benchma Follow these steps to prepare your environment for pallet benchmarking: -1. Install the `frame-omni-bencher` command-line tool: +1. Install the [`frame-omni-bencher`](https://crates.io/crates/frame-omni-bencher){target=\_blank} command-line tool: ```bash cargo install frame-omni-bencher @@ -51,7 +52,7 @@ Follow these steps to prepare your environment for pallet benchmarking: --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml' ``` -3. Add your pallet to the runtime's benchmark configuration: +3. Add your pallet to the runtime's benchmarks configuration: 1. Register your pallet in `runtime/src/benchmarks.rs`: ```rust hl_lines="11" --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs:26:37' @@ -80,7 +81,7 @@ When writing benchmarking tests for your pallet, you'll create specialized test Every benchmark test must follow a three-step pattern: 1. **Setup** - perform any necessary setup before calling the extrinsic. This might include creating accounts, setting initial states, or preparing test data -2. **Execute the extrinsic** - execute the actual extrinsic using the `#[extrinsic_call]` macro. This must be a single line that calls your extrinsic function with the origin as its first argument +2. **Execute the extrinsic** - execute the actual extrinsic using the [`#[extrinsic_call]`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/attr.extrinsic_call.html){target=\_blank} macro. This must be a single line that calls your extrinsic function with the origin as its first argument 3. **Verification** - check that the extrinsic worked correctly within the benchmark context by checking the expected state changes Check the following example on how to benchmark the `set_counter_value` extrinsic: @@ -96,7 +97,7 @@ Now, implement the complete set of benchmark tests. Copy the following content i ``` !!!note - The `#[benchmark]` macro marks these functions as benchmark tests, while the `#[extrinsic_call]` macro specifically identifies which line contains the extrinsic being measured. For more information check the [frame_benchmarking](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\_blank} rust docs. + The [`#[benchmark]`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/attr.benchmark.html){target=\_blank} macro marks these functions as benchmark tests, while the `#[extrinsic_call]` macro specifically identifies which line contains the extrinsic being measured. For more information check the [frame_benchmarking](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\_blank} rust docs. ## Execute the Benchmarking @@ -116,7 +117,7 @@ After implementing your benchmark test suite, you'll need to execute the tests a touch weights.rs ``` -3. Before running the benchmarking tool, you'll need a template file that defines how weight information should be formatted. Download the official template from the Polkadot SDK repository: +3. Before running the benchmarking tool, you'll need a template file that defines how weight information should be formatted. Download the official template from the Polkadot SDK repository and save it in your project folders for future use: ```bash mkdir ./pallets/benchmarking && \ From 165cbc1c9cc88467ba7c73133375b65d354512d5 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Wed, 8 Jan 2025 08:55:00 -0300 Subject: [PATCH 7/9] Apply suggestions --- .../parachains/zero-to-hero/pallet-benchmarking.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index 659d5d72f..e3b318a41 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -16,8 +16,6 @@ This tutorial demonstrates how to: For comprehensive information about benchmarking concepts, refer to the [Benchmarking](/develop/parachains/testing/benchmarking/){target=\_blank} guide. ---- - ## Environment Setup Follow these steps to prepare your environment for pallet benchmarking: @@ -43,16 +41,13 @@ Follow these steps to prepare your environment for pallet benchmarking: ``` 3. Add the `runtime-benchmarks` feature flag: - ```toml + ```toml hl_lines="3-8" + --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:22:22' + ... --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml:31:36' ``` - ??? "View complete `Cargo.toml` file:" - ```toml - --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml' - ``` - -3. Add your pallet to the runtime's benchmarks configuration: +3. Add your pallet to the runtime's benchmark configuration: 1. Register your pallet in `runtime/src/benchmarks.rs`: ```rust hl_lines="11" --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs:26:37' From e241b117c163b466564a41f69267c49ff355b0d6 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Wed, 8 Jan 2025 09:11:51 -0300 Subject: [PATCH 8/9] Apply suggestions --- .../pallet-benchmarking/benchmarking.rs | 2 -- .../zero-to-hero/pallet-benchmarking.md | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs index 880be495e..4951522cf 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs @@ -14,8 +14,6 @@ mod benchmarks { #[benchmark] fn set_counter_value() { - let caller: T::AccountId = whitelisted_caller(); - #[extrinsic_call] set_counter_value(RawOrigin::Root, 5); diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index e3b318a41..a0425d982 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -69,6 +69,9 @@ Follow these steps to prepare your environment for pallet benchmarking: --8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs:1:12' ``` + !!!note + The `benchmarking` module is gated behind the `runtime-benchmarks` feature flag. It will only be compiled when this flag is explicitly enabled in your project's `Cargo.toml` or via the `--features runtime-benchmarks` compilation flag. + ## Implement Benchmark Tests When writing benchmarking tests for your pallet, you'll create specialized test functions for each extrinsic, similar to unit tests. These tests use the mock runtime you created earlier for testing, allowing you to leverage its utility functions. @@ -79,12 +82,20 @@ Every benchmark test must follow a three-step pattern: 2. **Execute the extrinsic** - execute the actual extrinsic using the [`#[extrinsic_call]`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/attr.extrinsic_call.html){target=\_blank} macro. This must be a single line that calls your extrinsic function with the origin as its first argument 3. **Verification** - check that the extrinsic worked correctly within the benchmark context by checking the expected state changes -Check the following example on how to benchmark the `set_counter_value` extrinsic: +Check the following example on how to benchmark the `increment` extrinsic: ```rust ---8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs:15:23' +--8<-- 'code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs:23:37' ``` +This benchmark test: + +1. Creates a whitelisted caller and sets an initial counter value of 5 +2. Calls the increment extrinsic to increase the counter by 1 +3. Verifies that the counter was properly incremented to 6 and that the user's interaction was recorded in storage + +This example demonstrates how to properly set up state, execute an extrinsic, and verify its effects during benchmarking. + Now, implement the complete set of benchmark tests. Copy the following content in the `benchmarking.rs` file: ```rust From 68a1697ab4e447a033c918992fe83cabbe179e4a Mon Sep 17 00:00:00 2001 From: 0xLucca <95830307+0xLucca@users.noreply.github.com> Date: Wed, 8 Jan 2025 20:30:00 -0300 Subject: [PATCH 9/9] Apply suggestions from code review Co-authored-by: Erin Shaben --- .../parachains/zero-to-hero/pallet-benchmarking/lib.rs | 10 +++++----- .../zero-to-hero/pallet-benchmarking/mock.rs | 4 ++-- .../parachains/zero-to-hero/pallet-benchmarking/mod.rs | 8 ++++---- .../parachains/zero-to-hero/pallet-benchmarking.md | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs index 204c38bd1..7405ce1d5 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/lib.rs @@ -23,13 +23,13 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); - // Configuration trait for the pallet + // Configuration trait for the pallet. #[pallet::config] pub trait Config: frame_system::Config { - // Defines the event type for the pallet + // Defines the event type for the pallet. type RuntimeEvent: From> + IsType<::RuntimeEvent>; - // Defines the maximum value the counter can hold + // Defines the maximum value the counter can hold. #[pallet::constant] type CounterMaxValue: Get; @@ -143,7 +143,7 @@ pub mod pallet { .unwrap_or(0) .checked_add(1) .ok_or(Error::::UserInteractionOverflow)?; - *interactions = Some(new_interactions); // Store the new value + *interactions = Some(new_interactions); // Store the new value. Ok(()) })?; @@ -182,7 +182,7 @@ pub mod pallet { .unwrap_or(0) .checked_add(1) .ok_or(Error::::UserInteractionOverflow)?; - *interactions = Some(new_interactions); // Store the new value + *interactions = Some(new_interactions); // Store the new value. Ok(()) })?; diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs index 98ac7c05f..47f8e1cc8 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs @@ -33,7 +33,7 @@ impl frame_system::Config for Test { type Block = Block; } -// Custom pallet configuration +// Custom pallet configuration. parameter_types! { pub const CounterMaxValue: u32 = 10; } @@ -44,7 +44,7 @@ impl custom_pallet::Config for Test { type WeightInfo = custom_pallet::weights::SubstrateWeight; } -// Test externalities initialization +// Test externalities initialization. pub fn new_test_ext() -> sp_io::TestExternalities { frame_system::GenesisConfig::::default() .build_storage() diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs index 00170db05..fed958422 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs @@ -297,7 +297,7 @@ impl pallet_collator_selection::Config for Runtime { type MaxCandidates = ConstU32<100>; type MinEligibleCollators = ConstU32<4>; type MaxInvulnerables = ConstU32<20>; - // should be a multiple of session or things will get inconsistent + // Should be a multiple of session or things will get inconsistent. type KickThreshold = Period; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_collator_selection::IdentityCollator; @@ -311,7 +311,7 @@ impl pallet_parachain_template::Config for Runtime { type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; } -// Configure utility pallet +// Configure utility pallet. impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -319,12 +319,12 @@ impl pallet_utility::Config for Runtime { type WeightInfo = pallet_utility::weights::SubstrateWeight; } -// Define counter max value runtime constant +// Define counter max value runtime constant. parameter_types! { pub const CounterMaxValue: u32 = 500; } -// Configure custom pallet +// Configure custom pallet. impl custom_pallet::Config for Runtime { type RuntimeEvent = RuntimeEvent; type CounterMaxValue = CounterMaxValue; diff --git a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index a0425d982..deabfdeca 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -103,7 +103,7 @@ Now, implement the complete set of benchmark tests. Copy the following content i ``` !!!note - The [`#[benchmark]`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/attr.benchmark.html){target=\_blank} macro marks these functions as benchmark tests, while the `#[extrinsic_call]` macro specifically identifies which line contains the extrinsic being measured. For more information check the [frame_benchmarking](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\_blank} rust docs. + The [`#[benchmark]`](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/attr.benchmark.html){target=\_blank} macro marks these functions as benchmark tests, while the `#[extrinsic_call]` macro specifically identifies which line contains the extrinsic being measured. For more information, check the [frame_benchmarking](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=\_blank} Rust docs. ## Execute the Benchmarking