diff --git a/Cargo.lock b/Cargo.lock index 609ccb0baeef9..db23e3d76b84a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5012,6 +5012,7 @@ dependencies = [ "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", + "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", "pallet-gilt", "pallet-grandpa", @@ -5866,6 +5867,7 @@ dependencies = [ "frame-system", "log 0.4.14", "pallet-balances", + "pallet-election-provider-support-benchmarking", "parity-scale-codec", "parking_lot 0.12.0", "rand 0.7.3", @@ -5881,6 +5883,18 @@ dependencies = [ "strum", ] +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-system", + "parity-scale-codec", + "sp-npos-elections", + "sp-runtime", +] + [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" @@ -9106,7 +9120,7 @@ dependencies = [ name = "sc-sysinfo" version = "6.0.0-dev" dependencies = [ - "futures 0.3.19", + "futures 0.3.21", "libc", "log 0.4.14", "rand 0.7.3", diff --git a/Cargo.toml b/Cargo.toml index 576bae6b574b2..fe0704194c4b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ members = [ "frame/try-runtime", "frame/election-provider-multi-phase", "frame/election-provider-support", + "frame/election-provider-support/benchmarking", "frame/election-provider-support/solution-type", "frame/election-provider-support/solution-type/fuzzer", "frame/examples/basic", diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index 686508b47dba1..41b2402d33a53 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -65,6 +65,7 @@ pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = f pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } +pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } @@ -196,6 +197,7 @@ runtime-benchmarks = [ "pallet-conviction-voting/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-election-provider-multi-phase/runtime-benchmarks", + "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", "pallet-gilt/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 57584bed39b2c..dce319952f2c6 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -643,17 +643,18 @@ impl Get> for OffchainRandomBalancing { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; type Solver = SequentialPhragmen< AccountId, pallet_election_provider_multi_phase::SolutionAccuracyOf, >; type DataProvider = ::DataProvider; + type WeightInfo = frame_election_provider_support::weights::SubstrateWeight; } -impl onchain::BoundedExecutionConfig for OnChainSeqPhragmen { - type VotersBound = ConstU32<20_000>; +impl onchain::BoundedConfig for OnChainSeqPhragmen { + type VotersBound = MaxElectingVoters; type TargetsBound = ConstU32<2_000>; } @@ -1531,6 +1532,7 @@ mod benches { [pallet_contracts, Contracts] [pallet_democracy, Democracy] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] + [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] [pallet_gilt, Gilt] [pallet_grandpa, Grandpa] @@ -1847,6 +1849,7 @@ impl_runtime_apis! { // which is why we need these two lines below. use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; + use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; @@ -1868,11 +1871,13 @@ impl_runtime_apis! { // which is why we need these two lines below. use pallet_session_benchmarking::Pallet as SessionBench; use pallet_offences_benchmarking::Pallet as OffencesBench; + use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; impl pallet_session_benchmarking::Config for Runtime {} impl pallet_offences_benchmarking::Config for Runtime {} + impl pallet_election_provider_support_benchmarking::Config for Runtime {} impl frame_system_benchmarking::Config for Runtime {} impl baseline::Config for Runtime {} diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 37d8e9e37a5f4..15f53e7da0823 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -173,10 +173,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index 25f98d965d86b..48134966a9253 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -17,7 +17,9 @@ static_assertions = "1.1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive", ] } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.1", default-features = false, features = [ + "derive", +] } log = { version = "0.4.14", default-features = false } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } @@ -33,11 +35,14 @@ frame-election-provider-support = { version = "4.0.0-dev", default-features = fa # Optional imports for benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } +pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../election-provider-support/benchmarking", optional = true } rand = { version = "0.7.3", default-features = false, optional = true, features = [ "alloc", "small_rng", ] } -strum = { optional = true, default-features = false, version = "0.23.0", features = ["derive"] } +strum = { optional = true, default-features = false, version = "0.23.0", features = [ + "derive", +] } [dev-dependencies] parking_lot = "0.12.0" @@ -46,7 +51,6 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-io = { version = "6.0.0", path = "../../primitives/io" } sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../primitives/npos-elections" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index d6f040363dba0..7c06ff6bee546 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -276,10 +276,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; + type WeightInfo = (); } pub struct MockFallback; @@ -304,7 +305,7 @@ impl InstantElectionProvider for MockFallback { max_voters, max_targets, ) - .map_err(|_| "UnboundedExecution failed") + .map_err(|_| "onchain::UnboundedExecution failed.") } else { super::NoFallback::::elect_with_bounds(max_voters, max_targets) } diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml new file mode 100644 index 0000000000000..e9719be139a6d --- /dev/null +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Benchmarking for election provider support onchain config trait" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ + "derive", +] } +sp-npos-elections = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/npos-elections" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } +frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = ".." } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../benchmarking", optional = true } + + +[features] +default = ["std"] +std = [ + "codec/std", + "sp-npos-elections/std", + "sp-runtime/std", + "frame-benchmarking/std", + "frame-system/std", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", +] diff --git a/frame/election-provider-support/benchmarking/src/lib.rs b/frame/election-provider-support/benchmarking/src/lib.rs new file mode 100644 index 0000000000000..547e35bed36e8 --- /dev/null +++ b/frame/election-provider-support/benchmarking/src/lib.rs @@ -0,0 +1,91 @@ +// This file is part of Substrate. + +// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Election provider support pallet benchmarking. +//! This is separated into its own crate to avoid bloating the size of the runtime. + +#![cfg(feature = "runtime-benchmarks")] +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::Decode; +use frame_benchmarking::{benchmarks, Vec}; +use frame_election_provider_support::{NposSolver, PhragMMS, SequentialPhragmen}; + +pub struct Pallet(frame_system::Pallet); +pub trait Config: frame_system::Config {} + +const VOTERS: [u32; 2] = [1_000, 2_000]; +const TARGETS: [u32; 2] = [500, 1_000]; +const VOTES_PER_VOTER: [u32; 2] = [5, 16]; + +const SEED: u32 = 999; +fn set_up_voters_targets( + voters_len: u32, + targets_len: u32, + degree: usize, +) -> (Vec<(AccountId, u64, impl IntoIterator)>, Vec) { + // fill targets. + let mut targets = (0..targets_len) + .map(|i| frame_benchmarking::account::("Target", i, SEED)) + .collect::>(); + assert!(targets.len() > degree, "we should always have enough voters to fill"); + targets.truncate(degree); + + // fill voters. + let voters = (0..voters_len) + .map(|i| { + let voter = frame_benchmarking::account::("Voter", i, SEED); + (voter, 1_000, targets.clone()) + }) + .collect::>(); + + (voters, targets) +} + +benchmarks! { + phragmen { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + SequentialPhragmen:: + ::solve(d as usize, targets, voters).is_ok() + ); + } + + phragmms { + // number of votes in snapshot. + let v in (VOTERS[0]) .. VOTERS[1]; + // number of targets in snapshot. + let t in (TARGETS[0]) .. TARGETS[1]; + // number of votes per voter (ie the degree). + let d in (VOTES_PER_VOTER[0]) .. VOTES_PER_VOTER[1]; + + let (voters, targets) = set_up_voters_targets::(v, t, d as usize); + }: { + assert!( + PhragMMS:: + ::solve(d as usize, targets, voters).is_ok() + ); + } +} diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 19735cf6035ac..37ea2fcc59091 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -170,7 +170,7 @@ pub mod onchain; pub mod traits; #[cfg(feature = "std")] use codec::{Decode, Encode}; -use frame_support::{BoundedVec, RuntimeDebug}; +use frame_support::{weights::Weight, BoundedVec, RuntimeDebug}; use sp_runtime::traits::Bounded; use sp_std::{fmt::Debug, prelude::*}; @@ -195,6 +195,9 @@ pub use sp_arithmetic; #[doc(hidden)] pub use sp_std; +pub mod weights; +pub use weights::WeightInfo; + #[cfg(test)] mod mock; #[cfg(test)] @@ -523,6 +526,12 @@ pub trait NposSolver { targets: Vec, voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error>; + + /// Measure the weight used in the calculation of the solver. + /// - `voters` is the number of voters. + /// - `targets` is the number of targets. + /// - `vote_degree` is the degree ie the maximum numbers of votes per voter. + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight; } /// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the @@ -547,6 +556,10 @@ impl< ) -> Result, Self::Error> { sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) } + + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { + T::phragmen(voters, targets, vote_degree) + } } /// A wrapper for [`sp_npos_elections::phragmms()`] that implements [`NposSolver`]. See the @@ -571,6 +584,10 @@ impl< ) -> Result, Self::Error> { sp_npos_elections::phragmms(winners, targets, voters, Balancing::get()) } + + fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { + T::phragmms(voters, targets, vote_degree) + } } /// A voter, at the level of abstraction of this crate. diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 57fd931a467d1..62e76c3888822 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -15,9 +15,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. +//! An implementation of [`ElectionProvider`] that uses an `NposSolver` to do the election. As the +//! name suggests, this is meant to be used onchain. Given how heavy the calculations are, please be +//! careful when using it onchain. -use crate::{ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver}; +use crate::{ + Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo, +}; use frame_support::{traits::Get, weights::DispatchClass}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; @@ -41,39 +45,32 @@ impl From for Error { /// /// This will accept voting data on the fly and produce the results immediately. /// -/// Finally, the [`ElectionProvider`] implementation of this type does not impose any limits on the +/// The [`ElectionProvider`] implementation of this type does not impose any dynamic limits on the /// number of voters and targets that are fetched. This could potentially make this unsuitable for -/// execution onchain. One could, however, impose bounds on it by using for example -/// `BoundedExecution` which will the bounds provided in the configuration. +/// execution onchain. One could, however, impose bounds on it by using `BoundedExecution` using the +/// `MaxVoters` and `MaxTargets` bonds in the `BoundedConfig` trait. /// -/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs, -/// either via using `BoundedExecution` and imposing the bounds there, or dynamically via calling -/// `elect_with_bounds` providing these bounds. If you use `elect_with_bounds` along with -/// `InstantElectionProvider`, the bound that would be used is the minimum of the 2 bounds. -/// -/// It is advisable to use the former ([`ElectionProvider::elect`]) only at genesis, or for testing, -/// the latter [`InstantElectionProvider::elect_with_bounds`] for onchain operations, with -/// thoughtful bounds. +/// On the other hand, the [`InstantElectionProvider`] implementation does limit these inputs +/// dynamically. If you use `elect_with_bounds` along with `InstantElectionProvider`, the bound that +/// would be used is the minimum of the dynamic bounds given as arguments to `elect_with_bounds` and +/// the trait bounds (`MaxVoters` and `MaxTargets`). /// /// Please use `BoundedExecution` at all times except at genesis or for testing, with thoughtful /// bounds in order to bound the potential execution time. Limit the use `UnboundedExecution` at /// genesis or for testing, as it does not bound the inputs. However, this can be used with /// `[InstantElectionProvider::elect_with_bounds`] that dynamically imposes limits. -pub struct BoundedExecution(PhantomData); +pub struct BoundedExecution(PhantomData); /// An unbounded variant of [`BoundedExecution`]. /// /// ### Warning /// -/// This can be very expensive to run frequently on-chain. Use with care. Moreover, this -/// implementation ignores the additional data of the election data provider and gives no insight on -/// how much weight was consumed. -pub struct UnboundedExecution(PhantomData); - -/// Configuration trait of [`UnboundedExecution`]. -pub trait ExecutionConfig { - /// Something that implements the system pallet configs. This is to enable to register extra - /// weight. +/// This can be very expensive to run frequently on-chain. Use with care. +pub struct UnboundedExecution(PhantomData); + +/// Configuration trait for an onchain election execution. +pub trait Config { + /// Needed for weight registration. type System: frame_system::Config; /// `NposSolver` that should be used, an example would be `PhragMMS`. type Solver: NposSolver< @@ -85,17 +82,18 @@ pub trait ExecutionConfig { AccountId = ::AccountId, BlockNumber = ::BlockNumber, >; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; } -/// Configuration trait of [`BoundedExecution`]. -pub trait BoundedExecutionConfig: ExecutionConfig { +pub trait BoundedConfig: Config { /// Bounds the number of voters. type VotersBound: Get; /// Bounds the number of targets. type TargetsBound: Get; } -fn elect_with( +fn elect_with( maybe_max_voters: Option, maybe_max_targets: Option, ) -> Result::AccountId>, Error> { @@ -104,6 +102,9 @@ fn elect_with( T::DataProvider::electable_targets(maybe_max_targets).map_err(Error::DataProvider)?; let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; + let voters_len = voters.len() as u32; + let targets_len = targets.len() as u32; + let stake_map: BTreeMap<_, _> = voters .iter() .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) @@ -118,7 +119,11 @@ fn elect_with( let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; - let weight = ::BlockWeights::get().max_block; + let weight = T::Solver::weight::( + voters_len, + targets_len, + ::MaxVotesPerVoter::get(), + ); frame_system::Pallet::::register_extra_weight_unchecked( weight, DispatchClass::Mandatory, @@ -127,13 +132,13 @@ fn elect_with( Ok(to_supports(&staked)) } -impl ElectionProvider for UnboundedExecution { +impl ElectionProvider for UnboundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result::AccountId>, Self::Error> { + fn elect() -> Result, Self::Error> { // This should not be called if not in `std` mode (and therefore neither in genesis nor in // testing) if cfg!(not(feature = "std")) { @@ -147,7 +152,7 @@ impl ElectionProvider for UnboundedExecution { } } -impl InstantElectionProvider for UnboundedExecution { +impl InstantElectionProvider for UnboundedExecution { fn elect_with_bounds( max_voters: usize, max_targets: usize, @@ -156,18 +161,18 @@ impl InstantElectionProvider for UnboundedExecution { } } -impl ElectionProvider for BoundedExecution { +impl ElectionProvider for BoundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; - fn elect() -> Result::AccountId>, Self::Error> { + fn elect() -> Result, Self::Error> { elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } } -impl InstantElectionProvider for BoundedExecution { +impl InstantElectionProvider for BoundedExecution { fn elect_with_bounds( max_voters: usize, max_targets: usize, @@ -182,6 +187,8 @@ impl InstantElectionProvider for BoundedExecution #[cfg(test)] mod tests { use super::*; + use crate::{PhragMMS, SequentialPhragmen}; + use frame_support::traits::ConstU32; use sp_npos_elections::Support; use sp_runtime::Perbill; type AccountId = u64; @@ -228,13 +235,32 @@ mod tests { type MaxConsumers = frame_support::traits::ConstU32<16>; } - impl ExecutionConfig for Runtime { - type System = Self; - type Solver = crate::SequentialPhragmen; + struct PhragmenParams; + struct PhragMMSParams; + + impl Config for PhragmenParams { + type System = Runtime; + type Solver = SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; + type WeightInfo = (); } - type OnChainPhragmen = UnboundedExecution; + impl BoundedConfig for PhragmenParams { + type VotersBound = ConstU32<600>; + type TargetsBound = ConstU32<400>; + } + + impl Config for PhragMMSParams { + type System = Runtime; + type Solver = PhragMMS; + type DataProvider = mock_data_provider::DataProvider; + type WeightInfo = (); + } + + impl BoundedConfig for PhragMMSParams { + type VotersBound = ConstU32<600>; + type TargetsBound = ConstU32<400>; + } mod mock_data_provider { use frame_support::{bounded_vec, traits::ConstU32}; @@ -273,7 +299,20 @@ mod tests { fn onchain_seq_phragmen_works() { sp_io::TestExternalities::new_empty().execute_with(|| { assert_eq!( - OnChainPhragmen::elect().unwrap(), + BoundedExecution::::elect().unwrap(), + vec![ + (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), + (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) + ] + ); + }) + } + + #[test] + fn onchain_phragmms_works() { + sp_io::TestExternalities::new_empty().execute_with(|| { + assert_eq!( + BoundedExecution::::elect().unwrap(), vec![ (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) diff --git a/frame/election-provider-support/src/weights.rs b/frame/election-provider-support/src/weights.rs new file mode 100644 index 0000000000000..f288ae63bb5da --- /dev/null +++ b/frame/election-provider-support/src/weights.rs @@ -0,0 +1,94 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_election_provider_support_onchain_benchmarking +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-04-04, STEPS: `1`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/substrate +// benchmark +// --chain=dev +// --steps=1 +// --repeat=1 +// --pallet=pallet_election_provider_support_benchmarking +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=frame/election-provider-support/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_election_provider_support_benchmarking. +pub trait WeightInfo { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight; + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight; +} + +/// Weights for pallet_election_provider_support_benchmarking using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 667_000 + .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_334_000 + .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 60_644_000 + .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + } + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 73_000 + .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 146_000 + .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_649_000 + .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + fn phragmen(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 667_000 + .saturating_add((32_973_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 1_334_000 + .saturating_add((1_334_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 60_644_000 + .saturating_add((2_636_364_000 as Weight).saturating_mul(d as Weight)) + } + fn phragmms(v: u32, t: u32, d: u32, ) -> Weight { + (0 as Weight) + // Standard Error: 73_000 + .saturating_add((21_073_000 as Weight).saturating_mul(v as Weight)) + // Standard Error: 146_000 + .saturating_add((65_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 6_649_000 + .saturating_add((1_711_424_000 as Weight).saturating_mul(d as Weight)) + } +} diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 0296cd2e28d88..67d5a3d7fd373 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -181,10 +181,11 @@ parameter_types! { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; - type Solver = SequentialPhragmen<::AccountId, Perbill>; + type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 1a4414de0b0b0..74cc29586920d 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -151,10 +151,11 @@ parameter_types! { pub type Extrinsic = sp_runtime::testing::TestXt; pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 24b42b3e9f4b5..5acc484f9ba62 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -157,10 +157,11 @@ where } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl pallet_staking::Config for Test { diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index bb90aded852ee..09809483ec155 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -248,10 +248,11 @@ impl pallet_bags_list::Config for Test { } pub struct OnChainSeqPhragmen; -impl onchain::ExecutionConfig for OnChainSeqPhragmen { +impl onchain::Config for OnChainSeqPhragmen { type System = Test; type Solver = SequentialPhragmen; type DataProvider = Staking; + type WeightInfo = (); } impl crate::pallet::pallet::Config for Test { diff --git a/primitives/npos-elections/src/balancing.rs b/primitives/npos-elections/src/balancing.rs index 98f193e9e6116..54b8ee4bf243e 100644 --- a/primitives/npos-elections/src/balancing.rs +++ b/primitives/npos-elections/src/balancing.rs @@ -37,7 +37,7 @@ use sp_std::prelude::*; /// /// In almost all cases, a balanced solution will have a better score than an unbalanced solution, /// yet this is not 100% guaranteed because the first element of a [`crate::ElectionScore`] does not -/// directly related to balancing. +/// directly relate to balancing. /// /// Note that some reference implementation adopt an approach in which voters are balanced randomly /// per round. To advocate determinism, we don't do this. In each round, all voters are exactly diff --git a/primitives/npos-elections/src/phragmms.rs b/primitives/npos-elections/src/phragmms.rs index 6220cacd157b2..aa4c558bea1da 100644 --- a/primitives/npos-elections/src/phragmms.rs +++ b/primitives/npos-elections/src/phragmms.rs @@ -37,7 +37,7 @@ use sp_std::{prelude::*, rc::Rc}; /// - The algorithm is a _best-effort_ to elect `to_elect`. If less candidates are provided, less /// winners are returned, without an error. /// -/// This can only fail of the normalization fails. This can happen if for any of the resulting +/// This can only fail if the normalization fails. This can happen if for any of the resulting /// assignments, `assignment.distribution.map(|p| p.deconstruct()).sum()` fails to fit inside /// `UpperOf

`. A user of this crate may statically assert that this can never happen and safely /// `expect` this to return `Ok`.