From e15079f654abf1e5550ef21d2e4bda0deceecc46 Mon Sep 17 00:00:00 2001 From: 0xLucca <0xlucca.dev@gmail.com> Date: Thu, 9 Jan 2025 12:33:56 -0300 Subject: [PATCH] Update pallet-benchmarking --- .snippets/code/Cargo.lock | 91 +++++ .snippets/code/Cargo.toml | 1 + .../custom-pallet/Cargo.toml} | 0 .../custom-pallet/src}/benchmarking.rs | 0 .../pallets/custom-pallet/src/lib.rs | 199 +++++++++++ .../{ => pallets/custom-pallet/src}/mock.rs | 13 +- .../pallets/custom-pallet/src/tests.rs | 157 +++++++++ .../pallets/custom-pallet/src/weights.rs | 120 +++++++ .../pallets/template/Cargo.toml | 49 +++ .../pallets/template/README.md | 5 + .../pallets/template/src/benchmarking.rs | 34 ++ .../pallets/template/src/lib.rs | 186 ++++++++++ .../pallets/template/src/mock.rs | 44 +++ .../pallets/template/src/tests.rs | 23 ++ .../pallets/template/src/weights.rs | 90 +++++ .../Cargo.toml} | 4 +- .../pallet-benchmarking/runtime/build.rs | 17 + .../pallet-benchmarking/runtime/src/apis.rs | 305 +++++++++++++++++ .../{ => runtime/src}/benchmarks.rs | 0 .../{ => runtime/src/configs}/mod.rs | 0 .../runtime/src/configs/xcm_config.rs | 193 +++++++++++ .../runtime/src/genesis_config_presets.rs | 151 ++++++++ .../pallet-benchmarking/runtime/src/lib.rs | 323 ++++++++++++++++++ .../runtime/src/weights/block_weights.rs | 53 +++ .../runtime/src/weights/extrinsic_weights.rs | 53 +++ .../runtime/src/weights/mod.rs | 27 ++ .../runtime/src/weights/paritydb_weights.rs | 63 ++++ .../runtime/src/weights/rocksdb_weights.rs | 63 ++++ .../parachains/zero-to-hero/.pages | 2 +- .../zero-to-hero/add-pallets-to-runtime.md | 8 + .../zero-to-hero/pallet-benchmarking.md | 9 +- .../zero-to-hero/pallet-unit-testing.md | 6 +- 32 files changed, 2271 insertions(+), 18 deletions(-) rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{pallet-cargo.toml => pallets/custom-pallet/Cargo.toml} (100%) rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{ => pallets/custom-pallet/src}/benchmarking.rs (100%) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/lib.rs rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{ => pallets/custom-pallet/src}/mock.rs (80%) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/tests.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/weights.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/Cargo.toml create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/README.md create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/benchmarking.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/lib.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/mock.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/tests.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/weights.rs rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{runtime-cargo.toml => runtime/Cargo.toml} (97%) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/build.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/apis.rs rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{ => runtime/src}/benchmarks.rs (100%) rename .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/{ => runtime/src/configs}/mod.rs (100%) create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/configs/xcm_config.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/genesis_config_presets.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/lib.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/block_weights.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/extrinsic_weights.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/mod.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/paritydb_weights.rs create mode 100644 .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/rocksdb_weights.rs diff --git a/.snippets/code/Cargo.lock b/.snippets/code/Cargo.lock index 2df3be64f..8e05f49ac 100644 --- a/.snippets/code/Cargo.lock +++ b/.snippets/code/Cargo.lock @@ -1042,6 +1042,20 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "custom-pallet" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "custom-pallet-0" version = "0.1.0" @@ -3146,6 +3160,20 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "pallet-parachain-template-1" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", +] + [[package]] name = "pallet-session" version = "38.0.0" @@ -3403,6 +3431,69 @@ dependencies = [ "substrate-wasm-builder", ] +[[package]] +name = "parachain-template-runtime-1" +version = "0.1.0" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-parachain-system", + "cumulus-pallet-session-benchmarking", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-aura", + "cumulus-primitives-core", + "cumulus-primitives-storage-weight-reclaim", + "cumulus-primitives-utility", + "custom-pallet", + "docify", + "frame-benchmarking", + "frame-executive", + "frame-metadata-hash-extension", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal", + "log", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "pallet-message-queue", + "pallet-parachain-template-1", + "pallet-session", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "scale-info", + "serde_json", + "smallvec", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-genesis-builder", + "sp-inherents", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-transaction-pool", + "sp-version", + "staging-parachain-info", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "substrate-wasm-builder", +] + [[package]] name = "parachains-common" version = "18.0.0" diff --git a/.snippets/code/Cargo.toml b/.snippets/code/Cargo.toml index 6e621fd4d..91e404ff0 100644 --- a/.snippets/code/Cargo.toml +++ b/.snippets/code/Cargo.toml @@ -14,6 +14,7 @@ members = [ "tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet", "tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing", "tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime/runtime", + "tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime", ] resolver = "2" 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/pallets/custom-pallet/Cargo.toml similarity index 100% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallet-cargo.toml rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/Cargo.toml 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/pallets/custom-pallet/src/benchmarking.rs similarity index 100% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarking.rs rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/benchmarking.rs diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/lib.rs new file mode 100644 index 000000000..7405ce1d5 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/lib.rs @@ -0,0 +1,199 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +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::*; + 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; + + /// A type representing the weights required by the dispatchables of this pallet. + type WeightInfo: WeightInfo; + } + + #[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(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(()) + } + + /// 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(T::WeightInfo::increment())] + 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(T::WeightInfo::decrement())] + 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(()) + } + } +} 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/pallets/custom-pallet/src/mock.rs similarity index 80% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mock.rs rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/mock.rs index 47f8e1cc8..ac39e24cb 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/pallets/custom-pallet/src/mock.rs @@ -1,4 +1,4 @@ -use crate as custom_pallet; +use crate as pallet_custom; use frame_support::{derive_impl, parameter_types}; use sp_runtime::BuildStorage; @@ -22,9 +22,9 @@ mod runtime { #[runtime::pallet_index(0)] pub type System = frame_system::Pallet; - + #[runtime::pallet_index(1)] - pub type CustomPallet = custom_pallet::Pallet; + pub type CustomPallet = pallet_custom::Pallet; } // System pallet configuration @@ -33,18 +33,17 @@ impl frame_system::Config for Test { type Block = Block; } -// Custom pallet configuration. +// Custom pallet configuration parameter_types! { pub const CounterMaxValue: u32 = 10; } -impl custom_pallet::Config for Test { +impl pallet_custom::Config for Test { type RuntimeEvent = RuntimeEvent; type CounterMaxValue = CounterMaxValue; - 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/pallets/custom-pallet/src/tests.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/tests.rs new file mode 100644 index 000000000..00fffdb06 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/tests.rs @@ -0,0 +1,157 @@ +use crate::{mock::*, Error, Event, UserInteractions}; +use frame_support::{assert_noop, assert_ok}; + +// Verify root can successfully set counter value +#[test] +fn it_works_for_set_counter_value() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Set counter value within max allowed (10) + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 5)); + // Ensure that the correct event is emitted when the value is set + System::assert_last_event(Event::CounterValueSet { counter_value: 5 }.into()); + }); +} + +// Ensure non-root accounts cannot set counter value +#[test] +fn set_counter_value_fails_for_non_root() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Ensure only root (privileged account) can set counter value + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::signed(1), 5), // non-root account + sp_runtime::traits::BadOrigin // Expecting a BadOrigin error + ); + }); +} + +// Check that setting value above max is prevented +#[test] +fn set_counter_value_fails_for_max_value_exceeded() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Ensure the counter value cannot be set above the max limit (10) + assert_noop!( + CustomPallet::set_counter_value(RuntimeOrigin::root(), 11), + Error::::CounterValueExceedsMax // Expecting CounterValueExceedsMax error + ); + }); +} + +// Test successful counter increment +#[test] +fn it_works_for_increment() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Initialize the counter value to 0 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 0)); + + // Increment the counter by 5 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 5)); + // Check that the event emitted matches the increment operation + System::assert_last_event(Event::CounterIncremented { + counter_value: 5, + who: 1, + incremented_amount: 5 + }.into()); + }); +} + +// Verify increment is blocked when it would exceed max value +#[test] +fn increment_fails_for_max_value_exceeded() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Set counter value close to max (10) + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 7)); + // Ensure that incrementing by 4 exceeds max value (10) and fails + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 4), + Error::::CounterValueExceedsMax // Expecting CounterValueExceedsMax error + ); + }); +} + +// Ensure increment fails on u32 overflow +#[test] +fn increment_handles_overflow() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Set to max value + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 1)); + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), u32::MAX), + Error::::CounterOverflow + ); + }); +} + +// Test successful counter decrement +#[test] +fn it_works_for_decrement() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Initialize counter value to 8 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 8)); + + // Decrement counter by 3 + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(1), 3)); + // Ensure the event matches the decrement action + System::assert_last_event(Event::CounterDecremented { + counter_value: 5, + who: 1, + decremented_amount: 3 + }.into()); + }); +} + +// Verify decrement is blocked when it would go below zero +#[test] +fn decrement_fails_for_below_zero() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Set counter value to 5 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 5)); + // Ensure that decrementing by 6 fails as it would result in a negative value + assert_noop!( + CustomPallet::decrement(RuntimeOrigin::signed(1), 6), + Error::::CounterValueBelowZero // Expecting CounterValueBelowZero error + ); + }); +} + +// Check that user interactions are correctly tracked +#[test] +fn user_interactions_increment() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Initialize counter value to 0 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 0)); + + // Increment by 5 and decrement by 2 + assert_ok!(CustomPallet::increment(RuntimeOrigin::signed(1), 5)); + assert_ok!(CustomPallet::decrement(RuntimeOrigin::signed(1), 2)); + + // Check if the user interactions are correctly tracked + assert_eq!(UserInteractions::::get(1).unwrap_or(0), 2); // User should have 2 interactions + }); +} + +// Ensure user interactions prevent overflow +#[test] +fn user_interactions_overflow() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + // Initialize counter value to 0 + assert_ok!(CustomPallet::set_counter_value(RuntimeOrigin::root(), 0)); + + // Set user interactions to max value (u32::MAX) + UserInteractions::::insert(1, u32::MAX); + // Ensure that incrementing by 5 fails due to overflow in user interactions + assert_noop!( + CustomPallet::increment(RuntimeOrigin::signed(1), 5), + Error::::UserInteractionOverflow // Expecting UserInteractionOverflow error + ); + }); +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/weights.rs new file mode 100644 index 000000000..ee2931be2 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/custom-pallet/src/weights.rs @@ -0,0 +1,120 @@ + +//! Autogenerated weights for `custom_pallet` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 43.0.0 +//! DATE: 2025-01-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `192.168.1.4`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024` + +// Executed Command: +// 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 + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `custom_pallet`. +pub trait WeightInfo { + fn set_counter_value() -> Weight; + fn increment() -> Weight; + fn decrement() -> Weight; +} + +/// Weights for `custom_pallet` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `CustomPallet::CounterValue` (r:0 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_counter_value() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `CustomPallet::CounterValue` (r:1 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CustomPallet::UserInteractions` (r:1 w:1) + /// Proof: `CustomPallet::UserInteractions` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn increment() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `3534` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3534) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `CustomPallet::CounterValue` (r:1 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CustomPallet::UserInteractions` (r:1 w:1) + /// Proof: `CustomPallet::UserInteractions` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn decrement() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `3534` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `CustomPallet::CounterValue` (r:0 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn set_counter_value() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(5_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: `CustomPallet::CounterValue` (r:1 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CustomPallet::UserInteractions` (r:1 w:1) + /// Proof: `CustomPallet::UserInteractions` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn increment() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `3534` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(12_000_000, 3534) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: `CustomPallet::CounterValue` (r:1 w:1) + /// Proof: `CustomPallet::CounterValue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CustomPallet::UserInteractions` (r:1 w:1) + /// Proof: `CustomPallet::UserInteractions` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn decrement() -> Weight { + // Proof Size summary in bytes: + // Measured: `69` + // Estimated: `3534` + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_000_000, 3534) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/Cargo.toml b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/Cargo.toml new file mode 100644 index 000000000..608e4fd52 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-parachain-template-1" +description = "FRAME pallet template for defining custom runtime logic." +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"] + +[dependencies] +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +frame-benchmarking = { optional = true, workspace = true } +frame-support.workspace = true +frame-system.workspace = true +sp-runtime.workspace = true + +[dev-dependencies] +sp-core = { default-features = true, workspace = true } +sp-io = { default-features = true, workspace = true } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +std = [ + "codec/std", + "scale-info/std", + + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + + "sp-runtime/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/README.md b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/README.md new file mode 100644 index 000000000..96e931ea4 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/README.md @@ -0,0 +1,5 @@ + + +## Release + +Polkadot SDK stable2409 diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/benchmarking.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/benchmarking.rs new file mode 100644 index 000000000..5acad6e60 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/benchmarking.rs @@ -0,0 +1,34 @@ +//! Benchmarking setup for pallet-template +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use frame_benchmarking::v2::*; + +#[benchmarks] +mod benchmarks { + use super::*; + #[cfg(test)] + use crate::pallet::Pallet as Template; + use frame_system::RawOrigin; + + #[benchmark] + fn do_something() { + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + do_something(RawOrigin::Signed(caller), 100); + + assert_eq!(Something::::get().map(|v| v.block_number), Some(100u32.into())); + } + + #[benchmark] + fn cause_error() { + Something::::put(CompositeStruct { block_number: 100u32.into() }); + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + cause_error(RawOrigin::Signed(caller)); + + assert_eq!(Something::::get().map(|v| v.block_number), Some(101u32.into())); + } + + impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/lib.rs new file mode 100644 index 000000000..6bfb98972 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/lib.rs @@ -0,0 +1,186 @@ +//! # Template Pallet +//! +//! A pallet with minimal functionality to help developers understand the essential components of +//! writing a FRAME pallet. It is typically used in beginner tutorials or in Polkadot SDK template +//! as a starting point for creating a new pallet and **not meant to be used in production**. +//! +//! ## Overview +//! +//! This template pallet contains basic examples of: +//! - declaring a storage item that stores a single block-number +//! - declaring and using events +//! - declaring and using errors +//! - a dispatchable function that allows a user to set a new value to storage and emits an event +//! upon success +//! - another dispatchable function that causes a custom error to be thrown +//! +//! Each pallet section is annotated with an attribute using the `#[pallet::...]` procedural macro. +//! This macro generates the necessary code for a pallet to be aggregated into a FRAME runtime. +//! +//! To get started with pallet development, consider using this tutorial: +//! +//! +//! +//! And reading the main documentation of the `frame` crate: +//! +//! +//! +//! And looking at the frame [`kitchen-sink`](https://paritytech.github.io/polkadot-sdk/master/pallet_example_kitchensink/index.html) +//! pallet, a showcase of all pallet macros. +//! +//! ### Pallet Sections +//! +//! The pallet sections in this template are: +//! +//! - A **configuration trait** that defines the types and parameters which the pallet depends on +//! (denoted by the `#[pallet::config]` attribute). See: [`Config`]. +//! - A **means to store pallet-specific data** (denoted by the `#[pallet::storage]` attribute). +//! See: [`storage_types`]. +//! - A **declaration of the events** this pallet emits (denoted by the `#[pallet::event]` +//! attribute). See: [`Event`]. +//! - A **declaration of the errors** that this pallet can throw (denoted by the `#[pallet::error]` +//! attribute). See: [`Error`]. +//! - A **set of dispatchable functions** that define the pallet's functionality (denoted by the +//! `#[pallet::call]` attribute). See: [`dispatchables`]. +//! +//! Run `cargo doc --package pallet-template --open` to view this pallet's documentation. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +// +// +// +// To see a full list of `pallet` macros and their use cases, see: +// +// +#[frame_support::pallet] +pub mod pallet { + use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*, DefaultNoBound}; + use frame_system::pallet_prelude::*; + use sp_runtime::traits::{CheckedAdd, One}; + + /// Configure the pallet by specifying the parameters and types on which it depends. + #[pallet::config] + pub trait Config: frame_system::Config { + /// Because this pallet emits events, it depends on the runtime's definition of an event. + /// + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// A type representing the weights required by the dispatchables of this pallet. + type WeightInfo: crate::weights::WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + /// A struct to store a single block-number. Has all the right derives to store it in storage. + /// + #[derive( + Encode, Decode, MaxEncodedLen, TypeInfo, CloneNoBound, PartialEqNoBound, DefaultNoBound, + )] + #[scale_info(skip_type_params(T))] + pub struct CompositeStruct { + /// A block number. + pub(crate) block_number: BlockNumberFor, + } + + /// The pallet's storage items. + /// + /// + #[pallet::storage] + pub type Something = StorageValue<_, CompositeStruct>; + + /// Pallets use events to inform users when important changes are made. + /// + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// We usually use passive tense for events. + SomethingStored { block_number: BlockNumberFor, who: T::AccountId }, + } + + /// Errors inform users that something went wrong. + /// + #[pallet::error] + pub enum Error { + /// Error names should be descriptive. + NoneValue, + /// Errors should have helpful documentation associated with them. + StorageOverflow, + } + + #[pallet::hooks] + impl Hooks> for Pallet {} + + /// Dispatchable functions allows users to interact with the pallet and invoke state changes. + /// These functions materialize as "extrinsics", which are often compared to transactions. + /// Dispatchable functions must be annotated with a weight and must return a DispatchResult. + /// + #[pallet::call] + impl Pallet { + /// An example dispatchable that takes a singles value as a parameter, writes the value to + /// storage and emits an event. This function must be dispatched by a signed extrinsic. + #[pallet::call_index(0)] + #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))] + pub fn do_something(origin: OriginFor, bn: u32) -> DispatchResultWithPostInfo { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // + let who = ensure_signed(origin)?; + + // Convert the u32 into a block number. This is possible because the set of trait bounds + // defined in [`frame_system::Config::BlockNumber`]. + let block_number: BlockNumberFor = bn.into(); + + // Update storage. + >::put(CompositeStruct { block_number }); + + // Emit an event. + Self::deposit_event(Event::SomethingStored { block_number, who }); + + // Return a successful [`DispatchResultWithPostInfo`] or [`DispatchResult`]. + Ok(().into()) + } + + /// An example dispatchable that may throw a custom error. + #[pallet::call_index(1)] + #[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().reads_writes(1,1))] + pub fn cause_error(origin: OriginFor) -> DispatchResultWithPostInfo { + let _who = ensure_signed(origin)?; + + // Read a value from storage. + match >::get() { + // Return an error if the value has not been set. + None => Err(Error::::NoneValue)?, + Some(mut old) => { + // Increment the value read from storage; will error in the event of overflow. + old.block_number = old + .block_number + .checked_add(&One::one()) + // ^^ equivalent is to: + // .checked_add(&1u32.into()) + // both of which build a `One` instance for the type `BlockNumber`. + .ok_or(Error::::StorageOverflow)?; + // Update the value in storage with the incremented result. + >::put(old); + // Explore how you can rewrite this using + // [`frame_support::storage::StorageValue::mutate`]. + Ok(().into()) + }, + } + } + } +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/mock.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/mock.rs new file mode 100644 index 000000000..46e311759 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/mock.rs @@ -0,0 +1,44 @@ +use frame_support::{derive_impl, weights::constants::RocksDbWeight}; +use frame_system::{mocking::MockBlock, GenesisConfig}; +use sp_runtime::{traits::ConstU64, BuildStorage}; + +// Configure a mock runtime to test the pallet. +#[frame_support::runtime] +mod test_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; + #[runtime::pallet_index(1)] + pub type TemplateModule = crate; +} + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] +impl frame_system::Config for Test { + type Nonce = u64; + type Block = MockBlock; + type BlockHashCount = ConstU64<250>; + type DbWeight = RocksDbWeight; +} + +impl crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + GenesisConfig::::default().build_storage().unwrap().into() +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/tests.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/tests.rs new file mode 100644 index 000000000..a4a41af63 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/tests.rs @@ -0,0 +1,23 @@ +use crate::{mock::*, Error, Something}; +use frame_support::{assert_noop, assert_ok}; + +#[test] +fn it_works_for_default_value() { + new_test_ext().execute_with(|| { + // Dispatch a signed extrinsic. + assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); + // Read pallet storage and assert an expected result. + assert_eq!(Something::::get().map(|v| v.block_number), Some(42)); + }); +} + +#[test] +fn correct_error_for_none_value() { + new_test_ext().execute_with(|| { + // Ensure the expected error is thrown when no value is present. + assert_noop!( + TemplateModule::cause_error(RuntimeOrigin::signed(1)), + Error::::NoneValue + ); + }); +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/weights.rs new file mode 100644 index 000000000..5bfe28e8b --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/pallets/template/src/weights.rs @@ -0,0 +1,90 @@ + +//! Autogenerated weights for pallet_template +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `_`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ../../target/release/node-template +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet_template +// --extrinsic +// * +// --steps=50 +// --repeat=20 +// --wasm-execution=compiled +// --output +// pallets/template/src/weights.rs +// --template +// ../../.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for pallet_template. +pub trait WeightInfo { + fn do_something() -> Weight; + fn cause_error() -> Weight; +} + +/// Weights for pallet_template using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: TemplateModule Something (r:0 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn do_something() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: TemplateModule Something (r:1 w:1) + /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn cause_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `32` + // Estimated: `1489` + // Minimum execution time: 6_000_000 picoseconds. + Weight::from_parts(6_000_000, 1489) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} 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 similarity index 97% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime-cargo.toml rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/Cargo.toml index 6670d8153..ca3501684 100644 --- 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 @@ -1,5 +1,5 @@ [package] -name = "parachain-template-runtime" +name = "parachain-template-runtime-1" description = "A parachain runtime template built with Substrate and Cumulus, part of Polkadot Sdk." version = "0.1.0" license = "Unlicense" @@ -24,7 +24,7 @@ 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 +pallet-parachain-template = { path = "../pallets/template", default-features = false, package = "pallet-parachain-template-1" } frame-benchmarking = { optional = true, workspace = true } frame-executive.workspace = true frame-metadata-hash-extension.workspace = true diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/build.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/build.rs new file mode 100644 index 000000000..4f33752ca --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/build.rs @@ -0,0 +1,17 @@ +#[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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/apis.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/apis.rs new file mode 100644 index 000000000..243db1b6d --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/apis.rs @@ -0,0 +1,305 @@ +// 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 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 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, sp_runtime::RuntimeString> { + 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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/benchmarks.rs similarity index 100% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/benchmarks.rs rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/benchmarks.rs 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/runtime/src/configs/mod.rs similarity index 100% rename from .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/mod.rs rename to .snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/configs/mod.rs diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/configs/xcm_config.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/configs/xcm_config.rs new file mode 100644 index 000000000..e162bcbf8 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/configs/xcm_config.rs @@ -0,0 +1,193 @@ +use crate::{ + AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, + Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, +}; +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 xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, 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< + DenyReserveTransferToRelayChain, + ( + 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; + // 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; +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +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 = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/genesis_config_presets.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/genesis_config_presets.rs new file mode 100644 index 000000000..fec53d173 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/genesis_config_presets.rs @@ -0,0 +1,151 @@ +use cumulus_primitives_core::ParaId; + +use crate::{ + AccountId, BalancesConfig, CollatorSelectionConfig, ParachainInfoConfig, PolkadotXcmConfig, + RuntimeGenesisConfig, SessionConfig, SessionKeys, SudoConfig, EXISTENTIAL_DEPOSIT, +}; +use alloc::{vec, vec::Vec}; +use parachains_common::{genesis_config_helpers::*, AuraId}; +use serde_json::Value; +use sp_core::sr25519; +use sp_genesis_builder::PresetId; + +/// The default XCM version to set in genesis config. +const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; + +/// 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 { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, 1u128 << 60)) + .collect::>(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), + candidacy_bond: EXISTENTIAL_DEPOSIT * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + template_session_keys(aura), // session keys + ) + }) + .collect::>(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + sudo: SudoConfig { key: Some(root) }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +fn local_testnet_genesis() -> Value { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + 1000.into(), + ) +} + +fn development_config_genesis() -> Value { + testnet_genesis( + // initial collators. + vec![ + ( + get_account_id_from_seed::("Alice"), + get_collator_keys_from_seed::("Alice"), + ), + ( + get_account_id_from_seed::("Bob"), + get_collator_keys_from_seed::("Bob"), + ), + ], + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + ], + get_account_id_from_seed::("Alice"), + 1000.into(), + ) +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => local_testnet_genesis(), + Ok(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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/lib.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/lib.rs new file mode 100644 index 000000000..a2a28d6d0 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/lib.rs @@ -0,0 +1,323 @@ +#![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 sp_runtime::{ + create_runtime_str, 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 sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +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 SignedExtension to the basic transaction logic. +#[docify::export(template_signed_extra)] +pub type SignedExtra = ( + 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, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + 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::*; + use sp_runtime::{ + generic, + traits::{BlakeTwo256, Hash as HashT}, + }; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + + /// 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: create_runtime_str!("parachain-template-runtime"), + impl_name: create_runtime_str!("parachain-template-runtime"), + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: apis::RUNTIME_API_VERSIONS, + transaction_version: 1, + state_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 + )] + 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; + + // 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/block_weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/block_weights.rs new file mode 100644 index 000000000..e7fdb2aae --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/block_weights.rs @@ -0,0 +1,53 @@ +// 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 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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/extrinsic_weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/extrinsic_weights.rs new file mode 100644 index 000000000..1a4adb968 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/extrinsic_weights.rs @@ -0,0 +1,53 @@ +// 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 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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/mod.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/mod.rs new file mode 100644 index 000000000..b473d49e2 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/mod.rs @@ -0,0 +1,27 @@ +// 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/paritydb_weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/paritydb_weights.rs new file mode 100644 index 000000000..256797038 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/paritydb_weights.rs @@ -0,0 +1,63 @@ +// 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 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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/rocksdb_weights.rs b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/rocksdb_weights.rs new file mode 100644 index 000000000..3dd817aa6 --- /dev/null +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking/runtime/src/weights/rocksdb_weights.rs @@ -0,0 +1,63 @@ +// 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 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 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/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages b/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages index b209fd5cb..842f21d46 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/.pages @@ -4,7 +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 + - 'Pallet Benchmarking': pallet-benchmarking.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/add-pallets-to-runtime.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime.md index 31159fec5..863b7feb8 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime.md @@ -112,4 +112,12 @@ Launch your parachain locally and start producing blocks: [: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/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md index deabfdeca..1c504ecaf 100644 --- a/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md +++ b/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-benchmarking.md @@ -5,8 +5,7 @@ description: Learn how to benchmark Polkadot SDK-based pallets, assigning precis ## Introduction -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. +After validating your pallet through testing and integrating it into your runtime, the next crucial step is benchmarking. Testing procedures were detailed in the [Pallet Unit Testing](/tutorials/polkadot-sdk/parachains/zero-to-hero/pallet-unit-testing/){target=\_blank} tutorial, while runtime integration was covered in the [Add Pallets to the Runtime](/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime/){target=\_blank} guide. This tutorial demonstrates how to: @@ -201,12 +200,12 @@ Your pallet is now complete with full testing and benchmarking support, ready fo
-- Tutorial __Add Pallets to the Runtime__ +- Tutorial __Deploy on Paseo TestNet__ --- - Enhance your runtime with custom functionality! Learn how to add, configure, and integrate pallets in Polkadot SDK-based blockchains. + 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/add-pallets-to-runtime/) + [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/deploy-to-testnet/)
\ No newline at end of file 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 80a0485a8..fec77a97d 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 __Pallet Benchmarking__ +- Tutorial __Add Pallets to the Runtime__ --- - Discover how to measure extrinsic costs and assign precise weights to optimize your pallet for accurate fees and runtime performance. + 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/pallet-benchmarking/) + [:octicons-arrow-right-24: Get Started](/tutorials/polkadot-sdk/parachains/zero-to-hero/add-pallets-to-runtime/)
\ No newline at end of file