diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/staking.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/staking.rs index 908168957d065..b0c5b784d96e4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/staking.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/staking.rs @@ -122,6 +122,8 @@ impl multi_block::Config for Runtime { type TargetSnapshotPerBlock = TargetSnapshotPerBlock; type AdminOrigin = EitherOfDiverse, EnsureSignedBy>; + type ManagerOrigin = + EitherOfDiverse, EnsureSignedBy>; type DataProvider = Staking; type MinerConfig = Self; type Verifier = MultiBlockElectionVerifier; diff --git a/prdoc/pr_10248.prdoc b/prdoc/pr_10248.prdoc new file mode 100644 index 0000000000000..3168facd7d7c7 --- /dev/null +++ b/prdoc/pr_10248.prdoc @@ -0,0 +1,13 @@ +title: Fix origin check in EPMB's manage extrinsic +doc: +- audience: Runtime Dev + description: |- + Fix origin check in EPMB's manage extrinsic and: + + - Break down `Admin` and `Manager` origins/extrinsics for easier configuration + - update the corresponding weights +crates: +- name: asset-hub-westend-runtime + bump: major +- name: pallet-election-provider-multi-block + bump: major diff --git a/substrate/frame/election-provider-multi-block/src/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/benchmarking.rs index f818cfc43ce11..d452bfb9c238c 100644 --- a/substrate/frame/election-provider-multi-block/src/benchmarking.rs +++ b/substrate/frame/election-provider-multi-block/src/benchmarking.rs @@ -21,7 +21,7 @@ use crate::{ }; use frame_benchmarking::v2::*; use frame_election_provider_support::{ElectionDataProvider, ElectionProvider}; -use frame_support::pallet_prelude::*; +use frame_support::{assert_ok, pallet_prelude::*}; const SNAPSHOT_NOT_BIG_ENOUGH: &'static str = "Snapshot page is not full, you should run this \ benchmark with enough genesis stakers in staking (DataProvider) to fill a page of voters/targets \ @@ -253,10 +253,81 @@ mod benchmarks { } #[benchmark(pov_mode = Measured)] - fn manage() -> Result<(), BenchmarkError> { - // TODO + fn manage_fallback() -> Result<(), BenchmarkError> { + // heaviest case is emergency set. + #[cfg(test)] + crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value()); + crate::Pallet::::start().unwrap(); + + // roll to signed so the snapshot exists + Pallet::::roll_until_before_matches(|| { + matches!(CurrentPhase::::get(), Phase::Signed(_)) + }); + + // set phase to emergency + CurrentPhase::::set(Phase::Emergency); + let origin = T::ManagerOrigin::try_successful_origin() + .map_err(|_| -> BenchmarkError { "cannot create manager origin".into() })?; + #[block] + { + // fallback might decide to fail, that's okay.. + let maybe_err = Pallet::::manage(origin, crate::ManagerOperation::EmergencyFallback); + //.. but it cannot be bad origin. + assert!(maybe_err.is_ok() || maybe_err.unwrap_err() != DispatchError::BadOrigin.into()); + } + + Ok(()) + } + + #[benchmark(pov_mode = Measured)] + fn admin_set() -> Result<(), BenchmarkError> { + // heaviest case is emergency set. + #[cfg(test)] + crate::mock::ElectionStart::set(sp_runtime::traits::Bounded::max_value()); + crate::Pallet::::start().unwrap(); + + // mine a single page solution. + let solution = crate::Pallet::::roll_to_signed_and_mine_solution(1); + + // verify to get the support. + let (voter_pages, all_targets, desired_targets) = + crate::unsigned::miner::OffchainWorkerMiner::::fetch_snapshot(T::Pages::get()) + .map_err(|_| -> BenchmarkError { "fetch_snapshot".into() })?; + let supports = crate::unsigned::miner::BaseMiner::::check_feasibility( + &solution, + &voter_pages, + &all_targets, + desired_targets, + ) + .map_err(|_| -> BenchmarkError { "check_feasibility".into() })?; + + let single_support = supports + .first() + .cloned() + .ok_or_else(|| -> BenchmarkError { "no support".into() })?; + + // set phase to emergency + CurrentPhase::::set(Phase::Emergency); + + // nothing is queued in verified just yet. + assert!(::queued_score().is_none()); + + let origin = T::AdminOrigin::try_successful_origin() + .map_err(|_| -> BenchmarkError { "cannot create admin origin".into() })?; #[block] - {} + { + assert_ok!(Pallet::::admin( + origin, + crate::AdminOperation::EmergencySetSolution( + sp_std::boxed::Box::new(single_support), + solution.score, + ), + )); + } + + // something is queued now. + assert!(::queued_score().is_some()); + Ok(()) } diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs index 236f42217cbfe..bd956cba23595 100644 --- a/substrate/frame/election-provider-multi-block/src/lib.rs +++ b/substrate/frame/election-provider-multi-block/src/lib.rs @@ -197,12 +197,14 @@ #[cfg(any(feature = "runtime-benchmarks", test))] use crate::signed::{CalculateBaseDeposit, CalculatePageDeposit}; +use crate::verifier::Verifier; use codec::{Decode, Encode, MaxEncodedLen}; use frame_election_provider_support::{ onchain, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, InstantElectionProvider, }; use frame_support::{ + dispatch::PostDispatchInfo, pallet_prelude::*, traits::{Defensive, EnsureOrigin}, DebugNoBound, Twox64Concat, @@ -213,13 +215,12 @@ use sp_arithmetic::{ traits::{CheckedAdd, Zero}, PerThing, UpperOf, }; -use sp_npos_elections::VoteWeight; +use sp_npos_elections::{EvaluateSupport, VoteWeight}; use sp_runtime::{ traits::{Hash, Saturating}, SaturatedConversion, }; use sp_std::{borrow::ToOwned, boxed::Box, prelude::*}; -use verifier::Verifier; #[cfg(test)] mod mock; @@ -445,7 +446,7 @@ impl From for ElectionError { } } -/// Different operations that the [`Config::AdminOrigin`] can perform on the pallet. +/// Different operations that only the [`Config::AdminOrigin`] can perform on the pallet. #[derive( Encode, Decode, @@ -460,27 +461,45 @@ impl From for ElectionError { #[codec(mel_bound(T: Config))] #[scale_info(skip_type_params(T))] pub enum AdminOperation { + /// Set the given (single page) emergency solution. + /// + /// Can only be called in emergency phase. + EmergencySetSolution(Box>>, ElectionScore), + /// Set the minimum untrusted score. This is directly communicated to the verifier component to + /// be taken into account. + /// + /// This is useful in preventing any serious issue where due to a bug we accept a very bad + /// solution. + SetMinUntrustedScore(ElectionScore), +} + +/// Different operations that the [`Config::ManagerOrigin`] (or [`Config::AdminOrigin`]) can perform +/// on the pallet. +#[derive( + Encode, + Decode, + DecodeWithMemTracking, + MaxEncodedLen, + TypeInfo, + DebugNoBound, + CloneNoBound, + PartialEqNoBound, + EqNoBound, +)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub enum ManagerOperation { /// Forcefully go to the next round, starting from the Off Phase. ForceRotateRound, /// Force-set the phase to the given phase. /// /// This can have many many combinations, use only with care and sufficient testing. ForceSetPhase(Phase), - /// Set the given (single page) emergency solution. - /// - /// Can only be called in emergency phase. - EmergencySetSolution(Box>>, ElectionScore), /// Trigger the (single page) fallback in `instant` mode, with the given parameters, and /// queue it if correct. /// /// Can only be called in emergency phase. EmergencyFallback, - /// Set the minimum untrusted score. This is directly communicated to the verifier component to - /// be taken into account. - /// - /// This is useful in preventing any serious issue where due to a bug we accept a very bad - /// solution. - SetMinUntrustedScore(ElectionScore), } /// Trait to notify other sub-systems that a round has ended. @@ -584,8 +603,15 @@ pub mod pallet { > + verifier::AsynchronousVerifier; /// The origin that can perform administration operations on this pallet. + /// + /// This is the highest privilege origin of this pallet, and should be configured + /// restrictively. type AdminOrigin: EnsureOrigin; + /// A less privileged origin than [`Config::AdminOrigin`], that can manage some election + /// aspects, without critical power. + type ManagerOrigin: EnsureOrigin; + /// An indicator of whether we should move to do the [`crate::types::Phase::Done`] or not? /// This is called at the end of the election process. /// @@ -604,18 +630,18 @@ pub mod pallet { impl Pallet { /// Manage this pallet. /// - /// The origin of this call must be [`Config::AdminOrigin`]. + /// The origin of this call must be [`Config::ManagerOrigin`]. /// - /// See [`AdminOperation`] for various operations that are possible. - #[pallet::weight(T::WeightInfo::manage())] + /// See [`ManagerOperation`] for various operations that are possible. + #[pallet::weight(T::WeightInfo::manage_fallback().max(T::WeightInfo::export_terminal()))] #[pallet::call_index(0)] - pub fn manage(origin: OriginFor, op: AdminOperation) -> DispatchResultWithPostInfo { - use crate::verifier::Verifier; - use sp_npos_elections::EvaluateSupport; - - let _ = T::AdminOrigin::ensure_origin(origin); + pub fn manage(origin: OriginFor, op: ManagerOperation) -> DispatchResultWithPostInfo { + T::ManagerOrigin::ensure_origin(origin.clone()).map(|_| ()).or_else(|_| { + // try admin origin as well as admin is a superset. + T::AdminOrigin::ensure_origin(origin).map(|_| ()) + })?; match op { - AdminOperation::EmergencyFallback => { + ManagerOperation::EmergencyFallback => { ensure!(Self::current_phase() == Phase::Emergency, Error::::UnexpectedPhase); // note: for now we run this on the msp, but we can make it configurable if need // be. @@ -634,25 +660,47 @@ pub mod pallet { })?; let score = fallback.evaluate(); T::Verifier::force_set_single_page_valid(fallback, 0, score); - Ok(().into()) + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::manage_fallback()), + pays_fee: Pays::No, + }) }, - AdminOperation::EmergencySetSolution(supports, score) => { - ensure!(Self::current_phase() == Phase::Emergency, Error::::UnexpectedPhase); - // TODO: hardcoding zero here doesn't make a lot of sense - T::Verifier::force_set_single_page_valid(*supports, 0, score); - Ok(().into()) - }, - AdminOperation::ForceSetPhase(phase) => { + ManagerOperation::ForceSetPhase(phase) => { Self::phase_transition(phase); - Ok(().into()) + Ok(PostDispatchInfo { + actual_weight: Some(T::DbWeight::get().reads_writes(1, 1)), + pays_fee: Pays::No, + }) }, - AdminOperation::ForceRotateRound => { + ManagerOperation::ForceRotateRound => { Self::rotate_round(); - Ok(().into()) + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::export_terminal()), + pays_fee: Pays::No, + }) + }, + } + } + + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::admin_set())] + pub fn admin(origin: OriginFor, op: AdminOperation) -> DispatchResultWithPostInfo { + T::AdminOrigin::ensure_origin(origin)?; + match op { + AdminOperation::EmergencySetSolution(supports, score) => { + ensure!(Self::current_phase() == Phase::Emergency, Error::::UnexpectedPhase); + T::Verifier::force_set_single_page_valid(*supports, 0, score); + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::admin_set()), + pays_fee: Pays::No, + }) }, AdminOperation::SetMinUntrustedScore(score) => { T::Verifier::set_minimum_score(score); - Ok(().into()) + Ok(PostDispatchInfo { + actual_weight: Some(T::DbWeight::get().reads_writes(1, 1)), + pays_fee: Pays::No, + }) }, } } @@ -1430,12 +1478,18 @@ where } pub(crate) fn roll_to_signed_and_mine_full_solution() -> PagedRawSolution { + use unsigned::miner::OffchainWorkerMiner; + Self::roll_to_signed_and_mine_solution(T::Pages::get()) + } + + pub(crate) fn roll_to_signed_and_mine_solution( + pages: PageIndex, + ) -> PagedRawSolution { use unsigned::miner::OffchainWorkerMiner; Self::roll_until_matches(|| Self::current_phase().is_signed()); // ensure snapshot is full. crate::Snapshot::::ensure_full_snapshot().expect("Snapshot is not full"); - OffchainWorkerMiner::::mine_solution(T::Pages::get(), false) - .expect("mine_solution failed") + OffchainWorkerMiner::::mine_solution(pages, false).expect("mine_solution failed") } pub(crate) fn submit_full_solution( @@ -1646,6 +1700,7 @@ mod phase_rotation { use super::{Event, *}; use crate::{mock::*, Phase}; use frame_election_provider_support::ElectionProvider; + use frame_support::assert_ok; #[test] fn single_page() { @@ -2782,58 +2837,9 @@ mod election_provider { } #[cfg(test)] -mod admin_ops { +mod manage_ops { use super::*; use crate::mock::*; - use frame_support::assert_ok; - - #[test] - fn set_solution_emergency_works() { - ExtBuilder::full().build_and_execute(|| { - roll_to_signed_open(); - - // we get a call to elect(0). this will cause emergency, since no fallback is allowed. - assert_eq!( - MultiBlock::elect(0), - Err(ElectionError::Fallback("Emergency phase started.".to_string())) - ); - assert_eq!(MultiBlock::current_phase(), Phase::Emergency); - - // we can now set the solution to emergency. - let (emergency, score) = emergency_solution(); - assert_ok!(MultiBlock::manage( - RuntimeOrigin::root(), - AdminOperation::EmergencySetSolution(Box::new(emergency), score) - )); - - assert_eq!(MultiBlock::current_phase(), Phase::Emergency); - assert_ok!(MultiBlock::elect(0)); - assert_eq!(MultiBlock::current_phase(), Phase::Off); - - assert_eq!( - multi_block_events(), - vec![ - Event::PhaseTransitioned { from: Phase::Off, to: Phase::Snapshot(3) }, - Event::PhaseTransitioned { - from: Phase::Snapshot(0), - to: Phase::Signed(SignedPhase::get() - 1) - }, - Event::PhaseTransitioned { - from: Phase::Signed(SignedPhase::get() - 1), - to: Phase::Emergency - }, - Event::PhaseTransitioned { from: Phase::Emergency, to: Phase::Off } - ] - ); - assert_eq!( - verifier_events(), - vec![verifier::Event::Queued( - ElectionScore { minimal_stake: 55, sum_stake: 130, sum_stake_squared: 8650 }, - None - )] - ); - }) - } #[test] fn trigger_fallback_works() { @@ -2842,6 +2848,15 @@ mod admin_ops { .build_and_execute(|| { roll_to_signed_open(); + // bad origin cannot call + assert_noop!( + MultiBlock::manage( + RuntimeOrigin::signed(Manager::get() + 1), + ManagerOperation::EmergencyFallback + ), + DispatchError::BadOrigin + ); + // we get a call to elect(0). this will cause emergency, since no fallback is // allowed. assert_eq!( @@ -2853,8 +2868,8 @@ mod admin_ops { // we can now set the solution to emergency, assuming fallback is set to onchain FallbackMode::set(FallbackModes::Onchain); assert_ok!(MultiBlock::manage( - RuntimeOrigin::root(), - AdminOperation::EmergencyFallback + RuntimeOrigin::signed(Manager::get()), + ManagerOperation::EmergencyFallback )); assert_eq!(MultiBlock::current_phase(), Phase::Emergency); @@ -2886,19 +2901,192 @@ mod admin_ops { }) } + // This scenario have multiple outcomes: + // 1. rotate in off => almost a noop + // 2. rotate mid signed, validation, unsigned, done, but NOT export => clear all data, move to + // next round and be off. Note: all of the data in this pallet is indexed by the round index, + // so moving to the next round will implicitly make the old data unavaioable, even if not + // cleared out. This secnario needs further testing. + // 3. rotate mid export: same as above, except staking will be out of sync and will also need + // governance intervention. + // + // This test is primarily checking the origin limits of this call, and will use scenario 2. #[test] - #[should_panic] fn force_rotate_round() { - // clears the snapshot and verifier data. - // leaves the signed data as is since we bump the round. - todo!(); + ExtBuilder::full().build_and_execute(|| { + roll_to_signed_open(); + let round = MultiBlock::round(); + let paged = + unsigned::miner::OffchainWorkerMiner::::mine_solution(Pages::get(), false) + .unwrap(); + load_signed_for_verification_and_start_and_roll_to_verified(99, paged, 0); + + // we have snapshot data now for this round. + assert_full_snapshot(); + // there is some data in the verifier pallet + assert!(verifier::QueuedSolution::::queued_score().is_some()); + // phase is + assert_eq!(MultiBlock::current_phase(), Phase::SignedValidation(2)); + + // force new round + + // bad origin cannot submit + assert_noop!( + MultiBlock::manage( + RuntimeOrigin::signed(Manager::get() + 1), + ManagerOperation::ForceRotateRound + ), + DispatchError::BadOrigin + ); + // manager can submit + assert_ok!(MultiBlock::manage( + RuntimeOrigin::signed(Manager::get()), + ManagerOperation::ForceRotateRound + )); + + // phase is off again + assert_eq!(MultiBlock::current_phase(), Phase::Off); + // round is bumped + assert_eq!(MultiBlock::round(), round + 1); + // snapshot is wiped + assert_none_snapshot(); + // verifier is in clean state + verifier::QueuedSolution::::assert_killed(); + }); + } + + #[test] + fn force_set_phase() { + ExtBuilder::full().build_and_execute(|| { + roll_to_signed_open(); + assert_eq!(MultiBlock::current_phase(), Phase::Signed(SignedPhase::get() - 1)); + + // bad origin cannot submit + assert_noop!( + MultiBlock::manage( + RuntimeOrigin::signed(Manager::get() + 1), + ManagerOperation::ForceSetPhase(Phase::Done) + ), + DispatchError::BadOrigin + ); + + // manager can submit. They skip the signed phases. + assert_ok!(MultiBlock::manage( + RuntimeOrigin::signed(Manager::get()), + ManagerOperation::ForceSetPhase(Phase::Unsigned(UnsignedPhase::get() - 1)) + )); + + assert_eq!(MultiBlock::current_phase(), Phase::Unsigned(UnsignedPhase::get() - 1)); + + // admin can also submit + assert_ok!(MultiBlock::manage( + RuntimeOrigin::root(), + ManagerOperation::ForceSetPhase(Phase::Unsigned(UnsignedPhase::get() - 2)) + )); + assert_eq!(MultiBlock::current_phase(), Phase::Unsigned(UnsignedPhase::get() - 2)); + }); + } +} +#[cfg(test)] +mod admin_ops { + use super::*; + use crate::mock::*; + + #[test] + fn set_solution_emergency_works() { + ExtBuilder::full().build_and_execute(|| { + roll_to_signed_open(); + + // bad origin cannot call + assert_noop!( + MultiBlock::admin( + RuntimeOrigin::signed(Manager::get() + 1), + AdminOperation::EmergencySetSolution(Default::default(), Default::default()) + ), + DispatchError::BadOrigin + ); + + // manager (non-root) cannot call + assert_noop!( + MultiBlock::admin( + RuntimeOrigin::signed(Manager::get()), + AdminOperation::EmergencySetSolution(Default::default(), Default::default()) + ), + DispatchError::BadOrigin + ); + + // we get a call to elect(0). this will cause emergency, since no fallback is allowed. + assert_eq!( + MultiBlock::elect(0), + Err(ElectionError::Fallback("Emergency phase started.".to_string())) + ); + assert_eq!(MultiBlock::current_phase(), Phase::Emergency); + + // we can now set the solution to emergency. + let (emergency, score) = emergency_solution(); + assert_ok!(MultiBlock::admin( + RuntimeOrigin::root(), + AdminOperation::EmergencySetSolution(Box::new(emergency), score) + )); + + assert_eq!(MultiBlock::current_phase(), Phase::Emergency); + assert_ok!(MultiBlock::elect(0)); + assert_eq!(MultiBlock::current_phase(), Phase::Off); + + assert_eq!( + multi_block_events(), + vec![ + Event::PhaseTransitioned { from: Phase::Off, to: Phase::Snapshot(3) }, + Event::PhaseTransitioned { + from: Phase::Snapshot(0), + to: Phase::Signed(SignedPhase::get() - 1) + }, + Event::PhaseTransitioned { + from: Phase::Signed(SignedPhase::get() - 1), + to: Phase::Emergency + }, + Event::PhaseTransitioned { from: Phase::Emergency, to: Phase::Off } + ] + ); + assert_eq!( + verifier_events(), + vec![verifier::Event::Queued( + ElectionScore { minimal_stake: 55, sum_stake: 130, sum_stake_squared: 8650 }, + None + )] + ); + }) } #[test] fn set_minimum_solution_score() { ExtBuilder::full().build_and_execute(|| { + // bad origin cannot call + assert_noop!( + MultiBlock::admin( + RuntimeOrigin::signed(Manager::get() + 1), + AdminOperation::SetMinUntrustedScore(ElectionScore { + minimal_stake: 100, + ..Default::default() + }) + ), + DispatchError::BadOrigin + ); + + // manager cannot call, only admin. + assert_noop!( + MultiBlock::admin( + RuntimeOrigin::signed(Manager::get()), + AdminOperation::SetMinUntrustedScore(ElectionScore { + minimal_stake: 100, + ..Default::default() + }) + ), + DispatchError::BadOrigin + ); + assert_eq!(VerifierPallet::minimum_score(), None); - assert_ok!(MultiBlock::manage( + assert_ok!(MultiBlock::admin( RuntimeOrigin::root(), AdminOperation::SetMinUntrustedScore(ElectionScore { minimal_stake: 100, diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index 27846e813600b..d2e5412f973f6 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -37,7 +37,7 @@ use frame_election_provider_support::{ }; pub use frame_support::{assert_noop, assert_ok}; use frame_support::{ - derive_impl, parameter_types, + derive_impl, ord_parameter_types, parameter_types, traits::{fungible::InspectHold, Hooks}, weights::{constants, Weight}, }; @@ -173,6 +173,10 @@ parameter_types! { pub static AreWeDone: AreWeDoneModes = AreWeDoneModes::Proceed; } +ord_parameter_types! { + pub const Manager: AccountId = 7; +} + impl Get> for AreWeDone { fn get() -> Phase { match >::get() { @@ -227,6 +231,7 @@ impl crate::Config for Runtime { type WeightInfo = (); type Verifier = VerifierPallet; type AdminOrigin = EnsureRoot; + type ManagerOrigin = frame_system::EnsureSignedBy; type Pages = Pages; type AreWeDone = AreWeDone; type OnRoundRotation = CleanRound; diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs index ee67db14fe12f..6047f2018d4ee 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -217,7 +217,11 @@ pub(crate) mod pallet { fn mutate_checked(mutate: impl FnOnce() -> R) -> R { let r = mutate(); #[cfg(debug_assertions)] - assert!(Self::sanity_check().is_ok()); + assert!(Self::sanity_check() + .inspect_err(|e| { + sublog!(error, "verifier", "sanity check failed: {:?}", e); + }) + .is_ok()); r } @@ -319,8 +323,6 @@ pub(crate) mod pallet { ValidSolution::X => QueuedSolutionX::::insert(Self::round(), page, supports), ValidSolution::Y => QueuedSolutionY::::insert(Self::round(), page, supports), } - - // write the score. QueuedSolutionScore::::insert(Self::round(), score); }) } diff --git a/substrate/frame/election-provider-multi-block/src/weights/mod.rs b/substrate/frame/election-provider-multi-block/src/weights/mod.rs index 2fc9b824c9723..5b0be0555de11 100644 --- a/substrate/frame/election-provider-multi-block/src/weights/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/weights/mod.rs @@ -129,7 +129,8 @@ pub mod traits { fn on_initialize_into_unsigned() -> Weight; fn export_non_terminal() -> Weight; fn export_terminal() -> Weight; - fn manage() -> Weight; + fn admin_set() -> Weight; + fn manage_fallback() -> Weight; } impl WeightInfo for () { @@ -157,7 +158,10 @@ pub mod traits { fn export_terminal() -> Weight { Default::default() } - fn manage() -> Weight { + fn admin_set() -> Weight { + Default::default() + } + fn manage_fallback() -> Weight { Default::default() } } diff --git a/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_dot_size.rs b/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_dot_size.rs index 67967eff9d159..da450c69a114b 100644 --- a/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_dot_size.rs +++ b/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_dot_size.rs @@ -325,11 +325,54 @@ impl crate::weights::traits::pallet_election_provider_m .saturating_add(T::DbWeight::get().reads(1036_u64)) .saturating_add(T::DbWeight::get().writes(1071_u64)) } - fn manage() -> Weight { + /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:0) + /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xa143099d7a337c5fd879b91b2b157c2d` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xa143099d7a337c5fd879b91b2b157c2d` (r:1 w:0) + /// Storage: `MultiBlockElection::Round` (r:1 w:0) + /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(388785), added: 391260, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) + /// Storage: `MultiBlockElection::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(64026), added: 66501, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x5640fd84ada5e16d1b6739279282536c` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5640fd84ada5e16d1b6739279282536c` (r:1 w:0) + /// Storage: `MultiBlockElection::DesiredTargets` (r:1 w:0) + /// Proof: `MultiBlockElection::DesiredTargets` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionScore` (r:1 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionScore` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:0) + /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionY` (r:0 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionY` (`max_values`: None, `max_size`: Some(33794026), added: 33796501, mode: `Measured`) + fn manage_fallback() -> Weight { + // Proof Size summary in bytes: + // Measured: `328713` + // Estimated: `332178` + // Minimum execution time: 538_906_259_000 picoseconds. + Weight::from_parts(539_733_270_000, 332178) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:0) + /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) + /// Storage: `MultiBlockElection::Round` (r:1 w:0) + /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionScore` (r:1 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionScore` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:0) + /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionY` (r:0 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionY` (`max_values`: None, `max_size`: Some(33794026), added: 33796501, mode: `Measured`) + fn admin_set() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 280_000 picoseconds. - Weight::from_parts(290_000, 0) + // Measured: `308` + // Estimated: `3773` + // Minimum execution time: 399_531_000 picoseconds. + Weight::from_parts(497_971_000, 3773) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_ksm_size.rs b/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_ksm_size.rs index 367b9e8a7028c..f7accc21fe446 100644 --- a/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_ksm_size.rs +++ b/substrate/frame/election-provider-multi-block/src/weights/pallet_election_provider_multi_block_ksm_size.rs @@ -325,11 +325,54 @@ impl crate::weights::traits::pallet_election_provider_m .saturating_add(T::DbWeight::get().reads(1798_u64)) .saturating_add(T::DbWeight::get().writes(1798_u64)) } - fn manage() -> Weight { + /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:0) + /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xa143099d7a337c5fd879b91b2b157c2d` (r:1 w:0) + /// Proof: UNKNOWN KEY `0xa143099d7a337c5fd879b91b2b157c2d` (r:1 w:0) + /// Storage: `MultiBlockElection::Round` (r:1 w:0) + /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(388785), added: 391260, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) + /// Storage: `MultiBlockElection::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(64026), added: 66501, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x5640fd84ada5e16d1b6739279282536c` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5640fd84ada5e16d1b6739279282536c` (r:1 w:0) + /// Storage: `MultiBlockElection::DesiredTargets` (r:1 w:0) + /// Proof: `MultiBlockElection::DesiredTargets` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionScore` (r:1 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionScore` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:0) + /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionY` (r:0 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionY` (`max_values`: None, `max_size`: Some(33794026), added: 33796501, mode: `Measured`) + fn manage_fallback() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 250_000 picoseconds. - Weight::from_parts(300_000, 0) + // Measured: `328713` + // Estimated: `332178` + // Minimum execution time: 538_906_259_000 picoseconds. + Weight::from_parts(539_733_270_000, 332178) + .saturating_add(T::DbWeight::get().reads(10_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:0) + /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) + /// Storage: `MultiBlockElection::Round` (r:1 w:0) + /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionScore` (r:1 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionScore` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:0) + /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionY` (r:0 w:1) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionY` (`max_values`: None, `max_size`: Some(33794026), added: 33796501, mode: `Measured`) + fn admin_set() -> Weight { + // Proof Size summary in bytes: + // Measured: `308` + // Estimated: `3773` + // Minimum execution time: 399_531_000 picoseconds. + Weight::from_parts(497_971_000, 3773) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } diff --git a/substrate/frame/staking-async/ahm-test/src/ah/mock.rs b/substrate/frame/staking-async/ahm-test/src/ah/mock.rs index 462e9ef41e515..e144cd7dbab9f 100644 --- a/substrate/frame/staking-async/ahm-test/src/ah/mock.rs +++ b/substrate/frame/staking-async/ahm-test/src/ah/mock.rs @@ -260,6 +260,7 @@ impl frame_election_provider_support::onchain::Config for OnChainConfig { impl multi_block::Config for Runtime { type AdminOrigin = EnsureRoot; + type ManagerOrigin = EnsureRoot; type DataProvider = Staking; type Fallback = frame_election_provider_support::onchain::OnChainExecution; type MinerConfig = Self; diff --git a/substrate/frame/staking-async/runtimes/parachain/src/staking.rs b/substrate/frame/staking-async/runtimes/parachain/src/staking.rs index 3e06f263432e0..75970f229b9c8 100644 --- a/substrate/frame/staking-async/runtimes/parachain/src/staking.rs +++ b/substrate/frame/staking-async/runtimes/parachain/src/staking.rs @@ -287,6 +287,7 @@ impl multi_block::Config for Runtime { type VoterSnapshotPerBlock = VoterSnapshotPerBlock; type TargetSnapshotPerBlock = TargetSnapshotPerBlock; type AdminOrigin = EnsureRoot; + type ManagerOrigin = EnsureRoot; type DataProvider = Staking; #[cfg(not(feature = "runtime-benchmarks"))] type Fallback = multi_block::Continue;