diff --git a/Cargo.lock b/Cargo.lock index 6c837a051ce4..2bb1a758bafa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14076,6 +14076,7 @@ dependencies = [ "pallet-balances", "pallet-broker", "pallet-message-queue", + "pallet-mmr", "pallet-session", "pallet-staking", "pallet-timestamp", @@ -14105,6 +14106,7 @@ dependencies = [ "sp-runtime", "sp-session", "sp-staking", + "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-executor", diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 7afdf49fe551..cfe373e8cba2 100644 --- a/polkadot/runtime/parachains/Cargo.toml +++ b/polkadot/runtime/parachains/Cargo.toml @@ -30,6 +30,7 @@ sp-keystore = { optional = true, workspace = true } sp-application-crypto = { optional = true, workspace = true } sp-tracing = { optional = true, workspace = true } sp-arithmetic = { workspace = true } +sp-std = { workspace = true, optional = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } @@ -37,6 +38,7 @@ pallet-balances = { workspace = true } pallet-babe = { workspace = true } pallet-broker = { workspace = true } pallet-message-queue = { workspace = true } +pallet-mmr = { workspace = true, optional = true } pallet-session = { workspace = true } pallet-staking = { workspace = true } pallet-timestamp = { workspace = true } @@ -86,6 +88,7 @@ std = [ "pallet-balances/std", "pallet-broker/std", "pallet-message-queue/std", + "pallet-mmr?/std", "pallet-session/std", "pallet-staking/std", "pallet-timestamp/std", @@ -109,6 +112,7 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", + "sp-std?/std", "xcm-executor/std", "xcm/std", ] @@ -120,6 +124,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-broker/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-mmr/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -128,6 +133,7 @@ runtime-benchmarks = [ "sp-application-crypto", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "sp-std", "static_assertions", "xcm-executor/runtime-benchmarks", ] @@ -141,6 +147,7 @@ try-runtime = [ "pallet-balances/try-runtime", "pallet-broker/try-runtime", "pallet-message-queue/try-runtime", + "pallet-mmr/try-runtime", "pallet-session/try-runtime", "pallet-staking/try-runtime", "pallet-timestamp/try-runtime", diff --git a/polkadot/runtime/parachains/src/paras/benchmarking.rs b/polkadot/runtime/parachains/src/paras/benchmarking.rs index 630b86132ab8..7bf8b833ed91 100644 --- a/polkadot/runtime/parachains/src/paras/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras/benchmarking.rs @@ -24,6 +24,7 @@ use polkadot_primitives::{ }; use sp_runtime::traits::{One, Saturating}; +pub mod mmr_setup; mod pvf_check; use self::pvf_check::{VoteCause, VoteOutcome}; diff --git a/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs new file mode 100644 index 000000000000..ab007692e78d --- /dev/null +++ b/polkadot/runtime/parachains/src/paras/benchmarking/mmr_setup.rs @@ -0,0 +1,40 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Implements benchmarking setup for the `merkle-mountain-range` pallet. + +use crate::paras::*; +use pallet_mmr::BenchmarkHelper; +use sp_std::vec; + +/// Struct to setup benchmarks for the `merkle-mountain-range` pallet. +pub struct MmrSetup(core::marker::PhantomData); + +impl BenchmarkHelper for MmrSetup +where + T: Config, +{ + fn setup() { + // Create a head with 1024 bytes of data. + let head = vec![42u8; 1024]; + + for para in 0..MAX_PARA_HEADS { + let id = (para as u32).into(); + let h = head.clone().into(); + Pallet::::heads_insert(&id, h); + } + } +} diff --git a/polkadot/runtime/parachains/src/paras/mod.rs b/polkadot/runtime/parachains/src/paras/mod.rs index 3f0b8659b159..a4c404de2a65 100644 --- a/polkadot/runtime/parachains/src/paras/mod.rs +++ b/polkadot/runtime/parachains/src/paras/mod.rs @@ -135,7 +135,7 @@ use serde::{Deserialize, Serialize}; pub use crate::Origin as ParachainOrigin; #[cfg(feature = "runtime-benchmarks")] -pub(crate) mod benchmarking; +pub mod benchmarking; #[cfg(test)] pub(crate) mod tests; @@ -1222,6 +1222,15 @@ const INVALID_TX_BAD_VALIDATOR_IDX: u8 = 1; const INVALID_TX_BAD_SUBJECT: u8 = 2; const INVALID_TX_DOUBLE_VOTE: u8 = 3; +/// This is intermediate "fix" for this issue: +/// +/// +/// It does not actually fix it, but makes the worst case better. Without that limit someone +/// could completely DoS the relay chain by registering a ridiculously high amount of paras. +/// With this limit the same attack could lead to some parachains ceasing to being able to +/// communicate via offchain XCMP. Snowbridge will still work as it only cares about `BridgeHub`. +pub const MAX_PARA_HEADS: usize = 1024; + impl Pallet { /// This is a call to schedule code upgrades for parachains which is safe to be called /// outside of this module. That means this function does all checks necessary to ensure @@ -1291,6 +1300,16 @@ impl Pallet { }) } + /// Get a list of the first [`MAX_PARA_HEADS`] para heads sorted by para_id. + /// This method is likely to be removed in the future. + pub fn sorted_para_heads() -> Vec<(u32, Vec)> { + let mut heads: Vec<(u32, Vec)> = + Heads::::iter().map(|(id, head)| (id.into(), head.0)).collect(); + heads.sort_by_key(|(id, _)| *id); + heads.truncate(MAX_PARA_HEADS); + heads + } + // Apply all para actions queued for the given session index. // // The actions to take are based on the lifecycle of of the paras. diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index f93a3ad65754..50970965e11e 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -226,6 +226,7 @@ runtime-benchmarks = [ "pallet-asset-rate/runtime-benchmarks", "pallet-babe/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-beefy-mmr/runtime-benchmarks", "pallet-bounties/runtime-benchmarks", "pallet-child-bounties/runtime-benchmarks", "pallet-collective/runtime-benchmarks", @@ -330,7 +331,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = ["rococo-runtime-constants/fast-runtime"] -runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"] +runtime-metrics = [ + "polkadot-runtime-parachains/runtime-metrics", + "sp-io/with-tracing", +] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5adffbd7422f..c7da339b9815 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -1307,9 +1307,11 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; type Hashing = Keccak256; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); type LeafData = pallet_beefy_mmr::Pallet; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; + type WeightInfo = weights::pallet_mmr::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup; } parameter_types! { @@ -1319,13 +1321,8 @@ parameter_types! { pub struct ParaHeadsRootProvider; impl BeefyDataProvider for ParaHeadsRootProvider { fn extra_data() -> H256 { - let mut para_heads: Vec<(u32, Vec)> = parachains_paras::Parachains::::get() - .into_iter() - .filter_map(|id| { - parachains_paras::Heads::::get(&id).map(|head| (id.into(), head.0)) - }) - .collect(); - para_heads.sort(); + let para_heads: Vec<(u32, Vec)> = + parachains_paras::Pallet::::sorted_para_heads(); binary_merkle_tree::merkle_root::( para_heads.into_iter().map(|pair| pair.encode()), ) @@ -1746,6 +1743,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_parameters, Parameters] [pallet_preimage, Preimage] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 3c6845dfb43e..c9204cc944fa 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -25,6 +25,7 @@ pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nis; pub mod pallet_parameters; diff --git a/polkadot/runtime/rococo/src/weights/pallet_mmr.rs b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs new file mode 100644 index 000000000000..361bfc7a661b --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs @@ -0,0 +1,77 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-15, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/testnet/polkadot +// benchmark +// pallet +// --steps=5 +// --repeat=1 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_mmr +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_mmr::WeightInfo for WeightInfo { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Heads` (r:2049 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::Nodes` (r:0 w:1000) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `2140817` + // Estimated: `7213082` + // Minimum execution time: 20_387_000_000 picoseconds. + Weight::from_parts(223_625_477_528, 0) + .saturating_add(Weight::from_parts(0, 7213082)) + // Standard Error: 310_550_970 + .saturating_add(Weight::from_parts(16_906_397_286, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2053)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + } +} diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index 9e739f4c7fe6..d2bafb33d2cb 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -240,6 +240,7 @@ runtime-benchmarks = [ "pallet-babe/runtime-benchmarks", "pallet-bags-list/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-beefy-mmr/runtime-benchmarks", "pallet-collective/runtime-benchmarks", "pallet-conviction-voting/runtime-benchmarks", "pallet-delegated-staking/runtime-benchmarks", @@ -346,7 +347,10 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # Set timing constants (e.g. session period) to faster versions to speed up testing. fast-runtime = [] -runtime-metrics = ["polkadot-runtime-parachains/runtime-metrics", "sp-io/with-tracing"] +runtime-metrics = [ + "polkadot-runtime-parachains/runtime-metrics", + "sp-io/with-tracing", +] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f0b16e731d9e..acd6f96878c9 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -342,9 +342,11 @@ impl pallet_mmr::Config for Runtime { const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX; type Hashing = Keccak256; type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; - type WeightInfo = (); type LeafData = pallet_beefy_mmr::Pallet; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; + type WeightInfo = weights::pallet_mmr::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = parachains_paras::benchmarking::mmr_setup::MmrSetup; } /// MMR helper types. @@ -366,13 +368,8 @@ parameter_types! { pub struct ParaHeadsRootProvider; impl BeefyDataProvider for ParaHeadsRootProvider { fn extra_data() -> H256 { - let mut para_heads: Vec<(u32, Vec)> = parachains_paras::Parachains::::get() - .into_iter() - .filter_map(|id| { - parachains_paras::Heads::::get(&id).map(|head| (id.into(), head.0)) - }) - .collect(); - para_heads.sort_by_key(|k| k.0); + let para_heads: Vec<(u32, Vec)> = + parachains_paras::Pallet::::sorted_para_heads(); binary_merkle_tree::merkle_root::( para_heads.into_iter().map(|pair| pair.encode()), ) @@ -1755,6 +1752,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] [pallet_offences, OffencesBench::] diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index f6a9008d7187..c3ed2b5a75ec 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -26,6 +26,7 @@ pub mod pallet_fast_unstake; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nomination_pools; pub mod pallet_preimage; diff --git a/polkadot/runtime/westend/src/weights/pallet_mmr.rs b/polkadot/runtime/westend/src/weights/pallet_mmr.rs new file mode 100644 index 000000000000..1a410e7fc46e --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_mmr.rs @@ -0,0 +1,76 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-17, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `am1max.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/testnet/polkadot +// benchmark +// pallet +// --steps=5 +// --repeat=1 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_mmr +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_mmr::WeightInfo for WeightInfo { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Heads` (r:1025 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `Mmr::Nodes` (r:8 w:4) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1071043 + x * (39 ±0)` + // Estimated: `3608787 + x * (39 ±6)` + // Minimum execution time: 11_102_000_000 picoseconds. + Weight::from_parts(21_772_042_215, 0) + .saturating_add(Weight::from_parts(0, 3608787)) + .saturating_add(T::DbWeight::get().reads(1031)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 39).saturating_mul(x.into())) + } +} diff --git a/prdoc/pr_4751.prdoc b/prdoc/pr_4751.prdoc new file mode 100644 index 000000000000..5a2c42209088 --- /dev/null +++ b/prdoc/pr_4751.prdoc @@ -0,0 +1,22 @@ +title: "Use all parachain heads for BEEFY MMR extra data" + +doc: + - audience: Runtime Dev + description: | + Previously, the extra data in an MMR leaf nodes was only computed based on lease-based parachain heads. + This PR extends the extra data to include others, including on-demand parachain heads. + Currently, the number of heads is limited to the first 1024 heads sorted by para id. + +crates: + - name: polkadot-runtime-parachains + bump: minor + - name: rococo-runtime + bump: minor + - name: westend-runtime + bump: minor + - name: pallet-mmr + bump: major + - name: pallet-beefy-mmr + bump: minor + - name: polkadot-sdk + bump: minor diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a1896325ee93..78c7bba64579 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1605,6 +1605,8 @@ impl pallet_mmr::Config for Runtime { type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } parameter_types! { diff --git a/substrate/frame/beefy-mmr/Cargo.toml b/substrate/frame/beefy-mmr/Cargo.toml index 11a7b281e87d..92e903af138d 100644 --- a/substrate/frame/beefy-mmr/Cargo.toml +++ b/substrate/frame/beefy-mmr/Cargo.toml @@ -64,3 +64,10 @@ try-runtime = [ "pallet-session/try-runtime", "sp-runtime/try-runtime", ] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-mmr/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", +] diff --git a/substrate/frame/beefy-mmr/src/mock.rs b/substrate/frame/beefy-mmr/src/mock.rs index 0521bdabbe49..3adef4f32bf4 100644 --- a/substrate/frame/beefy-mmr/src/mock.rs +++ b/substrate/frame/beefy-mmr/src/mock.rs @@ -93,6 +93,9 @@ impl pallet_mmr::Config for Test { type BlockHashProvider = pallet_mmr::DefaultBlockHashProvider; type WeightInfo = (); + + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl pallet_beefy::Config for Test { diff --git a/substrate/frame/merkle-mountain-range/src/benchmarking.rs b/substrate/frame/merkle-mountain-range/src/benchmarking.rs index 9eb676a4ee44..07afd9529eb2 100644 --- a/substrate/frame/merkle-mountain-range/src/benchmarking.rs +++ b/substrate/frame/merkle-mountain-range/src/benchmarking.rs @@ -28,10 +28,13 @@ benchmarks_instance_pallet! { let x in 1 .. 1_000; let leaves = x as NodeIndex; - }: { - for b in 0..leaves { - Pallet::::on_initialize((b as u32).into()); + + <>::BenchmarkHelper as BenchmarkHelper>::setup(); + for leaf in 0..(leaves - 1) { + Pallet::::on_initialize((leaf as u32).into()); } + }: { + Pallet::::on_initialize((leaves as u32 - 1).into()); } verify { assert_eq!(crate::NumberOfLeaves::::get(), leaves); } diff --git a/substrate/frame/merkle-mountain-range/src/default_weights.rs b/substrate/frame/merkle-mountain-range/src/default_weights.rs index 52e3f130383f..b0ef0539018c 100644 --- a/substrate/frame/merkle-mountain-range/src/default_weights.rs +++ b/substrate/frame/merkle-mountain-range/src/default_weights.rs @@ -24,7 +24,8 @@ use frame_support::weights::{ }; impl crate::WeightInfo for () { - fn on_initialize(peaks: u64) -> Weight { + fn on_initialize(peaks: u32) -> Weight { + let peaks = u64::from(peaks); // Reading the parent hash. let leaf_weight = DbWeight::get().reads(1); // Blake2 hash cost. diff --git a/substrate/frame/merkle-mountain-range/src/lib.rs b/substrate/frame/merkle-mountain-range/src/lib.rs index cacb33b50434..0ab44711bcf5 100644 --- a/substrate/frame/merkle-mountain-range/src/lib.rs +++ b/substrate/frame/merkle-mountain-range/src/lib.rs @@ -124,7 +124,18 @@ impl BlockHashProvider, T::Hash> } pub trait WeightInfo { - fn on_initialize(peaks: NodeIndex) -> Weight; + fn on_initialize(peaks: u32) -> Weight; +} + +/// This trait decoples dependencies on pallets needed for benchmarking. +#[cfg(feature = "runtime-benchmarks")] +pub trait BenchmarkHelper { + fn setup(); +} + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkHelper for () { + fn setup() {} } /// An MMR specific to the pallet. @@ -205,6 +216,10 @@ pub mod pallet { /// Weights for this pallet. type WeightInfo: WeightInfo; + + /// Benchmarking setup helper trait. + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: BenchmarkHelper; } /// Latest MMR Root hash. @@ -238,14 +253,14 @@ pub mod pallet { // MMR push never fails, but better safe than sorry. if mmr.push(data).is_none() { log::error!(target: "runtime::mmr", "MMR push failed"); - return T::WeightInfo::on_initialize(peaks_before) + return T::WeightInfo::on_initialize(peaks_before as u32) } // Update the size, `mmr.finalize()` should also never fail. let (leaves, root) = match mmr.finalize() { Ok((leaves, root)) => (leaves, root), Err(e) => { log::error!(target: "runtime::mmr", "MMR finalize failed: {:?}", e); - return T::WeightInfo::on_initialize(peaks_before) + return T::WeightInfo::on_initialize(peaks_before as u32) }, }; >::on_new_root(&root); @@ -255,7 +270,7 @@ pub mod pallet { let peaks_after = sp_mmr_primitives::utils::NodesUtils::new(leaves).number_of_peaks(); - T::WeightInfo::on_initialize(peaks_before.max(peaks_after)) + T::WeightInfo::on_initialize(peaks_before.max(peaks_after) as u32) } } } diff --git a/substrate/frame/merkle-mountain-range/src/mock.rs b/substrate/frame/merkle-mountain-range/src/mock.rs index 8318b20e8307..606719c6deba 100644 --- a/substrate/frame/merkle-mountain-range/src/mock.rs +++ b/substrate/frame/merkle-mountain-range/src/mock.rs @@ -46,6 +46,8 @@ impl Config for Test { type OnNewRoot = (); type BlockHashProvider = DefaultBlockHashProvider; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } #[derive(Encode, Decode, Clone, Default, Eq, PartialEq, Debug)] diff --git a/umbrella/Cargo.toml b/umbrella/Cargo.toml index 94ba09421d40..79e7c0c38eda 100644 --- a/umbrella/Cargo.toml +++ b/umbrella/Cargo.toml @@ -269,6 +269,7 @@ runtime-benchmarks = [ "pallet-babe?/runtime-benchmarks", "pallet-bags-list?/runtime-benchmarks", "pallet-balances?/runtime-benchmarks", + "pallet-beefy-mmr?/runtime-benchmarks", "pallet-bounties?/runtime-benchmarks", "pallet-bridge-grandpa?/runtime-benchmarks", "pallet-bridge-messages?/runtime-benchmarks",