From moonbeam-engineering
Creates and runs benchmarks for pallets and precompiles to generate accurate weight functions for the Moonbeam runtime. Use when adding new extrinsics, creating precompiles, optimizing functionality, updating weights after logic changes, or validating weight accuracy.
How this skill is triggered — by the user, by Claude, or both
Slash command
/moonbeam-engineering:benchmarking-palletsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- [Benchmarking Overview](#benchmarking-overview)
Weight {
ref_time: u64, // Computational time
proof_size: u64, // Storage proof size
}
# pallets/my-pallet/Cargo.toml
[dependencies]
frame-benchmarking = { workspace = true, optional = true }
[features]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
]
// pallets/my-pallet/src/benchmarking.rs
#![cfg(feature = "runtime-benchmarks")]
use super::*;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
#[benchmarks]
mod benchmarks {
use super::*;
/// Benchmark for `do_something` extrinsic
#[benchmark]
fn do_something() {
// Setup: Create any required state
let caller: T::AccountId = whitelisted_caller();
let value = 42u32;
// Optional: Fund the account if needed
// T::Currency::make_free_balance_be(&caller, 1_000_000_000_000u128.into());
#[extrinsic_call]
do_something(RawOrigin::Signed(caller.clone()), value);
// Verify: Assert the expected state change
assert_eq!(Something::<T>::get(), Some(value));
}
/// Benchmark with linear complexity
#[benchmark]
fn do_something_complex(n: Linear<1, 100>) {
let caller: T::AccountId = whitelisted_caller();
// Setup scales with n
for i in 0..n {
SomeStorage::<T>::insert(i, i);
}
#[extrinsic_call]
do_something_complex(RawOrigin::Signed(caller), n);
assert!(SomeStorage::<T>::iter().count() as u32 >= n);
}
/// Benchmark for storage-heavy operation
#[benchmark]
fn clear_storage(n: Linear<1, 1000>) {
let caller: T::AccountId = whitelisted_caller();
// Populate storage
for i in 0..n {
SomeStorage::<T>::insert(i, vec![0u8; 100]);
}
#[extrinsic_call]
clear_storage(RawOrigin::Signed(caller), n);
assert_eq!(SomeStorage::<T>::iter().count(), 0);
}
impl_benchmark_test_suite!(
Pallet,
crate::mock::new_test_ext(),
crate::mock::Test
);
}
// pallets/my-pallet/src/weights.rs
use frame_support::weights::Weight;
pub trait WeightInfo {
fn do_something() -> Weight;
fn do_something_complex(n: u32) -> Weight;
fn clear_storage(n: u32) -> Weight;
}
/// Placeholder weights for development
impl WeightInfo for () {
fn do_something() -> Weight {
Weight::from_parts(10_000, 0)
}
fn do_something_complex(n: u32) -> Weight {
Weight::from_parts(10_000 + n as u64 * 1_000, 0)
}
fn clear_storage(n: u32) -> Weight {
Weight::from_parts(10_000 + n as u64 * 5_000, 0)
}
}
// pallets/my-pallet/src/lib.rs
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use weights::WeightInfo;
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::do_something())]
pub fn do_something(origin: OriginFor<T>, value: u32) -> DispatchResult {
// ...
}
#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::do_something_complex(*n))]
pub fn do_something_complex(origin: OriginFor<T>, n: u32) -> DispatchResult {
// ...
}
}
// runtime/moonbase/lib.rs
#[cfg(feature = "runtime-benchmarks")]
mod benches {
frame_benchmarking::define_benchmarks!(
// Existing benchmarks...
[pallet_my_pallet, MyPallet]
);
}
# Run all benchmarks for a runtime
./scripts/run-benches-for-runtime.sh moonbase release
# Run specific pallet benchmarks
./scripts/run-benches-for-runtime.sh moonbase release pallet_my_pallet
# Build with benchmarks
cargo build --release --features runtime-benchmarks
# Run frame-omni-bencher
frame-omni-bencher v1 benchmark pallet \
--runtime target/release/wbuild/moonbase-runtime/moonbase_runtime.wasm \
--pallet pallet_my_pallet \
--extrinsic "*" \
--steps 50 \
--repeat 20 \
--wasm-execution compiled \
--output runtime/moonbase/src/weights/pallet_my_pallet.rs \
--template benchmarking/frame-weight-template.hbs
| Parameter | Purpose | Typical Value |
|---|---|---|
--steps | Number of sample points | 50 |
--repeat | Repetitions per step | 20 |
--heap-pages | WASM heap size | 4096 |
--wasm-execution | Execution mode | compiled |
The benchmark generates a weights file like:
// runtime/moonbase/src/weights/pallet_my_pallet.rs
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData;
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> pallet_my_pallet::WeightInfo for SubstrateWeight<T> {
fn do_something() -> Weight {
Weight::from_parts(12_345_000, 3456)
.saturating_add(T::DbWeight::get().reads(1))
.saturating_add(T::DbWeight::get().writes(1))
}
fn do_something_complex(n: u32) -> Weight {
Weight::from_parts(10_000_000, 1000)
.saturating_add(Weight::from_parts(500_000, 100).saturating_mul(n as u64))
.saturating_add(T::DbWeight::get().reads(1 + n as u64))
.saturating_add(T::DbWeight::get().writes(n as u64))
}
}
// precompiles/my-precompile/src/benchmarking.rs
#![cfg(feature = "runtime-benchmarks")]
use frame_benchmarking::v2::*;
#[benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn do_something() {
let caller = H160::from_low_u64_be(1);
let value = U256::from(42);
#[block]
{
MyPrecompile::<T>::do_something(caller, value).unwrap();
}
}
}
// In the precompile implementation
const BASE_GAS_COST: u64 = 200;
const PER_ITEM_GAS_COST: u64 = 100;
fn gas_cost(items: u64) -> u64 {
BASE_GAS_COST.saturating_add(PER_ITEM_GAS_COST.saturating_mul(items))
}
Always benchmark the worst case:
#[benchmark]
fn bounded_operation(n: Linear<1, MAX_ITEMS>) {
// Setup with maximum complexity
for i in 0..n {
HeavyStorage::<T>::insert(i, vec![0u8; MAX_SIZE]);
}
#[extrinsic_call]
bounded_operation(RawOrigin::Root, n);
}
// Weight should reflect actual DB access
Weight::from_parts(compute_time, proof_size)
.saturating_add(T::DbWeight::get().reads(read_count))
.saturating_add(T::DbWeight::get().writes(write_count))
# Run benchmark tests to verify they work
cargo test -p pallet-my-pallet --features runtime-benchmarks
After generating weights:
# Check benchmark compiles
cargo check --release -p moonbase-runtime --features runtime-benchmarks
# Run with more verbose output
RUST_LOG=runtime::benchmark=trace frame-omni-bencher ...
# Increase heap pages
--heap-pages 8192
npx claudepluginhub moonsong-labs/knowledge-work-plugins --plugin moonbeam-engineeringScans Substrate/Polkadot pallets for 7 critical vulnerabilities like arithmetic overflow, panic DoS, incorrect weights, and bad origin checks. For auditing FRAME runtimes.
Scans Substrate/Polkadot pallets for 7 critical vulnerabilities including arithmetic overflow, panic DoS, incorrect weights, and bad origin checks. Use when auditing Substrate runtimes or FRAME pallets.
Creates and runs reliable benchmarks to measure code change impacts on performance, including latency, throughput. Supports Node.js (vitest, tinybench), Python (pytest-benchmark), frontend (Lighthouse CI), with warmup, stats.