From be4bd2a56cfc163e06c6cad4cb304f066e7935b9 Mon Sep 17 00:00:00 2001 From: Gonza Montiel Date: Tue, 3 Mar 2026 09:20:04 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8F=81=20pallet=20grandpa=20bench?= =?UTF-8?q?marking=20(#442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Changes ### Add `pallet-grandpa-benchmarking` crate Upstream `pallet-grandpa` does not benchmark `report_equivocation`, only the raw `check_equivocation_proof` crypto proxy. This PR adds a new `pallet-grandpa-benchmarking` wrapper crate (modelled after `pallet-session-benchmarking`) that benchmarks both `report_equivocation` and `note_stalled` against the DataHaven runtimes, using upstream `check_equivocation_proof()`. ### Add node's benchmark pallet subcommand to benchmarks script Running the bench for `report_equivocation` requires a real ed25519 verifier. We typically use `frame-omni-bencher`, but this helper executes the runtime as a WASM blob. In that environment the ed25519 host function does not work as a real verifier, and since the equivocation proof contains real signatures created outside the WASM sandbox, the verification always fails and the extrinsic returns `InvalidEquivocationProof`. So, benchmarks for `pallet_grandpa` must run via the node's `benchmark pallet` subcommand. The `run-benchmarks.sh` script was updated to support this case running directly via node. Any palet included in the new `NODE_PALLETS` list, routes selected pallets through the node binary, while all other pallets continue to use `frame-omni-bencher`. ### Calculate proper weights for production Weight files for all three runtimes (stagenet, testnet, mainnet) are updated with the new `report_equivocation(v, n)` linear weight function derived from real measurements. --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com> Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com> --- .github/workflows/task-e2e.yml | 2 + operator/Cargo.lock | 22 ++ operator/Cargo.toml | 1 + .../pallets/grandpa-benchmarking/Cargo.toml | 56 ++++++ .../grandpa-benchmarking/src/benchmarking.rs | 190 ++++++++++++++++++ .../pallets/grandpa-benchmarking/src/lib.rs | 83 ++++++++ operator/runtime/mainnet/Cargo.toml | 3 + operator/runtime/mainnet/src/benchmarks.rs | 2 +- operator/runtime/mainnet/src/lib.rs | 12 ++ .../mainnet/src/weights/pallet_grandpa.rs | 71 +++++-- operator/runtime/stagenet/Cargo.toml | 3 + operator/runtime/stagenet/src/benchmarks.rs | 2 +- operator/runtime/stagenet/src/lib.rs | 12 ++ .../stagenet/src/weights/pallet_grandpa.rs | 71 +++++-- operator/runtime/testnet/Cargo.toml | 3 + operator/runtime/testnet/src/benchmarks.rs | 2 +- operator/runtime/testnet/src/lib.rs | 12 ++ .../testnet/src/weights/pallet_grandpa.rs | 71 +++++-- operator/scripts/run-benchmarks.sh | 82 +++++++- 19 files changed, 626 insertions(+), 74 deletions(-) create mode 100644 operator/pallets/grandpa-benchmarking/Cargo.toml create mode 100644 operator/pallets/grandpa-benchmarking/src/benchmarking.rs create mode 100644 operator/pallets/grandpa-benchmarking/src/lib.rs diff --git a/.github/workflows/task-e2e.yml b/.github/workflows/task-e2e.yml index dfd8cee6..fd7a3daa 100644 --- a/.github/workflows/task-e2e.yml +++ b/.github/workflows/task-e2e.yml @@ -60,6 +60,8 @@ jobs: run: bun ./scripts/check-generated-state.ts - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + with: + version: v1.4.3 - name: Pull Kurtosis images run: | docker pull ${{ env.KURTOSIS_CORE_IMAGE }}:${{ env.KURTOSIS_VERSION }} diff --git a/operator/Cargo.lock b/operator/Cargo.lock index 60011856..702cc2d4 100644 --- a/operator/Cargo.lock +++ b/operator/Cargo.lock @@ -2669,6 +2669,7 @@ dependencies = [ "pallet-file-system", "pallet-file-system-runtime-api", "pallet-grandpa", + "pallet-grandpa-benchmarking", "pallet-identity", "pallet-im-online", "pallet-message-queue", @@ -2972,6 +2973,7 @@ dependencies = [ "pallet-file-system", "pallet-file-system-runtime-api", "pallet-grandpa", + "pallet-grandpa-benchmarking", "pallet-identity", "pallet-im-online", "pallet-message-queue", @@ -3128,6 +3130,7 @@ dependencies = [ "pallet-file-system", "pallet-file-system-runtime-api", "pallet-grandpa", + "pallet-grandpa-benchmarking", "pallet-identity", "pallet-im-online", "pallet-message-queue", @@ -9282,6 +9285,25 @@ dependencies = [ "sp-staking", ] +[[package]] +name = "pallet-grandpa-benchmarking" +version = "0.25.0" +dependencies = [ + "finality-grandpa", + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-grandpa", + "pallet-session", + "parity-scale-codec", + "sp-application-crypto", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "sp-session", + "sp-std", +] + [[package]] name = "pallet-identity" version = "39.1.0" diff --git a/operator/Cargo.toml b/operator/Cargo.toml index 4419b4b3..194e5f4e 100644 --- a/operator/Cargo.toml +++ b/operator/Cargo.toml @@ -44,6 +44,7 @@ pallet-external-validators = { path = "./pallets/external-validators", default-f pallet-external-validators-rewards = { path = "./pallets/external-validators-rewards", default-features = false } pallet-outbound-commitment-store = { path = "./pallets/outbound-commitment-store", default-features = false } pallet-proxy-genesis-companion = { path = "./pallets/proxy-genesis-companion", default-features = false } +pallet-grandpa-benchmarking = { path = "./pallets/grandpa-benchmarking", default-features = false } pallet-session-benchmarking = { path = "./pallets/session-benchmarking", default-features = false } # Crates.io (wasm) diff --git a/operator/pallets/grandpa-benchmarking/Cargo.toml b/operator/pallets/grandpa-benchmarking/Cargo.toml new file mode 100644 index 00000000..67f8cbd8 --- /dev/null +++ b/operator/pallets/grandpa-benchmarking/Cargo.toml @@ -0,0 +1,56 @@ +[package] +authors = { workspace = true } +description = "Benchmarking helpers for pallet-grandpa in DataHaven runtimes." +edition = { workspace = true } +license = { workspace = true } +name = "pallet-grandpa-benchmarking" +version = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true + +[dependencies] +codec = { workspace = true } +frame-benchmarking = { workspace = true, optional = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +finality-grandpa = { version = "0.16.3", default-features = false } +pallet-grandpa = { workspace = true } +pallet-session = { workspace = true, features = ["historical"] } +sp-consensus-grandpa = { workspace = true } +sp-application-crypto = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-session = { workspace = true } +sp-std = { workspace = true } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "finality-grandpa/std", + "pallet-grandpa/std", + "pallet-session/std", + "sp-consensus-grandpa/std", + "sp-application-crypto/std", + "sp-core/std", + "sp-runtime/std", + "sp-session/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-grandpa/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +[dev-dependencies] +sp-core = { workspace = true, features = ["full_crypto"] } diff --git a/operator/pallets/grandpa-benchmarking/src/benchmarking.rs b/operator/pallets/grandpa-benchmarking/src/benchmarking.rs new file mode 100644 index 00000000..ee9bd5c0 --- /dev/null +++ b/operator/pallets/grandpa-benchmarking/src/benchmarking.rs @@ -0,0 +1,190 @@ +//! Benchmarks for `pallet_grandpa` covering both extrinsics in `pallet_grandpa::WeightInfo`: +//! `report_equivocation` and `note_stalled`. +//! +//! Upstream `pallet-grandpa` benchmarks `check_equivocation_proof` (a raw crypto cost proxy) and +//! `note_stalled`, but does not benchmark the actual `report_equivocation` extrinsic dispatch. +//! This crate fills that gap so the node's benchmark command can generate a complete `WeightInfo` +//! impl from real measurements against the DataHaven runtime. +//! +//! The equivocation proof is pre-encoded (see `PREENCODED_EQUIVOCATION_PROOF`) and was generated +//! with the same ed25519 seed used in `setup_equivocation`, so the authority ID embedded in the +//! proof matches the key registered in the session. +//! Regenerate with: `cargo test -p pallet-grandpa-benchmarking --features std -- test_generate_equivocation_blob --nocapture` +//! +//! `frame-omni-bencher` will fail with `InvalidEquivocationProof` because its WASM host does not +//! provide a real ed25519 verifier. Use the node's `benchmark pallet` subcommand instead. + +use alloc::{boxed::Box, vec}; + +use codec::Decode; +use frame_benchmarking::v2::*; +use frame_support::traits::{KeyOwnerProofSystem, OnInitialize}; +use frame_system::RawOrigin; +use sp_application_crypto::{RuntimeAppPublic, UncheckedFrom}; +use sp_runtime::traits::Convert; + +use crate::{Config, Pallet}; + +type GrandpaId = sp_consensus_grandpa::AuthorityId; +type GrandpaEquivocationProof = sp_consensus_grandpa::EquivocationProof< + ::Hash, + frame_system::pallet_prelude::BlockNumberFor, +>; + +/// Pre-encoded equivocation proof (set_id=0, round=1) signed with the test vector key. +/// Generated by `test_generate_equivocation_blob` in `tests` module of `lib.rs`. +const PREENCODED_EQUIVOCATION_PROOF: [u8; 249] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, + 254, 211, 201, 100, 7, 58, 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, + 26, 225, 44, 34, 212, 241, 98, 217, 160, 18, 201, 49, 146, 51, 218, 93, 62, 146, 60, 197, 225, + 2, 155, 143, 144, 228, 114, 73, 201, 171, 37, 107, 53, 1, 0, 0, 0, 94, 182, 72, 53, 215, 108, + 169, 70, 216, 243, 227, 8, 163, 172, 0, 93, 157, 90, 110, 18, 72, 38, 48, 16, 57, 74, 178, 17, + 106, 150, 24, 107, 195, 175, 45, 40, 156, 45, 67, 202, 120, 13, 87, 252, 21, 17, 62, 155, 246, + 219, 28, 34, 255, 230, 191, 85, 75, 147, 164, 14, 131, 146, 99, 2, 123, 10, 161, 115, 94, 91, + 165, 141, 50, 54, 49, 108, 103, 31, 228, 240, 14, 211, 102, 238, 114, 65, 124, 158, 208, 42, + 83, 168, 1, 158, 133, 184, 2, 0, 0, 0, 151, 111, 43, 192, 22, 148, 165, 193, 112, 145, 172, 94, + 236, 197, 151, 102, 5, 97, 64, 30, 160, 179, 79, 79, 150, 102, 200, 105, 32, 233, 249, 185, + 118, 73, 110, 32, 193, 87, 150, 41, 254, 155, 104, 77, 236, 36, 48, 202, 161, 26, 247, 61, 181, + 109, 221, 114, 165, 70, 43, 146, 198, 158, 253, 1, +]; + +/// Constructs a dummy, unique, deterministic grandpa id +fn grandpa_id_for_validator(i: u32) -> GrandpaId { + let mut raw = [0u8; 32]; + raw[..4].copy_from_slice(&i.to_le_bytes()); + raw[4] = 0xff; + GrandpaId::unchecked_from(raw) +} + +fn setup_equivocation( + extra_validators: u32, +) -> Result< + ( + Box>, + ::KeyOwnerProof, + ::AccountId, + ), + BenchmarkError, +> { + use frame_system::pallet_prelude::BlockNumberFor; + use frame_system::Pallet as System; + + let reporter: T::AccountId = whitelisted_caller(); + frame_system::Pallet::::inc_providers(&reporter); + + // Ensure we are at a sane block number and that session is initialized. + System::::set_block_number(1u32.into()); + as OnInitialize>>::on_initialize(1u32.into()); + + // Use the same seed as in test_generate_equivocation_blob so the key matches the + // pre-encoded proof and the host keystore can store it for KeyOwnerProof. + let seed = b"0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60".to_vec(); + let grandpa_id: GrandpaId = GrandpaId::generate_pair(Some(seed)); + + // Install session keys for the reporter account. The runtime provides the concrete + // `T::Keys` type construction via `Config::benchmark_session_keys`. + let keys = T::benchmark_session_keys(grandpa_id.clone()); + pallet_session::Pallet::::set_keys( + RawOrigin::Signed(reporter.clone()).into(), + keys.clone(), + vec![0, 1, 2, 3], + ) + .map_err(|_| BenchmarkError::Stop("set_keys failed"))?; + + // ValidatorId = AccountId in all DataHaven runtimes; the reporter went through set_keys + // successfully so the conversion is guaranteed to succeed. + let reporter_validator_id: T::ValidatorId = T::ValidatorIdOf::convert(reporter.clone()) + .ok_or_else(|| BenchmarkError::Stop("could not convert reporter to ValidatorId"))?; + + // Build the full validator + queued-keys lists: the real offender first, then + // `extra_validators` background validators. Each gets a unique GRANDPA key so the session + // trie has `extra_validators + 1` distinct leaves. The resulting trie depth (and therefore + // `key_owner_proof.validator_count()`) scales with `v`, giving the linear regression a + // real signal to measure. + let mut validators = vec![reporter_validator_id.clone()]; + let mut queued_keys = vec![(reporter_validator_id, keys)]; + + for i in 0..extra_validators { + let validator_id: T::ValidatorId = account("validator", i, i); + let validator_keys = T::benchmark_session_keys(grandpa_id_for_validator(i)); + pallet_session::NextKeys::::insert(&validator_id, validator_keys.clone()); + validators.push(validator_id.clone()); + queued_keys.push((validator_id, validator_keys)); + } + + // Overwrite session storage so the full set (offender + background validators) is active. + pallet_session::Validators::::put(validators); + pallet_session::QueuedKeys::::put(queued_keys); + + // Initialize session again after overwriting validator state. + as OnInitialize>>::on_initialize(1u32.into()); + + // Generate a fresh KeyOwnerProof via Historical for the GRANDPA key registered above. + // The authority ID in this proof must match the one embedded in PREENCODED_EQUIVOCATION_PROOF, + // which is guaranteed because both use the same seed. The proof's `validator_count` field + // will now equal `extra_validators + 1`, matching what the weight function receives at + // dispatch time in production. + let key_owner_proof = pallet_session::historical::Pallet::::prove(( + sp_consensus_grandpa::KEY_TYPE, + grandpa_id.clone(), + )) + .ok_or_else(|| BenchmarkError::Stop("Historical::prove returned None".into()))?; + + // Decode the pre-encoded equivocation proof (set_id=0, round=1). The pallet will only + // accept this if the on-chain current_set_id is also 0, which holds in a fresh benchmark + // environment since no set rotation has occurred. + let proof: GrandpaEquivocationProof = + Decode::decode(&mut &PREENCODED_EQUIVOCATION_PROOF[..]) + .map_err(|_| BenchmarkError::Stop("failed to decode pre-encoded equivocation proof"))?; + + Ok((Box::new(proof), key_owner_proof, reporter)) +} + +#[benchmarks] +mod benchmarks { + use super::*; + use pallet_grandpa::Call; + + #[benchmark] + fn note_stalled() -> Result<(), BenchmarkError> { + let delay = 1000u32.into(); + let best_finalized_block_number = 1u32.into(); + + #[extrinsic_call] + _(RawOrigin::Root, delay, best_finalized_block_number); + + Ok(()) + } + + /// Benchmarks the full `report_equivocation` dispatch cost. + /// + /// The upstream `WeightInfo::report_equivocation` signature takes + /// `(validator_count: u32, max_nominators_per_validator: u32)` as linear components. + /// We expose the same parameters here so the generated weight function matches the + /// trait exactly and the linear terms are populated from real measurements. + /// `v` = validator_count, `n` = max_nominators_per_validator (matches upstream component names). + /// + /// `v` background validators are registered in the session alongside the real offender, so + /// the session trie has `v + 1` leaves and `key_owner_proof.validator_count()` equals `v + 1`. + /// This means the trie verification path actually grows with `v`, giving the linear regression + /// a real signal and producing a meaningful slope coefficient in the generated weight function. + /// + /// # Disclaimer: setup over-counts `v` cost + /// + /// The `v` slope in the generated weights is dominated by `Session::NextKeys` reads, because + /// `Historical::prove` (called during setup) reads all `v` validators to build the full trie. + /// In production, `Historical::check_proof` (called during dispatch) only traverses the O(log v) + /// Merkle path nodes — it does not read all validators. The generated weights therefore + /// over-count the per-validator cost and are conservative/safe (they overcharge rather than + /// undercharge), but this is a known tension inherent to benchmarking session historical + /// proofs: the setup must call `prove`, which is more expensive than `check_proof`. + #[benchmark] + fn report_equivocation(v: Linear<0, 1000>, n: Linear<0, 1>) -> Result<(), BenchmarkError> { + let (proof, key_owner_proof, reporter) = setup_equivocation::(v)?; + + #[extrinsic_call] + _(RawOrigin::Signed(reporter), proof, key_owner_proof); + + Ok(()) + } +} diff --git a/operator/pallets/grandpa-benchmarking/src/lib.rs b/operator/pallets/grandpa-benchmarking/src/lib.rs new file mode 100644 index 00000000..7f2af769 --- /dev/null +++ b/operator/pallets/grandpa-benchmarking/src/lib.rs @@ -0,0 +1,83 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +pub struct Pallet(pallet_grandpa::Pallet); + +/// Benchmarking configuration for `pallet-grandpa` in DataHaven. +/// +/// This is a small wrapper crate (similar to `pallet-session-benchmarking`) that provides +/// benchmarks for GRANDPA extrinsics that upstream `pallet-grandpa` does not expose in its +/// own benchmarking suite. Run via the node's `benchmark pallet` subcommand, not +/// `frame-omni-bencher`, as the latter lacks a real ed25519 verifier. +pub trait Config: + pallet_grandpa::Config< + KeyOwnerProof = as frame_support::traits::KeyOwnerProofSystem<( + sp_core::crypto::KeyTypeId, + sp_consensus_grandpa::AuthorityId, + )>>::Proof, + > + pallet_session::Config + + pallet_session::historical::Config +{ + /// Construct a full `Self::Keys` value for benchmarking, filling all slots except GRANDPA + /// with dummy values and placing `grandpa` in the GRANDPA slot. + fn benchmark_session_keys(grandpa: sp_consensus_grandpa::AuthorityId) -> Self::Keys; +} + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[cfg(all(test, feature = "std"))] +mod tests { + use codec::Encode; + use sp_consensus_grandpa; + use sp_core::{ed25519, Pair as PairTrait}; + use sp_runtime::traits::{BlakeTwo256, Hash as HashT}; + + /// Run with: cargo test -p pallet-grandpa-benchmarking --features std -- test_generate_equivocation_blob --nocapture + /// Then paste the printed bytes into PREENCODED_EQUIVOCATION_PROOF in benchmarking.rs. + #[test] + fn test_generate_equivocation_blob() { + let seed = "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"; + let pair = ed25519::Pair::from_string(seed, None).expect("valid seed"); + let set_id: u64 = 0; + let round: u64 = 1; + + let h1 = BlakeTwo256::hash_of(&1u32); + let h2 = BlakeTwo256::hash_of(&2u32); + let prevote1 = finality_grandpa::Prevote { + target_hash: h1, + target_number: 1u32, + }; + let prevote2 = finality_grandpa::Prevote { + target_hash: h2, + target_number: 2u32, + }; + + let msg1 = finality_grandpa::Message::Prevote(prevote1.clone()); + let msg2 = finality_grandpa::Message::Prevote(prevote2.clone()); + let payload1 = sp_consensus_grandpa::localized_payload(round, set_id, &msg1); + let payload2 = sp_consensus_grandpa::localized_payload(round, set_id, &msg2); + + let sig1 = pair.sign(&payload1); + let sig2 = pair.sign(&payload2); + + let equivocation = finality_grandpa::Equivocation { + round_number: round, + identity: sp_consensus_grandpa::AuthorityId::from(pair.public()), + first: (prevote1, sig1.into()), + second: (prevote2, sig2.into()), + }; + + let proof = sp_consensus_grandpa::EquivocationProof::::new( + set_id, + equivocation.into(), + ); + let encoded = proof.encode(); + println!( + "PREENCODED_EQUIVOCATION_PROOF (len={}): {:?}", + encoded.len(), + encoded + ); + } +} diff --git a/operator/runtime/mainnet/Cargo.toml b/operator/runtime/mainnet/Cargo.toml index 4de1517f..186bc7b9 100644 --- a/operator/runtime/mainnet/Cargo.toml +++ b/operator/runtime/mainnet/Cargo.toml @@ -72,6 +72,7 @@ pallet-referenda = { workspace = true } pallet-safe-mode = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } +pallet-grandpa-benchmarking = { workspace = true, optional = true } pallet-session-benchmarking = { workspace = true, optional = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } @@ -196,6 +197,7 @@ std = [ "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", + "pallet-grandpa-benchmarking?/std", "pallet-session-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", @@ -342,6 +344,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-grandpa-benchmarking/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/operator/runtime/mainnet/src/benchmarks.rs b/operator/runtime/mainnet/src/benchmarks.rs index 62136c7c..01d8bf96 100644 --- a/operator/runtime/mainnet/src/benchmarks.rs +++ b/operator/runtime/mainnet/src/benchmarks.rs @@ -22,7 +22,7 @@ frame_benchmarking::define_benchmarks!( [pallet_mmr, Mmr] [pallet_beefy_mmr, BeefyMmrLeaf] [pallet_babe, Babe] - [pallet_grandpa, Grandpa] + [pallet_grandpa, pallet_grandpa_benchmarking::Pallet::] [pallet_randomness, Randomness] // Substrate pallets diff --git a/operator/runtime/mainnet/src/lib.rs b/operator/runtime/mainnet/src/lib.rs index 660a630e..94b4ec5b 100644 --- a/operator/runtime/mainnet/src/lib.rs +++ b/operator/runtime/mainnet/src/lib.rs @@ -973,6 +973,18 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl pallet_session_benchmarking::Config for Runtime {} + impl pallet_grandpa_benchmarking::Config for Runtime { + fn benchmark_session_keys(grandpa: GrandpaId) -> Self::Keys { + use sp_core::crypto::UncheckedFrom; + + SessionKeys { + babe: sp_consensus_babe::AuthorityId::unchecked_from([1u8; 32]), + grandpa, + im_online: pallet_im_online::sr25519::AuthorityId::unchecked_from([1u8; 32]), + beefy: sp_consensus_beefy::ecdsa_crypto::AuthorityId::unchecked_from([1u8; 33]), + } + } + } impl baseline::Config for Runtime {} use frame_support::traits::WhitelistedStorageKeys; diff --git a/operator/runtime/mainnet/src/weights/pallet_grandpa.rs b/operator/runtime/mainnet/src/weights/pallet_grandpa.rs index 887905ab..7250e7d1 100644 --- a/operator/runtime/mainnet/src/weights/pallet_grandpa.rs +++ b/operator/runtime/mainnet/src/weights/pallet_grandpa.rs @@ -17,33 +17,34 @@ //! Autogenerated weights for `pallet_grandpa` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 51.0.0 -//! DATE: 2026-01-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 46.2.0 +//! DATE: 2026-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` //! WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/datahaven-node // benchmark // pallet // --runtime // target/production/wbuild/datahaven-mainnet-runtime/datahaven_mainnet_runtime.compact.compressed.wasm +// --genesis-builder +// runtime // --pallet // pallet_grandpa // --extrinsic -// +// * +// --steps +// 50 +// --repeat +// 20 // --header // ../file_header.txt // --template // benchmarking/frame-weight-template.hbs // --output // runtime/mainnet/src/weights/pallet_grandpa.rs -// --steps -// 50 -// --repeat -// 20 #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,24 +56,52 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_grandpa`. pub struct WeightInfo(PhantomData); impl pallet_grandpa::WeightInfo for WeightInfo { - /// The range of component `x` is `[0, 1]`. - fn report_equivocation(prev: u32, _equivocations: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 78_547_000 picoseconds. - Weight::from_parts(78_982_114, 0) - // Standard Error: 28_584 - .saturating_add(Weight::from_parts(129_485, 0).saturating_mul(prev.into())) - } /// Storage: `Grandpa::Stalled` (r:0 w:1) /// Proof: `Grandpa::Stalled` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn note_stalled() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_815_000 picoseconds. - Weight::from_parts(3_947_000, 0) + // Minimum execution time: 2_506_000 picoseconds. + Weight::from_parts(2_591_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::NextKeys` (r:1001 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Grandpa::SetIdSession` (r:1 w:0) + /// Proof: `Grandpa::SetIdSession` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `Offences::ConcurrentReportsIndex` (r:1 w:1) + /// Proof: `Offences::ConcurrentReportsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Offences::Reports` (r:1 w:1) + /// Proof: `Offences::Reports` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ExternalValidatorsSlashes::SlashingMode` (r:1 w:0) + /// Proof: `ExternalValidatorsSlashes::SlashingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ActiveEra` (r:1 w:0) + /// Proof: `ExternalValidators::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `ExternalValidators::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::WhitelistedValidators` (r:1 w:0) + /// Proof: `ExternalValidators::WhitelistedValidators` (`max_values`: Some(1), `max_size`: Some(2002), added: 2497, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidatorsSlashes::NextSlashId` (r:1 w:1) + /// Proof: `ExternalValidatorsSlashes::NextSlashId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `v` is `[0, 1000]`. + /// The range of component `n` is `[0, 1]`. + fn report_equivocation(v: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1202 + v * (184 ±0)` + // Estimated: `4604 + n * (84 ±3) + v * (2660 ±0)` + // Minimum execution time: 159_361_000 picoseconds. + Weight::from_parts(161_997_000, 4604) + // Standard Error: 6_387 + .saturating_add(Weight::from_parts(12_204_491, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 84).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2660).saturating_mul(v.into())) + } } diff --git a/operator/runtime/stagenet/Cargo.toml b/operator/runtime/stagenet/Cargo.toml index c1b33c46..c171e435 100644 --- a/operator/runtime/stagenet/Cargo.toml +++ b/operator/runtime/stagenet/Cargo.toml @@ -72,6 +72,7 @@ pallet-referenda = { workspace = true } pallet-safe-mode = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } +pallet-grandpa-benchmarking = { workspace = true, optional = true } pallet-session-benchmarking = { workspace = true, optional = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } @@ -197,6 +198,7 @@ std = [ "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", + "pallet-grandpa-benchmarking?/std", "pallet-session-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", @@ -344,6 +346,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-grandpa-benchmarking/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/operator/runtime/stagenet/src/benchmarks.rs b/operator/runtime/stagenet/src/benchmarks.rs index bfbaa347..0b400bad 100644 --- a/operator/runtime/stagenet/src/benchmarks.rs +++ b/operator/runtime/stagenet/src/benchmarks.rs @@ -22,7 +22,7 @@ frame_benchmarking::define_benchmarks!( [pallet_mmr, Mmr] [pallet_beefy_mmr, BeefyMmrLeaf] [pallet_babe, Babe] - [pallet_grandpa, Grandpa] + [pallet_grandpa, pallet_grandpa_benchmarking::Pallet::] [pallet_randomness, Randomness] // Substrate pallets diff --git a/operator/runtime/stagenet/src/lib.rs b/operator/runtime/stagenet/src/lib.rs index b78a265e..0655d3be 100644 --- a/operator/runtime/stagenet/src/lib.rs +++ b/operator/runtime/stagenet/src/lib.rs @@ -975,6 +975,18 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl pallet_session_benchmarking::Config for Runtime {} + impl pallet_grandpa_benchmarking::Config for Runtime { + fn benchmark_session_keys(grandpa: GrandpaId) -> Self::Keys { + use sp_core::crypto::UncheckedFrom; + + SessionKeys { + babe: sp_consensus_babe::AuthorityId::unchecked_from([1u8; 32]), + grandpa, + im_online: pallet_im_online::sr25519::AuthorityId::unchecked_from([1u8; 32]), + beefy: sp_consensus_beefy::ecdsa_crypto::AuthorityId::unchecked_from([1u8; 33]), + } + } + } impl baseline::Config for Runtime {} use frame_support::traits::WhitelistedStorageKeys; diff --git a/operator/runtime/stagenet/src/weights/pallet_grandpa.rs b/operator/runtime/stagenet/src/weights/pallet_grandpa.rs index 9a0d48f0..f30c5bcf 100644 --- a/operator/runtime/stagenet/src/weights/pallet_grandpa.rs +++ b/operator/runtime/stagenet/src/weights/pallet_grandpa.rs @@ -17,33 +17,34 @@ //! Autogenerated weights for `pallet_grandpa` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 51.0.0 -//! DATE: 2025-12-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 46.2.0 +//! DATE: 2026-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` //! WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/datahaven-node // benchmark // pallet // --runtime // target/production/wbuild/datahaven-stagenet-runtime/datahaven_stagenet_runtime.compact.compressed.wasm +// --genesis-builder +// runtime // --pallet // pallet_grandpa // --extrinsic -// +// * +// --steps +// 50 +// --repeat +// 20 // --header // ../file_header.txt // --template // benchmarking/frame-weight-template.hbs // --output // runtime/stagenet/src/weights/pallet_grandpa.rs -// --steps -// 50 -// --repeat -// 20 #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,24 +56,52 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_grandpa`. pub struct WeightInfo(PhantomData); impl pallet_grandpa::WeightInfo for WeightInfo { - /// The range of component `x` is `[0, 1]`. - fn report_equivocation(prev: u32, _equivocations: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 78_547_000 picoseconds. - Weight::from_parts(78_982_114, 0) - // Standard Error: 28_584 - .saturating_add(Weight::from_parts(129_485, 0).saturating_mul(prev.into())) - } /// Storage: `Grandpa::Stalled` (r:0 w:1) /// Proof: `Grandpa::Stalled` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn note_stalled() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_815_000 picoseconds. - Weight::from_parts(3_947_000, 0) + // Minimum execution time: 2_453_000 picoseconds. + Weight::from_parts(2_554_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::NextKeys` (r:1001 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Grandpa::SetIdSession` (r:1 w:0) + /// Proof: `Grandpa::SetIdSession` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `Offences::ConcurrentReportsIndex` (r:1 w:1) + /// Proof: `Offences::ConcurrentReportsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Offences::Reports` (r:1 w:1) + /// Proof: `Offences::Reports` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ExternalValidatorsSlashes::SlashingMode` (r:1 w:0) + /// Proof: `ExternalValidatorsSlashes::SlashingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ActiveEra` (r:1 w:0) + /// Proof: `ExternalValidators::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `ExternalValidators::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::WhitelistedValidators` (r:1 w:0) + /// Proof: `ExternalValidators::WhitelistedValidators` (`max_values`: Some(1), `max_size`: Some(2002), added: 2497, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidatorsSlashes::NextSlashId` (r:1 w:1) + /// Proof: `ExternalValidatorsSlashes::NextSlashId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `v` is `[0, 1000]`. + /// The range of component `n` is `[0, 1]`. + fn report_equivocation(v: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1202 + v * (184 ±0)` + // Estimated: `4604 + n * (84 ±3) + v * (2660 ±0)` + // Minimum execution time: 183_867_000 picoseconds. + Weight::from_parts(186_282_000, 4604) + // Standard Error: 5_669 + .saturating_add(Weight::from_parts(12_384_539, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 84).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2660).saturating_mul(v.into())) + } } diff --git a/operator/runtime/testnet/Cargo.toml b/operator/runtime/testnet/Cargo.toml index ad02e6dd..9eb0d7d0 100644 --- a/operator/runtime/testnet/Cargo.toml +++ b/operator/runtime/testnet/Cargo.toml @@ -73,6 +73,7 @@ pallet-referenda = { workspace = true } pallet-safe-mode = { workspace = true } pallet-scheduler = { workspace = true } pallet-session = { workspace = true } +pallet-grandpa-benchmarking = { workspace = true, optional = true } pallet-session-benchmarking = { workspace = true, optional = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } @@ -197,6 +198,7 @@ std = [ "frame-metadata-hash-extension/std", "frame-support/std", "frame-system-benchmarking?/std", + "pallet-grandpa-benchmarking?/std", "pallet-session-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", @@ -340,6 +342,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", + "pallet-grandpa-benchmarking/runtime-benchmarks", "pallet-session-benchmarking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", diff --git a/operator/runtime/testnet/src/benchmarks.rs b/operator/runtime/testnet/src/benchmarks.rs index 63b8116c..f807eabe 100644 --- a/operator/runtime/testnet/src/benchmarks.rs +++ b/operator/runtime/testnet/src/benchmarks.rs @@ -22,7 +22,7 @@ frame_benchmarking::define_benchmarks!( [pallet_mmr, Mmr] [pallet_beefy_mmr, BeefyMmrLeaf] [pallet_babe, Babe] - [pallet_grandpa, Grandpa] + [pallet_grandpa, pallet_grandpa_benchmarking::Pallet::] [pallet_randomness, Randomness] // Substrate pallets diff --git a/operator/runtime/testnet/src/lib.rs b/operator/runtime/testnet/src/lib.rs index 0f1d0dd5..c177d49b 100644 --- a/operator/runtime/testnet/src/lib.rs +++ b/operator/runtime/testnet/src/lib.rs @@ -973,6 +973,18 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl pallet_session_benchmarking::Config for Runtime {} + impl pallet_grandpa_benchmarking::Config for Runtime { + fn benchmark_session_keys(grandpa: GrandpaId) -> Self::Keys { + use sp_core::crypto::UncheckedFrom; + + SessionKeys { + babe: sp_consensus_babe::AuthorityId::unchecked_from([1u8; 32]), + grandpa, + im_online: pallet_im_online::sr25519::AuthorityId::unchecked_from([1u8; 32]), + beefy: sp_consensus_beefy::ecdsa_crypto::AuthorityId::unchecked_from([1u8; 33]), + } + } + } impl baseline::Config for Runtime {} use frame_support::traits::WhitelistedStorageKeys; diff --git a/operator/runtime/testnet/src/weights/pallet_grandpa.rs b/operator/runtime/testnet/src/weights/pallet_grandpa.rs index c9c25235..6d02ae74 100644 --- a/operator/runtime/testnet/src/weights/pallet_grandpa.rs +++ b/operator/runtime/testnet/src/weights/pallet_grandpa.rs @@ -17,33 +17,34 @@ //! Autogenerated weights for `pallet_grandpa` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 51.0.0 -//! DATE: 2026-01-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 46.2.0 +//! DATE: 2026-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `ip-10-0-0-176`, CPU: `Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz` //! WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: -// frame-omni-bencher -// v1 +// ./target/production/datahaven-node // benchmark // pallet // --runtime // target/production/wbuild/datahaven-testnet-runtime/datahaven_testnet_runtime.compact.compressed.wasm +// --genesis-builder +// runtime // --pallet // pallet_grandpa // --extrinsic -// +// * +// --steps +// 50 +// --repeat +// 20 // --header // ../file_header.txt // --template // benchmarking/frame-weight-template.hbs // --output // runtime/testnet/src/weights/pallet_grandpa.rs -// --steps -// 50 -// --repeat -// 20 #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,24 +56,52 @@ use sp_std::marker::PhantomData; /// Weights for `pallet_grandpa`. pub struct WeightInfo(PhantomData); impl pallet_grandpa::WeightInfo for WeightInfo { - /// The range of component `x` is `[0, 1]`. - fn report_equivocation(prev: u32, _equivocations: u32) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 78_547_000 picoseconds. - Weight::from_parts(78_982_114, 0) - // Standard Error: 28_584 - .saturating_add(Weight::from_parts(129_485, 0).saturating_mul(prev.into())) - } /// Storage: `Grandpa::Stalled` (r:0 w:1) /// Proof: `Grandpa::Stalled` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn note_stalled() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_815_000 picoseconds. - Weight::from_parts(3_947_000, 0) + // Minimum execution time: 2_418_000 picoseconds. + Weight::from_parts(2_662_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `Session::CurrentIndex` (r:1 w:0) + /// Proof: `Session::CurrentIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::NextKeys` (r:1001 w:0) + /// Proof: `Session::NextKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Grandpa::SetIdSession` (r:1 w:0) + /// Proof: `Grandpa::SetIdSession` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) + /// Storage: `Offences::ConcurrentReportsIndex` (r:1 w:1) + /// Proof: `Offences::ConcurrentReportsIndex` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Offences::Reports` (r:1 w:1) + /// Proof: `Offences::Reports` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ExternalValidatorsSlashes::SlashingMode` (r:1 w:0) + /// Proof: `ExternalValidatorsSlashes::SlashingMode` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ActiveEra` (r:1 w:0) + /// Proof: `ExternalValidators::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `ExternalValidators::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidators::WhitelistedValidators` (r:1 w:0) + /// Proof: `ExternalValidators::WhitelistedValidators` (`max_values`: Some(1), `max_size`: Some(2002), added: 2497, mode: `MaxEncodedLen`) + /// Storage: `ExternalValidatorsSlashes::NextSlashId` (r:1 w:1) + /// Proof: `ExternalValidatorsSlashes::NextSlashId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `v` is `[0, 1000]`. + /// The range of component `n` is `[0, 1]`. + fn report_equivocation(v: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1202 + v * (184 ±0)` + // Estimated: `4604 + n * (84 ±3) + v * (2660 ±0)` + // Minimum execution time: 186_789_000 picoseconds. + Weight::from_parts(190_096_000, 4604) + // Standard Error: 5_639 + .saturating_add(Weight::from_parts(12_403_947, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(11_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(Weight::from_parts(0, 84).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2660).saturating_mul(v.into())) + } } diff --git a/operator/scripts/run-benchmarks.sh b/operator/scripts/run-benchmarks.sh index 922cda6a..97b1ccd4 100755 --- a/operator/scripts/run-benchmarks.sh +++ b/operator/scripts/run-benchmarks.sh @@ -1,6 +1,9 @@ #!/bin/bash -# DataHaven Benchmarking Script using frame-omni-bencher -# Automatically discovers and benchmarks all pallets in the runtime +# DataHaven Benchmarking Script +# Uses frame-omni-bencher for most pallets. +# Pallets listed in NODE_PALLETS are benchmarked via the native node binary instead, +# because frame-omni-bencher's WASM host lacks the crypto primitives they require +# (e.g. pallet_grandpa needs a real ed25519 verifier for report_equivocation). set -e @@ -10,6 +13,11 @@ STEPS=${2:-50} REPEAT=${3:-20} FEATURES="runtime-benchmarks" +# Pallets that must be benchmarked via the native node binary instead of frame-omni-bencher. +# Add pallet names here (space-separated) when their benchmarks require crypto or host +# functions that the WASM execution environment cannot provide. +NODE_PALLETS=("pallet_grandpa") + # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -52,9 +60,17 @@ if [ ! -f "$TEMPLATE_PATH" ]; then exit 1 fi -# Build the runtime WASM -echo -e "${YELLOW}Building runtime $RUNTIME (production profile) with features: $FEATURES${NC}" -cargo build --profile production --features "$FEATURES" -p datahaven-$RUNTIME-runtime +# Build the runtime WASM and the node binary +echo -e "${YELLOW}Building runtime $RUNTIME and node (production profile) with features: $FEATURES${NC}" +cargo build --profile production --features "$FEATURES" \ + -p datahaven-$RUNTIME-runtime \ + -p datahaven-node + +NODE_BIN="target/production/datahaven-node" +if [ ! -f "$NODE_BIN" ]; then + echo -e "${RED}Error: Node binary not found at $NODE_BIN${NC}" + exit 1 +fi # Get the WASM path WASM_PATH="target/production/wbuild/datahaven-$RUNTIME-runtime/datahaven_${RUNTIME}_runtime.compact.compressed.wasm" @@ -97,6 +113,48 @@ mkdir -p "$WEIGHTS_DIR" # Run benchmarks for each pallet using frame-omni-bencher echo -e "${GREEN}Starting benchmarks...${NC}\n" +# Returns 0 if the given pallet should be benchmarked via the node binary, 1 otherwise. +requires_node_benchmark() { + local PALLET=$1 + for node_pallet in "${NODE_PALLETS[@]}"; do + if [ "$node_pallet" == "$PALLET" ]; then + return 0 + fi + done + return 1 +} + +# Benchmark a pallet via the native node binary. +# Used for pallets whose benchmarks require host functions unavailable in WASM +# (e.g. real ed25519 verification for pallet_grandpa::report_equivocation). +benchmark_pallet_via_node() { + local PALLET=$1 + local OUTPUT_FILE=$2 + + echo -e "${YELLOW}Benchmarking $PALLET (via node binary)...${NC}" + + "$NODE_BIN" benchmark pallet \ + --runtime "$WASM_PATH" \ + --genesis-builder runtime \ + --pallet "$PALLET" \ + --extrinsic "*" \ + --header ../file_header.txt \ + --template "$TEMPLATE_PATH" \ + --output "$WEIGHTS_DIR/$OUTPUT_FILE.rs" \ + --steps "$STEPS" \ + --repeat "$REPEAT" 2>&1 | tee "benchmark_${PALLET}.log" + + local exit_code=${PIPESTATUS[0]} + + if [ $exit_code -eq 0 ]; then + echo -e "${GREEN}✓ $PALLET benchmarked successfully (node)${NC}" + return 0 + else + echo -e "${RED}✗ Error benchmarking $PALLET (node)${NC}" + return 1 + fi +} + # Function to run benchmark for a pallet benchmark_pallet() { local PALLET=$1 @@ -131,10 +189,18 @@ benchmark_pallet() { for PALLET in "${PALLETS[@]}"; do # Use the pallet name directly as the output file name OUTPUT_FILE="$PALLET" - if benchmark_pallet "$PALLET" "$OUTPUT_FILE"; then - RESULTS[$PALLET]="SUCCESS" + if requires_node_benchmark "$PALLET"; then + if benchmark_pallet_via_node "$PALLET" "$OUTPUT_FILE"; then + RESULTS[$PALLET]="SUCCESS" + else + RESULTS[$PALLET]="FAILED" + fi else - RESULTS[$PALLET]="FAILED" + if benchmark_pallet "$PALLET" "$OUTPUT_FILE"; then + RESULTS[$PALLET]="SUCCESS" + else + RESULTS[$PALLET]="FAILED" + fi fi echo "" done