mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Decouple Staking and Election - Part 2.1: Unleash Multi Phase (#8113)
* Base features and traits. * pallet and unsigned phase * Undo bad formattings. * some formatting cleanup. * Small self-cleanup. * Make it all build * self-review * Some doc tests. * Some changes from other PR * Fix session test * Update Cargo.lock * Update frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Some review comments * Rename + make encode/decode * Do an assert as well, just in case. * Fix build * Update frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * Las comment * fix staking fuzzer. * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Add one last layer of feasibility check as well. * Last fixes to benchmarks * Some more docs. * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Some nits * It all works * Some self cleanup * Update frame/staking/src/lib.rs Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com> * remove most todos. * Round of self-review. * Fix migration * clean macro * Revert wrong merge * remove fuzzer stuff. * Self review * Update frame/staking/src/lib.rs Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> * review comments * add logs * Add tests to demonstrate the capacity of the snapshot. * Replace upgrade * Last touches * Fix benchmakrs * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_staking --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/staking/src/weights.rs --template=./.maintain/frame-weight-template.hbs * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_election_provider_multi_phase --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/election-provider-multi-phase/src/weights.rs --template=./.maintain/frame-weight-template.hbs * remove unused stuff * Fix tests. Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Guillaume Thiolliere <gui.thiolliere@gmail.com> Co-authored-by: Parity Benchmarking Bot <admin@parity.io> Co-authored-by: Peter Goodspeed-Niklaus <coriolinus@users.noreply.github.com>
This commit is contained in:
Generated
+1
-23
@@ -5323,6 +5323,7 @@ dependencies = [
|
||||
"pallet-timestamp",
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.11.1",
|
||||
"paste 1.0.4",
|
||||
"rand_chacha 0.2.2",
|
||||
"serde",
|
||||
"sp-application-crypto",
|
||||
@@ -5338,29 +5339,6 @@ dependencies = [
|
||||
"substrate-test-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-staking-fuzz"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"frame-election-provider-support",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"honggfuzz",
|
||||
"pallet-balances",
|
||||
"pallet-indices",
|
||||
"pallet-session",
|
||||
"pallet-staking",
|
||||
"pallet-staking-reward-curve",
|
||||
"pallet-timestamp",
|
||||
"parity-scale-codec",
|
||||
"serde",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-npos-elections",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pallet-staking-reward-curve"
|
||||
version = "3.0.0"
|
||||
|
||||
@@ -105,7 +105,6 @@ members = [
|
||||
"frame/session/benchmarking",
|
||||
"frame/society",
|
||||
"frame/staking",
|
||||
"frame/staking/fuzzer",
|
||||
"frame/staking/reward-curve",
|
||||
"frame/staking/reward-fn",
|
||||
"frame/sudo",
|
||||
|
||||
@@ -468,14 +468,6 @@ parameter_types! {
|
||||
pub const SlashDeferDuration: pallet_staking::EraIndex = 24 * 7; // 1/4 the bonding duration.
|
||||
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
|
||||
pub const MaxNominatorRewardedPerValidator: u32 = 256;
|
||||
pub const ElectionLookahead: BlockNumber = EPOCH_DURATION_IN_BLOCKS / 4;
|
||||
pub const MaxIterations: u32 = 10;
|
||||
// 0.05%. The higher the value, the more strict solution acceptance becomes.
|
||||
pub MinSolutionScoreBump: Perbill = Perbill::from_rational(5u32, 10_000);
|
||||
pub OffchainSolutionWeightLimit: Weight = RuntimeBlockWeights::get()
|
||||
.get(DispatchClass::Normal)
|
||||
.max_extrinsic.expect("Normal extrinsics have a weight limit configured; qed")
|
||||
.saturating_sub(BlockExecutionWeight::get());
|
||||
}
|
||||
|
||||
impl pallet_staking::Config for Runtime {
|
||||
@@ -499,14 +491,6 @@ impl pallet_staking::Config for Runtime {
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = Session;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type ElectionLookahead = ElectionLookahead;
|
||||
type Call = Call;
|
||||
type MaxIterations = MaxIterations;
|
||||
type MinSolutionScoreBump = MinSolutionScoreBump;
|
||||
type UnsignedPriority = StakingUnsignedPriority;
|
||||
// The unsigned solution weight targeted by the OCW. We set it to the maximum possible value of
|
||||
// a single extrinsic.
|
||||
type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit;
|
||||
type ElectionProvider = ElectionProviderMultiPhase;
|
||||
type WeightInfo = pallet_staking::weights::SubstrateWeight<Runtime>;
|
||||
}
|
||||
@@ -518,7 +502,7 @@ parameter_types! {
|
||||
|
||||
// fallback: no need to do on-chain phragmen initially.
|
||||
pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy =
|
||||
pallet_election_provider_multi_phase::FallbackStrategy::Nothing;
|
||||
pallet_election_provider_multi_phase::FallbackStrategy::OnChain;
|
||||
|
||||
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(1u32, 10_000);
|
||||
|
||||
@@ -536,7 +520,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
type SignedPhase = SignedPhase;
|
||||
type UnsignedPhase = UnsignedPhase;
|
||||
type SolutionImprovementThreshold = MinSolutionScoreBump;
|
||||
type SolutionImprovementThreshold = SolutionImprovementThreshold;
|
||||
type MinerMaxIterations = MinerMaxIterations;
|
||||
type MinerMaxWeight = MinerMaxWeight;
|
||||
type MinerTxPriority = MultiPhaseUnsignedPriority;
|
||||
@@ -1095,7 +1079,7 @@ construct_runtime!(
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
|
||||
ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
||||
Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event<T>},
|
||||
Council: pallet_collective::<Instance1>::{Pallet, Call, Storage, Origin<T>, Event<T>, Config<T>},
|
||||
|
||||
@@ -208,12 +208,6 @@ impl pallet_staking::Config for Test {
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ElectionLookahead;
|
||||
type Call = Call;
|
||||
type UnsignedPriority = StakingUnsignedPriority;
|
||||
type MaxIterations = ();
|
||||
type MinSolutionScoreBump = ();
|
||||
type OffchainSolutionWeightLimit = ();
|
||||
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@@ -737,7 +737,6 @@ mod tests {
|
||||
roll_to(25);
|
||||
assert!(MultiPhase::current_phase().is_unsigned());
|
||||
|
||||
// mine seq_phragmen solution with 2 iters.
|
||||
assert_eq!(
|
||||
MultiPhase::mine_check_and_submit().unwrap_err(),
|
||||
MinerError::PreDispatchChecksFailed,
|
||||
@@ -844,7 +843,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ocw_only_runs_when_signed_open_now() {
|
||||
fn ocw_only_runs_when_unsigned_open_now() {
|
||||
let (mut ext, pool) = ExtBuilder::default().build_offchainify(0);
|
||||
ext.execute_with(|| {
|
||||
roll_to(25);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//! Autogenerated weights for pallet_election_provider_multi_phase
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
|
||||
//! DATE: 2021-03-14, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2021-03-19, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
@@ -57,52 +57,50 @@ pub trait WeightInfo {
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
fn on_initialize_nothing() -> Weight {
|
||||
(22_833_000 as Weight)
|
||||
(22_730_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(7 as Weight))
|
||||
}
|
||||
fn on_initialize_open_signed() -> Weight {
|
||||
(106_993_000 as Weight)
|
||||
(112_051_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(8 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn on_initialize_open_unsigned_with_snapshot() -> Weight {
|
||||
(106_490_000 as Weight)
|
||||
(112_165_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(8 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn on_initialize_open_unsigned_without_snapshot() -> Weight {
|
||||
(21_275_000 as Weight)
|
||||
(21_039_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn elect_queued() -> Weight {
|
||||
(7_274_346_000 as Weight)
|
||||
(7_362_949_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(6 as Weight))
|
||||
}
|
||||
fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight {
|
||||
fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((4_017_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 66_000
|
||||
.saturating_add((130_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((13_057_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 99_000
|
||||
.saturating_add((4_558_000 as Weight).saturating_mul(d as Weight))
|
||||
// Standard Error: 21_000
|
||||
.saturating_add((3_933_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 21_000
|
||||
.saturating_add((13_520_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 107_000
|
||||
.saturating_add((2_880_000 as Weight).saturating_mul(d as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((4_186_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 40_000
|
||||
.saturating_add((803_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((9_806_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 61_000
|
||||
.saturating_add((4_156_000 as Weight).saturating_mul(d as Weight))
|
||||
// Standard Error: 10_000
|
||||
.saturating_add((4_069_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 36_000
|
||||
.saturating_add((503_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 10_000
|
||||
.saturating_add((10_000_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 54_000
|
||||
.saturating_add((3_734_000 as Weight).saturating_mul(d as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
}
|
||||
}
|
||||
@@ -110,52 +108,50 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn on_initialize_nothing() -> Weight {
|
||||
(22_833_000 as Weight)
|
||||
(22_730_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
|
||||
}
|
||||
fn on_initialize_open_signed() -> Weight {
|
||||
(106_993_000 as Weight)
|
||||
(112_051_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(8 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn on_initialize_open_unsigned_with_snapshot() -> Weight {
|
||||
(106_490_000 as Weight)
|
||||
(112_165_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(8 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn on_initialize_open_unsigned_without_snapshot() -> Weight {
|
||||
(21_275_000 as Weight)
|
||||
(21_039_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn elect_queued() -> Weight {
|
||||
(7_274_346_000 as Weight)
|
||||
(7_362_949_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(6 as Weight))
|
||||
}
|
||||
fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight {
|
||||
fn submit_unsigned(v: u32, _t: u32, a: u32, d: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((4_017_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 66_000
|
||||
.saturating_add((130_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 19_000
|
||||
.saturating_add((13_057_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 99_000
|
||||
.saturating_add((4_558_000 as Weight).saturating_mul(d as Weight))
|
||||
// Standard Error: 21_000
|
||||
.saturating_add((3_933_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 21_000
|
||||
.saturating_add((13_520_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 107_000
|
||||
.saturating_add((2_880_000 as Weight).saturating_mul(d as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn feasibility_check(v: u32, t: u32, a: u32, d: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((4_186_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 40_000
|
||||
.saturating_add((803_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((9_806_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 61_000
|
||||
.saturating_add((4_156_000 as Weight).saturating_mul(d as Weight))
|
||||
// Standard Error: 10_000
|
||||
.saturating_add((4_069_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 36_000
|
||||
.saturating_add((503_000 as Weight).saturating_mul(t as Weight))
|
||||
// Standard Error: 10_000
|
||||
.saturating_add((10_000_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 54_000
|
||||
.saturating_add((3_734_000 as Weight).saturating_mul(d as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,9 @@ use frame_support::weights::Weight;
|
||||
|
||||
/// Re-export some type as they are used in the interface.
|
||||
pub use sp_arithmetic::PerThing;
|
||||
pub use sp_npos_elections::{Assignment, ExtendedBalance, PerThing128, Supports, VoteWeight};
|
||||
pub use sp_npos_elections::{
|
||||
Assignment, ExtendedBalance, PerThing128, Supports, Support, VoteWeight
|
||||
};
|
||||
|
||||
/// Types that are used by the data provider trait.
|
||||
pub mod data_provider {
|
||||
|
||||
@@ -54,7 +54,7 @@ frame_support::construct_runtime!(
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
||||
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event, ValidateUnsigned},
|
||||
Offences: pallet_offences::{Pallet, Call, Storage, Event},
|
||||
@@ -214,12 +214,6 @@ impl pallet_staking::Config for Test {
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ElectionLookahead;
|
||||
type Call = Call;
|
||||
type UnsignedPriority = StakingUnsignedPriority;
|
||||
type MaxIterations = ();
|
||||
type MinSolutionScoreBump = ();
|
||||
type OffchainSolutionWeightLimit = ();
|
||||
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ use pallet_session::historical::{Config as HistoricalConfig, IdentificationTuple
|
||||
use pallet_session::{Config as SessionConfig, SessionManager};
|
||||
use pallet_staking::{
|
||||
Module as Staking, Config as StakingConfig, RewardDestination, ValidatorPrefs,
|
||||
Exposure, IndividualExposure, ElectionStatus, MAX_NOMINATIONS, Event as StakingEvent
|
||||
Exposure, IndividualExposure, MAX_NOMINATIONS, Event as StakingEvent
|
||||
};
|
||||
|
||||
const SEED: u32 = 0;
|
||||
@@ -386,8 +386,6 @@ benchmarks! {
|
||||
let o = 10;
|
||||
let n = 100;
|
||||
|
||||
Staking::<T>::put_election_status(ElectionStatus::Closed);
|
||||
|
||||
let mut deferred_offences = vec![];
|
||||
let offenders = make_offenders::<T>(o, n)?.0;
|
||||
let offence_details = offenders.into_iter()
|
||||
|
||||
@@ -172,13 +172,7 @@ impl pallet_staking::Config for Test {
|
||||
type SessionInterface = Self;
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ();
|
||||
type Call = Call;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type UnsignedPriority = ();
|
||||
type MaxIterations = ();
|
||||
type MinSolutionScoreBump = ();
|
||||
type OffchainSolutionWeightLimit = ();
|
||||
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
@@ -222,7 +216,7 @@ frame_support::construct_runtime!(
|
||||
{
|
||||
System: system::{Pallet, Call, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
||||
ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},
|
||||
Offences: pallet_offences::{Pallet, Call, Storage, Event},
|
||||
|
||||
@@ -39,7 +39,7 @@ frame_support::construct_runtime!(
|
||||
{
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: pallet_staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
||||
}
|
||||
);
|
||||
@@ -177,13 +177,7 @@ impl pallet_staking::Config for Test {
|
||||
type SessionInterface = Self;
|
||||
type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ();
|
||||
type Call = Call;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type UnsignedPriority = UnsignedPriority;
|
||||
type MaxIterations = ();
|
||||
type MinSolutionScoreBump = ();
|
||||
type OffchainSolutionWeightLimit = ();
|
||||
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ static_assertions = "1.1.0"
|
||||
serde = { version = "1.0.101", optional = true }
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
|
||||
sp-std = { version = "3.0.0", default-features = false, path = "../../primitives/std" }
|
||||
# TWO_PHASE_NOTE:: ideally we should be able to get rid of this.
|
||||
sp-npos-elections = { version = "3.0.0", default-features = false, path = "../../primitives/npos-elections" }
|
||||
sp-io ={ version = "3.0.0", default-features = false, path = "../../primitives/io" }
|
||||
sp-runtime = { version = "3.0.0", default-features = false, path = "../../primitives/runtime" }
|
||||
@@ -27,8 +26,9 @@ frame-system = { version = "3.0.0", default-features = false, path = "../system"
|
||||
pallet-session = { version = "3.0.0", default-features = false, features = ["historical"], path = "../session" }
|
||||
pallet-authorship = { version = "3.0.0", default-features = false, path = "../authorship" }
|
||||
sp-application-crypto = { version = "3.0.0", default-features = false, path = "../../primitives/application-crypto" }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
frame-election-provider-support = { version = "3.0.0", default-features = false, path = "../election-provider-support" }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
paste = "1.0"
|
||||
|
||||
# Optional imports for benchmarking
|
||||
frame-benchmarking = { version = "3.1.0", default-features = false, path = "../benchmarking", optional = true }
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
hfuzz_target
|
||||
hfuzz_workspace
|
||||
-2294
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
[package]
|
||||
name = "pallet-staking-fuzz"
|
||||
version = "0.0.0"
|
||||
authors = ["Automatically generated"]
|
||||
publish = false
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://substrate.dev"
|
||||
repository = "https://github.com/paritytech/substrate/"
|
||||
description = "FRAME pallet staking fuzzing"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
|
||||
[dependencies]
|
||||
honggfuzz = "0.5"
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
|
||||
pallet-staking = { version = "3.0.0", path = "..", features = ["runtime-benchmarks"] }
|
||||
pallet-staking-reward-curve = { version = "3.0.0", path = "../reward-curve" }
|
||||
pallet-session = { version = "3.0.0", path = "../../session" }
|
||||
pallet-indices = { version = "3.0.0", path = "../../indices" }
|
||||
pallet-balances = { version = "3.0.0", path = "../../balances" }
|
||||
pallet-timestamp = { version = "3.0.0", path = "../../timestamp" }
|
||||
frame-system = { version = "3.0.0", path = "../../system" }
|
||||
frame-support = { version = "3.0.0", path = "../../support" }
|
||||
sp-std = { version = "3.0.0", path = "../../../primitives/std" }
|
||||
sp-io ={ version = "3.0.0", path = "../../../primitives/io" }
|
||||
sp-core = { version = "3.0.0", path = "../../../primitives/core" }
|
||||
sp-npos-elections = { version = "3.0.0", path = "../../../primitives/npos-elections" }
|
||||
sp-runtime = { version = "3.0.0", path = "../../../primitives/runtime" }
|
||||
frame-election-provider-support = { version = "3.0.0", path = "../../election-provider-support" }
|
||||
serde = "1.0.101"
|
||||
|
||||
[features]
|
||||
# Note feature std is required so that impl_opaque_keys derive serde.
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[[bin]]
|
||||
name = "submit_solution"
|
||||
path = "src/submit_solution.rs"
|
||||
@@ -1,183 +0,0 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2021 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.
|
||||
|
||||
//! Fuzzing for staking pallet.
|
||||
//!
|
||||
//! HFUZZ_RUN_ARGS="-n 8" cargo hfuzz run submit_solution
|
||||
|
||||
use honggfuzz::fuzz;
|
||||
|
||||
use mock::Test;
|
||||
use pallet_staking::testing_utils::*;
|
||||
use frame_support::{assert_ok, storage::StorageValue, traits::UnfilteredDispatchable};
|
||||
use frame_system::RawOrigin;
|
||||
use sp_runtime::DispatchError;
|
||||
use sp_core::offchain::{testing::TestOffchainExt, OffchainWorkerExt, OffchainDbExt};
|
||||
use pallet_staking::{EraElectionStatus, ElectionStatus, Module as Staking, Call as StakingCall};
|
||||
|
||||
mod mock;
|
||||
|
||||
#[repr(u32)]
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Mode {
|
||||
/// Initial submission. This will be rather cheap.
|
||||
InitialSubmission,
|
||||
/// A better submission that will replace the previous ones. This is the most expensive.
|
||||
StrongerSubmission,
|
||||
/// A weak submission that will be rejected. This will be rather cheap.
|
||||
WeakerSubmission,
|
||||
}
|
||||
|
||||
pub fn new_test_ext(iterations: u32) -> sp_io::TestExternalities {
|
||||
let mut ext: sp_io::TestExternalities = frame_system::GenesisConfig::default()
|
||||
.build_storage::<mock::Test>()
|
||||
.map(Into::into)
|
||||
.expect("Failed to create test externalities.");
|
||||
|
||||
let (offchain, offchain_state) = TestOffchainExt::new();
|
||||
|
||||
let mut seed = [0u8; 32];
|
||||
seed[0..4].copy_from_slice(&iterations.to_le_bytes());
|
||||
offchain_state.write().seed = seed;
|
||||
|
||||
ext.register_extension(OffchainDbExt::new(offchain.clone()));
|
||||
ext.register_extension(OffchainWorkerExt::new(offchain));
|
||||
|
||||
ext
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let to_range = |x: u32, a: u32, b: u32| {
|
||||
let collapsed = x % b;
|
||||
if collapsed >= a {
|
||||
collapsed
|
||||
} else {
|
||||
collapsed + a
|
||||
}
|
||||
};
|
||||
loop {
|
||||
fuzz!(|data: (u32, u32, u32, u32, u32)| {
|
||||
let (mut num_validators, mut num_nominators, mut edge_per_voter, mut to_elect, mode_u32) = data;
|
||||
// always run with 5 iterations.
|
||||
let mut ext = new_test_ext(5);
|
||||
let mode: Mode = unsafe { std::mem::transmute(mode_u32) };
|
||||
num_validators = to_range(num_validators, 50, 1000);
|
||||
num_nominators = to_range(num_nominators, 50, 2000);
|
||||
edge_per_voter = to_range(edge_per_voter, 1, 16);
|
||||
to_elect = to_range(to_elect, 20, num_validators);
|
||||
|
||||
let do_reduce = true;
|
||||
|
||||
println!("+++ instance with params {} / {} / {} / {} / {:?}({})",
|
||||
num_nominators,
|
||||
num_validators,
|
||||
edge_per_voter,
|
||||
to_elect,
|
||||
mode,
|
||||
mode_u32,
|
||||
);
|
||||
|
||||
ext.execute_with(|| {
|
||||
// initial setup
|
||||
init_active_era();
|
||||
|
||||
assert_ok!(create_validators_with_nominators_for_era::<Test>(
|
||||
num_validators,
|
||||
num_nominators,
|
||||
edge_per_voter as usize,
|
||||
true,
|
||||
None,
|
||||
));
|
||||
|
||||
<EraElectionStatus<Test>>::put(ElectionStatus::Open(1));
|
||||
assert!(<Staking<Test>>::create_stakers_snapshot().0);
|
||||
|
||||
let origin = RawOrigin::Signed(create_funded_user::<Test>("fuzzer", 0, 100));
|
||||
|
||||
// stuff to submit
|
||||
let (winners, compact, score, size) = match mode {
|
||||
Mode::InitialSubmission => {
|
||||
// No need to setup anything
|
||||
get_seq_phragmen_solution::<Test>(do_reduce)
|
||||
},
|
||||
Mode::StrongerSubmission => {
|
||||
let (winners, compact, score, size) = get_weak_solution::<Test>(false);
|
||||
println!("Weak on chain score = {:?}", score);
|
||||
assert_ok!(
|
||||
<Staking<Test>>::submit_election_solution(
|
||||
origin.clone().into(),
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
current_era::<Test>(),
|
||||
size,
|
||||
)
|
||||
);
|
||||
get_seq_phragmen_solution::<Test>(do_reduce)
|
||||
},
|
||||
Mode::WeakerSubmission => {
|
||||
let (winners, compact, score, size) = get_seq_phragmen_solution::<Test>(do_reduce);
|
||||
println!("Strong on chain score = {:?}", score);
|
||||
assert_ok!(
|
||||
<Staking<Test>>::submit_election_solution(
|
||||
origin.clone().into(),
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
current_era::<Test>(),
|
||||
size,
|
||||
)
|
||||
);
|
||||
get_weak_solution::<Test>(false)
|
||||
}
|
||||
};
|
||||
|
||||
// must have chosen correct number of winners.
|
||||
assert_eq!(winners.len() as u32, <Staking<Test>>::validator_count());
|
||||
|
||||
// final call and origin
|
||||
let call = StakingCall::<Test>::submit_election_solution(
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
current_era::<Test>(),
|
||||
size,
|
||||
);
|
||||
|
||||
// actually submit
|
||||
match mode {
|
||||
Mode::WeakerSubmission => {
|
||||
assert_eq!(
|
||||
call.dispatch_bypass_filter(origin.into()).unwrap_err().error,
|
||||
DispatchError::Module {
|
||||
index: 2,
|
||||
error: 16,
|
||||
message: Some("OffchainElectionWeakSubmission"),
|
||||
},
|
||||
);
|
||||
},
|
||||
// NOTE: so exhaustive pattern doesn't work here.. maybe some rust issue?
|
||||
// or due to `#[repr(u32)]`?
|
||||
Mode::InitialSubmission | Mode::StrongerSubmission => {
|
||||
assert_ok!(call.dispatch_bypass_filter(origin.into()));
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ use super::*;
|
||||
use crate::Module as Staking;
|
||||
use testing_utils::*;
|
||||
|
||||
use sp_npos_elections::CompactSolution;
|
||||
use sp_runtime::traits::One;
|
||||
use frame_system::RawOrigin;
|
||||
pub use frame_benchmarking::{
|
||||
@@ -94,8 +93,8 @@ pub fn create_validator_with_nominators<T: Config>(
|
||||
// Start a new Era
|
||||
let new_validators = Staking::<T>::new_era(SessionIndex::one()).unwrap();
|
||||
|
||||
assert!(new_validators.len() == 1);
|
||||
assert!(new_validators[0] == v_stash, "Our validator was not selected!");
|
||||
assert_eq!(new_validators.len(), 1);
|
||||
assert_eq!(new_validators[0], v_stash, "Our validator was not selected!");
|
||||
|
||||
// Give Era Points
|
||||
let reward = EraRewardPoints::<T::AccountId> {
|
||||
@@ -541,231 +540,6 @@ benchmarks! {
|
||||
assert!(balance_before > balance_after);
|
||||
}
|
||||
|
||||
// This benchmark create `v` validators intent, `n` nominators intent, in total creating `e`
|
||||
// edges.
|
||||
#[extra]
|
||||
submit_solution_initial {
|
||||
// number of validator intention. This will be equal to `ElectionSize::validators`.
|
||||
let v in 200 .. 400;
|
||||
// number of nominator intention. This will be equal to `ElectionSize::nominators`.
|
||||
let n in 500 .. 1000;
|
||||
// number of assignments. Basically, number of active nominators. This will be equal to
|
||||
// `compact.len()`.
|
||||
let a in 200 .. 400;
|
||||
// number of winners, also ValidatorCount. This will be equal to `winner.len()`.
|
||||
let w in 16 .. 100;
|
||||
|
||||
ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value");
|
||||
|
||||
let winners = create_validators_with_nominators_for_era::<T>(
|
||||
v,
|
||||
n,
|
||||
MAX_NOMINATIONS,
|
||||
false,
|
||||
Some(w),
|
||||
)?;
|
||||
|
||||
// needed for the solution to be generates.
|
||||
assert!(<Staking<T>>::create_stakers_snapshot().0);
|
||||
|
||||
// set number of winners
|
||||
ValidatorCount::put(w);
|
||||
|
||||
// create a assignments in total for the w winners.
|
||||
let (winners, assignments) = create_assignments_for_offchain::<T>(a, winners)?;
|
||||
|
||||
let (
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
size
|
||||
) = offchain_election::prepare_submission::<T>(
|
||||
assignments,
|
||||
winners,
|
||||
false,
|
||||
T::BlockWeights::get().max_block,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
winners.len(), compact.unique_targets().len(),
|
||||
"unique targets ({}) and winners ({}) count not same. This solution is not valid.",
|
||||
compact.unique_targets().len(),
|
||||
winners.len(),
|
||||
);
|
||||
|
||||
// needed for the solution to be accepted
|
||||
<EraElectionStatus<T>>::put(ElectionStatus::Open(T::BlockNumber::from(1u32)));
|
||||
|
||||
let era = <Staking<T>>::current_era().unwrap_or(0);
|
||||
let caller: T::AccountId = account("caller", n, SEED);
|
||||
whitelist_account!(caller);
|
||||
}: {
|
||||
let result = <Staking<T>>::submit_election_solution(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
winners,
|
||||
compact,
|
||||
score.clone(),
|
||||
era,
|
||||
size,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
verify {
|
||||
// new solution has been accepted.
|
||||
assert_eq!(<Staking<T>>::queued_score().unwrap(), score);
|
||||
}
|
||||
|
||||
// same as submit_solution_initial but we place a very weak solution on chian first.
|
||||
submit_solution_better {
|
||||
// number of validator intention.
|
||||
let v in 200 .. 400;
|
||||
// number of nominator intention.
|
||||
let n in 500 .. 1000;
|
||||
// number of assignments. Basically, number of active nominators.
|
||||
let a in 200 .. 400;
|
||||
// number of winners, also ValidatorCount.
|
||||
let w in 16 .. 100;
|
||||
|
||||
ensure!(w as usize >= MAX_NOMINATIONS, "doesn't support lower value");
|
||||
|
||||
let winners = create_validators_with_nominators_for_era::<T>(
|
||||
v,
|
||||
n,
|
||||
MAX_NOMINATIONS,
|
||||
false,
|
||||
Some(w),
|
||||
)?;
|
||||
|
||||
// needed for the solution to be generates.
|
||||
assert!(<Staking<T>>::create_stakers_snapshot().0);
|
||||
|
||||
// set number of winners
|
||||
ValidatorCount::put(w);
|
||||
|
||||
// create a assignments in total for the w winners.
|
||||
let (winners, assignments) = create_assignments_for_offchain::<T>(a, winners)?;
|
||||
|
||||
let single_winner = winners[0].0.clone();
|
||||
|
||||
let (
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
size
|
||||
) = offchain_election::prepare_submission::<T>(
|
||||
assignments,
|
||||
winners,
|
||||
false,
|
||||
T::BlockWeights::get().max_block,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
winners.len(), compact.unique_targets().len(),
|
||||
"unique targets ({}) and winners ({}) count not same. This solution is not valid.",
|
||||
compact.unique_targets().len(),
|
||||
winners.len(),
|
||||
);
|
||||
|
||||
// needed for the solution to be accepted
|
||||
<EraElectionStatus<T>>::put(ElectionStatus::Open(T::BlockNumber::from(1u32)));
|
||||
|
||||
let era = <Staking<T>>::current_era().unwrap_or(0);
|
||||
let caller: T::AccountId = account("caller", n, SEED);
|
||||
whitelist_account!(caller);
|
||||
|
||||
// submit a very bad solution on-chain
|
||||
{
|
||||
// this is needed to fool the chain to accept this solution.
|
||||
ValidatorCount::put(1);
|
||||
let (winners, compact, score, size) = get_single_winner_solution::<T>(single_winner)?;
|
||||
assert!(
|
||||
<Staking<T>>::submit_election_solution(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
winners,
|
||||
compact,
|
||||
score.clone(),
|
||||
era,
|
||||
size,
|
||||
).is_ok());
|
||||
|
||||
// new solution has been accepted.
|
||||
assert_eq!(<Staking<T>>::queued_score().unwrap(), score);
|
||||
ValidatorCount::put(w);
|
||||
}
|
||||
}: {
|
||||
let result = <Staking<T>>::submit_election_solution(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
winners,
|
||||
compact,
|
||||
score.clone(),
|
||||
era,
|
||||
size,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
verify {
|
||||
// new solution has been accepted.
|
||||
assert_eq!(<Staking<T>>::queued_score().unwrap(), score);
|
||||
}
|
||||
|
||||
// This will be early rejected based on the score.
|
||||
#[extra]
|
||||
submit_solution_weaker {
|
||||
// number of validator intention.
|
||||
let v in 200 .. 400;
|
||||
// number of nominator intention.
|
||||
let n in 500 .. 1000;
|
||||
|
||||
create_validators_with_nominators_for_era::<T>(v, n, MAX_NOMINATIONS, false, None)?;
|
||||
|
||||
// needed for the solution to be generates.
|
||||
assert!(<Staking<T>>::create_stakers_snapshot().0);
|
||||
|
||||
// needed for the solution to be accepted
|
||||
<EraElectionStatus<T>>::put(ElectionStatus::Open(T::BlockNumber::from(1u32)));
|
||||
let era = <Staking<T>>::current_era().unwrap_or(0);
|
||||
let caller: T::AccountId = account("caller", n, SEED);
|
||||
whitelist_account!(caller);
|
||||
|
||||
// submit a seq-phragmen with all the good stuff on chain.
|
||||
{
|
||||
let (winners, compact, score, size) = get_seq_phragmen_solution::<T>(true);
|
||||
assert_eq!(
|
||||
winners.len(), compact.unique_targets().len(),
|
||||
"unique targets ({}) and winners ({}) count not same. This solution is not valid.",
|
||||
compact.unique_targets().len(),
|
||||
winners.len(),
|
||||
);
|
||||
assert!(
|
||||
<Staking<T>>::submit_election_solution(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
winners,
|
||||
compact,
|
||||
score.clone(),
|
||||
era,
|
||||
size,
|
||||
).is_ok()
|
||||
);
|
||||
|
||||
// new solution has been accepted.
|
||||
assert_eq!(<Staking<T>>::queued_score().unwrap(), score);
|
||||
}
|
||||
|
||||
// prepare a bad solution. This will be very early rejected.
|
||||
let (winners, compact, score, size) = get_weak_solution::<T>(true);
|
||||
}: {
|
||||
assert!(
|
||||
<Staking<T>>::submit_election_solution(
|
||||
RawOrigin::Signed(caller.clone()).into(),
|
||||
winners,
|
||||
compact,
|
||||
score.clone(),
|
||||
era,
|
||||
size,
|
||||
).is_err()
|
||||
);
|
||||
}
|
||||
|
||||
get_npos_voters {
|
||||
// number of validator intention.
|
||||
let v in 200 .. 400;
|
||||
@@ -896,15 +670,6 @@ mod tests {
|
||||
assert_ok!(closure_to_benchmark());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_benchmarks_offchain() {
|
||||
ExtBuilder::default().has_stakers(false).build().execute_with(|| {
|
||||
assert_ok!(test_benchmark_submit_solution_better::<Test>());
|
||||
assert_ok!(test_benchmark_submit_solution_weaker::<Test>());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
|
||||
+156
-1098
File diff suppressed because it is too large
Load Diff
@@ -22,14 +22,11 @@ use crate as staking;
|
||||
use frame_support::{
|
||||
assert_ok, parameter_types,
|
||||
traits::{Currency, FindAuthor, Get, OnFinalize, OnInitialize, OneSessionHandler},
|
||||
weights::{constants::RocksDbWeight, Weight},
|
||||
weights::constants::RocksDbWeight,
|
||||
IterableStorageMap, StorageDoubleMap, StorageMap, StorageValue,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_io;
|
||||
use sp_npos_elections::{
|
||||
to_supports, reduce, ExtendedBalance, StakedAssignment, ElectionScore, EvaluateSupport,
|
||||
};
|
||||
use sp_runtime::{
|
||||
curve::PiecewiseLinear,
|
||||
testing::{Header, TestXt, UintAuthorityId},
|
||||
@@ -101,7 +98,7 @@ frame_support::construct_runtime!(
|
||||
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
|
||||
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
|
||||
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
|
||||
Staking: staking::{Pallet, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
|
||||
Staking: staking::{Pallet, Call, Config<T>, Storage, Event<T>},
|
||||
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>},
|
||||
}
|
||||
);
|
||||
@@ -126,10 +123,8 @@ parameter_types! {
|
||||
pub static SessionsPerEra: SessionIndex = 3;
|
||||
pub static ExistentialDeposit: Balance = 1;
|
||||
pub static SlashDeferDuration: EraIndex = 0;
|
||||
pub static ElectionLookahead: BlockNumber = 0;
|
||||
pub static Period: BlockNumber = 5;
|
||||
pub static Offset: BlockNumber = 0;
|
||||
pub static MaxIterations: u32 = 0;
|
||||
}
|
||||
|
||||
impl frame_system::Config for Test {
|
||||
@@ -220,9 +215,6 @@ parameter_types! {
|
||||
pub const BondingDuration: EraIndex = 3;
|
||||
pub const RewardCurve: &'static PiecewiseLinear<'static> = &I_NPOS;
|
||||
pub const MaxNominatorRewardedPerValidator: u32 = 64;
|
||||
pub const UnsignedPriority: u64 = 1 << 20;
|
||||
pub const MinSolutionScoreBump: Perbill = Perbill::zero();
|
||||
pub OffchainSolutionWeightLimit: Weight = BlockWeights::get().max_block;
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@@ -262,13 +254,7 @@ impl Config for Test {
|
||||
type SessionInterface = Self;
|
||||
type EraPayout = ConvertCurve<RewardCurve>;
|
||||
type NextNewSession = Session;
|
||||
type ElectionLookahead = ElectionLookahead;
|
||||
type Call = Call;
|
||||
type MaxIterations = MaxIterations;
|
||||
type MinSolutionScoreBump = MinSolutionScoreBump;
|
||||
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
|
||||
type UnsignedPriority = UnsignedPriority;
|
||||
type OffchainSolutionWeightLimit = OffchainSolutionWeightLimit;
|
||||
type ElectionProvider = onchain::OnChainSequentialPhragmen<Self>;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
@@ -352,10 +338,6 @@ impl ExtBuilder {
|
||||
SESSIONS_PER_ERA.with(|v| *v.borrow_mut() = length);
|
||||
self
|
||||
}
|
||||
pub fn election_lookahead(self, look: BlockNumber) -> Self {
|
||||
ELECTION_LOOKAHEAD.with(|v| *v.borrow_mut() = look);
|
||||
self
|
||||
}
|
||||
pub fn period(self, length: BlockNumber) -> Self {
|
||||
PERIOD.with(|v| *v.borrow_mut() = length);
|
||||
self
|
||||
@@ -364,13 +346,6 @@ impl ExtBuilder {
|
||||
self.has_stakers = has;
|
||||
self
|
||||
}
|
||||
pub fn max_offchain_iterations(self, iterations: u32) -> Self {
|
||||
MAX_ITERATIONS.with(|v| *v.borrow_mut() = iterations);
|
||||
self
|
||||
}
|
||||
pub fn offchain_election_ext(self) -> Self {
|
||||
self.session_per_era(4).period(5).election_lookahead(3)
|
||||
}
|
||||
pub fn initialize_first_session(mut self, init: bool) -> Self {
|
||||
self.initialize_first_session = init;
|
||||
self
|
||||
@@ -774,198 +749,6 @@ pub(crate) fn add_slash(who: &AccountId) {
|
||||
);
|
||||
}
|
||||
|
||||
// winners will be chosen by simply their unweighted total backing stake. Nominator stake is
|
||||
// distributed evenly.
|
||||
pub(crate) fn horrible_npos_solution(
|
||||
do_reduce: bool,
|
||||
) -> (CompactAssignments, Vec<ValidatorIndex>, ElectionScore) {
|
||||
let mut backing_stake_of: BTreeMap<AccountId, Balance> = BTreeMap::new();
|
||||
|
||||
// self stake
|
||||
<Validators<Test>>::iter().for_each(|(who, _p)| {
|
||||
*backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who)
|
||||
});
|
||||
|
||||
// add nominator stuff
|
||||
<Nominators<Test>>::iter().for_each(|(who, nomination)| {
|
||||
nomination.targets.iter().for_each(|v| {
|
||||
*backing_stake_of.entry(*v).or_insert(Zero::zero()) +=
|
||||
Staking::slashable_balance_of(&who)
|
||||
})
|
||||
});
|
||||
|
||||
// elect winners
|
||||
let mut sorted: Vec<AccountId> = backing_stake_of.keys().cloned().collect();
|
||||
sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap());
|
||||
let winners: Vec<AccountId> = sorted
|
||||
.iter()
|
||||
.cloned()
|
||||
.take(Staking::validator_count() as usize)
|
||||
.collect();
|
||||
|
||||
// create assignments
|
||||
let mut staked_assignment: Vec<StakedAssignment<AccountId>> = Vec::new();
|
||||
<Nominators<Test>>::iter().for_each(|(who, nomination)| {
|
||||
let mut dist: Vec<(AccountId, ExtendedBalance)> = Vec::new();
|
||||
nomination.targets.iter().for_each(|v| {
|
||||
if winners.iter().find(|w| *w == v).is_some() {
|
||||
dist.push((*v, ExtendedBalance::zero()));
|
||||
}
|
||||
});
|
||||
|
||||
if dist.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
// assign real stakes. just split the stake.
|
||||
let stake = Staking::slashable_balance_of(&who) as ExtendedBalance;
|
||||
let mut sum: ExtendedBalance = Zero::zero();
|
||||
let dist_len = dist.len();
|
||||
{
|
||||
dist.iter_mut().for_each(|(_, w)| {
|
||||
let partial = stake / (dist_len as ExtendedBalance);
|
||||
*w = partial;
|
||||
sum += partial;
|
||||
});
|
||||
}
|
||||
|
||||
// assign the leftover to last.
|
||||
{
|
||||
let leftover = stake - sum;
|
||||
let last = dist.last_mut().unwrap();
|
||||
last.1 += leftover;
|
||||
}
|
||||
|
||||
staked_assignment.push(StakedAssignment {
|
||||
who,
|
||||
distribution: dist,
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure that this result is worse than seq-phragmen. Otherwise, it should not have been used
|
||||
// for testing.
|
||||
let score = {
|
||||
let (_, _, better_score) = prepare_submission_with(true, true, 0, |_| {});
|
||||
|
||||
let support = to_supports::<AccountId>(&winners, &staked_assignment).unwrap();
|
||||
let score = support.evaluate();
|
||||
|
||||
assert!(sp_npos_elections::is_score_better::<Perbill>(
|
||||
better_score,
|
||||
score,
|
||||
MinSolutionScoreBump::get(),
|
||||
));
|
||||
|
||||
score
|
||||
};
|
||||
|
||||
if do_reduce {
|
||||
reduce(&mut staked_assignment);
|
||||
}
|
||||
|
||||
let snapshot_validators = Staking::snapshot_validators().unwrap();
|
||||
let snapshot_nominators = Staking::snapshot_nominators().unwrap();
|
||||
let nominator_index = |a: &AccountId| -> Option<NominatorIndex> {
|
||||
snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex)
|
||||
};
|
||||
let validator_index = |a: &AccountId| -> Option<ValidatorIndex> {
|
||||
snapshot_validators.iter().position(|x| x == a).map(|i| i as ValidatorIndex)
|
||||
};
|
||||
|
||||
// convert back to ratio assignment. This takes less space.
|
||||
let assignments_reduced =
|
||||
sp_npos_elections::assignment_staked_to_ratio::<AccountId, OffchainAccuracy>(staked_assignment);
|
||||
|
||||
let compact =
|
||||
CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index)
|
||||
.unwrap();
|
||||
|
||||
// winner ids to index
|
||||
let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::<Vec<_>>();
|
||||
|
||||
(compact, winners, score)
|
||||
}
|
||||
|
||||
/// Note: this should always logically reproduce [`offchain_election::prepare_submission`], yet we
|
||||
/// cannot do it since we want to have `tweak` injected into the process.
|
||||
///
|
||||
/// If the input is being tweaked in a way that the score cannot be compute accurately,
|
||||
/// `compute_real_score` can be set to true. In this case a `Default` score is returned.
|
||||
pub(crate) fn prepare_submission_with(
|
||||
compute_real_score: bool,
|
||||
do_reduce: bool,
|
||||
iterations: usize,
|
||||
tweak: impl FnOnce(&mut Vec<StakedAssignment<AccountId>>),
|
||||
) -> (CompactAssignments, Vec<ValidatorIndex>, ElectionScore) {
|
||||
// run election on the default stuff.
|
||||
let sp_npos_elections::ElectionResult {
|
||||
winners,
|
||||
assignments,
|
||||
} = Staking::do_phragmen::<OffchainAccuracy>(iterations).unwrap();
|
||||
let winners = sp_npos_elections::to_without_backing(winners);
|
||||
|
||||
let mut staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
Staking::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
// apply custom tweaks. awesome for testing.
|
||||
tweak(&mut staked);
|
||||
|
||||
if do_reduce {
|
||||
reduce(&mut staked);
|
||||
}
|
||||
|
||||
// convert back to ratio assignment. This takes less space.
|
||||
let snapshot_validators = Staking::snapshot_validators().expect("snapshot not created.");
|
||||
let snapshot_nominators = Staking::snapshot_nominators().expect("snapshot not created.");
|
||||
let nominator_index = |a: &AccountId| -> Option<NominatorIndex> {
|
||||
snapshot_nominators
|
||||
.iter()
|
||||
.position(|x| x == a)
|
||||
.map_or_else(
|
||||
|| { println!("unable to find nominator index for {:?}", a); None },
|
||||
|i| Some(i as NominatorIndex),
|
||||
)
|
||||
};
|
||||
let validator_index = |a: &AccountId| -> Option<ValidatorIndex> {
|
||||
snapshot_validators
|
||||
.iter()
|
||||
.position(|x| x == a)
|
||||
.map_or_else(
|
||||
|| { println!("unable to find validator index for {:?}", a); None },
|
||||
|i| Some(i as ValidatorIndex),
|
||||
)
|
||||
};
|
||||
|
||||
let assignments_reduced = sp_npos_elections::assignment_staked_to_ratio(staked);
|
||||
|
||||
// re-compute score by converting, yet again, into staked type
|
||||
let score = if compute_real_score {
|
||||
let staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments_reduced.clone(),
|
||||
Staking::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map = to_supports(
|
||||
winners.as_slice(),
|
||||
staked.as_slice(),
|
||||
).unwrap();
|
||||
support_map.evaluate()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
let compact =
|
||||
CompactAssignments::from_assignment(assignments_reduced, nominator_index, validator_index)
|
||||
.expect("Failed to create compact");
|
||||
|
||||
// winner ids to index
|
||||
let winners = winners.into_iter().map(|w| validator_index(&w).unwrap()).collect::<Vec<_>>();
|
||||
|
||||
(compact, winners, score)
|
||||
}
|
||||
|
||||
/// Make all validator and nominator request their payment
|
||||
pub(crate) fn make_all_reward_payment(era: EraIndex) {
|
||||
let validators_with_reward =
|
||||
|
||||
@@ -1,598 +0,0 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2020-2021 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.
|
||||
|
||||
//! Helpers for offchain worker election.
|
||||
|
||||
use crate::{
|
||||
Call, CompactAssignments, ElectionSize, Module, NominatorIndex, Nominators, OffchainAccuracy,
|
||||
Config, ValidatorIndex, WeightInfo,
|
||||
};
|
||||
use codec::Decode;
|
||||
use frame_support::{traits::Get, weights::Weight, IterableStorageMap};
|
||||
use frame_system::offchain::SubmitTransaction;
|
||||
use sp_npos_elections::{
|
||||
to_supports, EvaluateSupport, reduce, Assignment, ElectionResult, ElectionScore,
|
||||
ExtendedBalance, CompactSolution,
|
||||
};
|
||||
use sp_runtime::{
|
||||
offchain::storage::StorageValueRef, traits::TrailingZeroInput, RuntimeDebug,
|
||||
};
|
||||
use sp_std::{convert::TryInto, prelude::*, collections::btree_map::BTreeMap};
|
||||
|
||||
/// Error types related to the offchain election machinery.
|
||||
#[derive(RuntimeDebug)]
|
||||
pub enum OffchainElectionError {
|
||||
/// election returned None. This means less candidate that minimum number of needed
|
||||
/// validators were present. The chain is in trouble and not much that we can do about it.
|
||||
ElectionFailed,
|
||||
/// Submission to the transaction pool failed.
|
||||
PoolSubmissionFailed,
|
||||
/// The snapshot data is not available.
|
||||
SnapshotUnavailable,
|
||||
/// Error from npos-election crate. This usually relates to compact operation.
|
||||
InternalElectionError(sp_npos_elections::Error),
|
||||
/// One of the computed winners is invalid.
|
||||
InvalidWinner,
|
||||
/// A nominator is not available in the snapshot.
|
||||
NominatorSnapshotCorrupt,
|
||||
}
|
||||
|
||||
impl From<sp_npos_elections::Error> for OffchainElectionError {
|
||||
fn from(e: sp_npos_elections::Error) -> Self {
|
||||
Self::InternalElectionError(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// Storage key used to store the persistent offchain worker status.
|
||||
pub(crate) const OFFCHAIN_HEAD_DB: &[u8] = b"parity/staking-election/";
|
||||
/// The repeat threshold of the offchain worker. This means we won't run the offchain worker twice
|
||||
/// within a window of 5 blocks.
|
||||
pub(crate) const OFFCHAIN_REPEAT: u32 = 5;
|
||||
/// Default number of blocks for which the unsigned transaction should stay in the pool
|
||||
pub(crate) const DEFAULT_LONGEVITY: u64 = 25;
|
||||
|
||||
/// Checks if an execution of the offchain worker is permitted at the given block number, or not.
|
||||
///
|
||||
/// This essentially makes sure that we don't run on previous blocks in case of a re-org, and we
|
||||
/// don't run twice within a window of length [`OFFCHAIN_REPEAT`].
|
||||
///
|
||||
/// Returns `Ok(())` if offchain worker should happen, `Err(reason)` otherwise.
|
||||
pub(crate) fn set_check_offchain_execution_status<T: Config>(
|
||||
now: T::BlockNumber,
|
||||
) -> Result<(), &'static str> {
|
||||
let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB);
|
||||
let threshold = T::BlockNumber::from(OFFCHAIN_REPEAT);
|
||||
|
||||
let mutate_stat =
|
||||
storage.mutate::<_, &'static str, _>(|maybe_head: Option<Option<T::BlockNumber>>| {
|
||||
match maybe_head {
|
||||
Some(Some(head)) if now < head => Err("fork."),
|
||||
Some(Some(head)) if now >= head && now <= head + threshold => {
|
||||
Err("recently executed.")
|
||||
}
|
||||
Some(Some(head)) if now > head + threshold => {
|
||||
// we can run again now. Write the new head.
|
||||
Ok(now)
|
||||
}
|
||||
_ => {
|
||||
// value doesn't exists. Probably this node just booted up. Write, and run
|
||||
Ok(now)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
match mutate_stat {
|
||||
// all good
|
||||
Ok(Ok(_)) => Ok(()),
|
||||
// failed to write.
|
||||
Ok(Err(_)) => Err("failed to write to offchain db."),
|
||||
// fork etc.
|
||||
Err(why) => Err(why),
|
||||
}
|
||||
}
|
||||
|
||||
/// The internal logic of the offchain worker of this module. This runs the phragmen election,
|
||||
/// compacts and reduces the solution, computes the score and submits it back to the chain as an
|
||||
/// unsigned transaction, without any signature.
|
||||
pub(crate) fn compute_offchain_election<T: Config>() -> Result<(), OffchainElectionError> {
|
||||
let iters = get_balancing_iters::<T>();
|
||||
// compute raw solution. Note that we use `OffchainAccuracy`.
|
||||
let ElectionResult {
|
||||
winners,
|
||||
assignments,
|
||||
} = <Module<T>>::do_phragmen::<OffchainAccuracy>(iters)
|
||||
.ok_or(OffchainElectionError::ElectionFailed)?;
|
||||
|
||||
// process and prepare it for submission.
|
||||
let (winners, compact, score, size) = prepare_submission::<T>(
|
||||
assignments,
|
||||
winners,
|
||||
true,
|
||||
T::OffchainSolutionWeightLimit::get(),
|
||||
)?;
|
||||
|
||||
crate::log!(
|
||||
info,
|
||||
"prepared a seq-phragmen solution with {} balancing iterations and score {:?}",
|
||||
iters,
|
||||
score,
|
||||
);
|
||||
|
||||
// defensive-only: current era can never be none except genesis.
|
||||
let current_era = <Module<T>>::current_era().unwrap_or_default();
|
||||
|
||||
// send it.
|
||||
let call = Call::submit_election_solution_unsigned(
|
||||
winners,
|
||||
compact,
|
||||
score,
|
||||
current_era,
|
||||
size,
|
||||
).into();
|
||||
|
||||
SubmitTransaction::<T, Call<T>>::submit_unsigned_transaction(call)
|
||||
.map_err(|_| OffchainElectionError::PoolSubmissionFailed)
|
||||
}
|
||||
|
||||
/// Get a random number of iterations to run the balancing.
|
||||
///
|
||||
/// Uses the offchain seed to generate a random number.
|
||||
pub fn get_balancing_iters<T: Config>() -> usize {
|
||||
match T::MaxIterations::get() {
|
||||
0 => 0,
|
||||
max @ _ => {
|
||||
let seed = sp_io::offchain::random_seed();
|
||||
let random = <u32>::decode(&mut TrailingZeroInput::new(seed.as_ref()))
|
||||
.expect("input is padded with zeroes; qed") % max.saturating_add(1);
|
||||
random as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find the maximum `len` that a compact can have in order to fit into the block weight.
|
||||
///
|
||||
/// This only returns a value between zero and `size.nominators`.
|
||||
pub fn maximum_compact_len<W: crate::WeightInfo>(
|
||||
winners_len: u32,
|
||||
size: ElectionSize,
|
||||
max_weight: Weight,
|
||||
) -> u32 {
|
||||
use sp_std::cmp::Ordering;
|
||||
|
||||
if size.nominators < 1 {
|
||||
return size.nominators;
|
||||
}
|
||||
|
||||
let max_voters = size.nominators.max(1);
|
||||
let mut voters = max_voters;
|
||||
|
||||
// helper closures.
|
||||
let weight_with = |voters: u32| -> Weight {
|
||||
W::submit_solution_better(
|
||||
size.validators.into(),
|
||||
size.nominators.into(),
|
||||
voters,
|
||||
winners_len,
|
||||
)
|
||||
};
|
||||
|
||||
let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result<u32, ()> {
|
||||
match current_weight.cmp(&max_weight) {
|
||||
Ordering::Less => {
|
||||
let next_voters = voters.checked_add(step);
|
||||
match next_voters {
|
||||
Some(voters) if voters < max_voters => Ok(voters),
|
||||
_ => Err(()),
|
||||
}
|
||||
},
|
||||
Ordering::Greater => voters.checked_sub(step).ok_or(()),
|
||||
Ordering::Equal => Ok(voters),
|
||||
}
|
||||
};
|
||||
|
||||
// First binary-search the right amount of voters
|
||||
let mut step = voters / 2;
|
||||
let mut current_weight = weight_with(voters);
|
||||
while step > 0 {
|
||||
match next_voters(current_weight, voters, step) {
|
||||
// proceed with the binary search
|
||||
Ok(next) if next != voters => {
|
||||
voters = next;
|
||||
},
|
||||
// we are out of bounds, break out of the loop.
|
||||
Err(()) => {
|
||||
break;
|
||||
},
|
||||
// we found the right value - early exit the function.
|
||||
Ok(next) => return next
|
||||
}
|
||||
step = step / 2;
|
||||
current_weight = weight_with(voters);
|
||||
}
|
||||
|
||||
|
||||
// Time to finish.
|
||||
// We might have reduced less than expected due to rounding error. Increase one last time if we
|
||||
// have any room left, the reduce until we are sure we are below limit.
|
||||
while voters + 1 <= max_voters && weight_with(voters + 1) < max_weight {
|
||||
voters += 1;
|
||||
}
|
||||
while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight {
|
||||
voters -= 1;
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
weight_with(voters.min(size.nominators)) <= max_weight,
|
||||
"weight_with({}) <= {}", voters.min(size.nominators), max_weight,
|
||||
);
|
||||
voters.min(size.nominators)
|
||||
}
|
||||
|
||||
/// Greedily reduce the size of the a solution to fit into the block, w.r.t. weight.
|
||||
///
|
||||
/// The weight of the solution is foremost a function of the number of voters (i.e.
|
||||
/// `compact.len()`). Aside from this, the other components of the weight are invariant. The number
|
||||
/// of winners shall not be changed (otherwise the solution is invalid) and the `ElectionSize` is
|
||||
/// merely a representation of the total number of stakers.
|
||||
///
|
||||
/// Thus, we reside to stripping away some voters. This means only changing the `compact` struct.
|
||||
///
|
||||
/// Note that the solution is already computed, and the winners are elected based on the merit of
|
||||
/// teh entire stake in the system. Nonetheless, some of the voters will be removed further down the
|
||||
/// line.
|
||||
///
|
||||
/// Indeed, the score must be computed **after** this step. If this step reduces the score too much,
|
||||
/// then the solution will be discarded.
|
||||
pub fn trim_to_weight<T: Config, FN>(
|
||||
maximum_allowed_voters: u32,
|
||||
mut compact: CompactAssignments,
|
||||
nominator_index: FN,
|
||||
) -> Result<CompactAssignments, OffchainElectionError>
|
||||
where
|
||||
for<'r> FN: Fn(&'r T::AccountId) -> Option<NominatorIndex>,
|
||||
{
|
||||
match compact.voter_count().checked_sub(maximum_allowed_voters as usize) {
|
||||
Some(to_remove) if to_remove > 0 => {
|
||||
// grab all voters and sort them by least stake.
|
||||
let balance_of = <Module<T>>::slashable_balance_of_fn();
|
||||
let mut voters_sorted = <Nominators<T>>::iter()
|
||||
.map(|(who, _)| (who.clone(), balance_of(&who)))
|
||||
.collect::<Vec<_>>();
|
||||
voters_sorted.sort_by_key(|(_, y)| *y);
|
||||
|
||||
// start removing from the least stake. Iterate until we know enough have been removed.
|
||||
let mut removed = 0;
|
||||
for (maybe_index, _stake) in voters_sorted
|
||||
.iter()
|
||||
.map(|(who, stake)| (nominator_index(&who), stake))
|
||||
{
|
||||
let index = maybe_index.ok_or(OffchainElectionError::NominatorSnapshotCorrupt)?;
|
||||
if compact.remove_voter(index) {
|
||||
crate::log!(
|
||||
trace,
|
||||
"removed a voter at index {} with stake {:?} from compact to reduce the size",
|
||||
index,
|
||||
_stake,
|
||||
);
|
||||
removed += 1
|
||||
}
|
||||
|
||||
if removed >= to_remove {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
crate::log!(
|
||||
warn,
|
||||
"{} nominators out of {} had to be removed from compact solution due to size \
|
||||
limits.",
|
||||
removed,
|
||||
compact.voter_count() + removed,
|
||||
);
|
||||
Ok(compact)
|
||||
}
|
||||
_ => {
|
||||
// nada, return as-is
|
||||
crate::log!(info, "Compact solution did not get trimmed due to block weight limits.",);
|
||||
Ok(compact)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes an election result and spits out some data that can be submitted to the chain.
|
||||
///
|
||||
/// This does a lot of stuff; read the inline comments.
|
||||
pub fn prepare_submission<T: Config>(
|
||||
assignments: Vec<Assignment<T::AccountId, OffchainAccuracy>>,
|
||||
winners: Vec<(T::AccountId, ExtendedBalance)>,
|
||||
do_reduce: bool,
|
||||
maximum_weight: Weight,
|
||||
) -> Result<
|
||||
(Vec<ValidatorIndex>, CompactAssignments, ElectionScore, ElectionSize),
|
||||
OffchainElectionError,
|
||||
> {
|
||||
// make sure that the snapshot is available.
|
||||
let snapshot_validators =
|
||||
<Module<T>>::snapshot_validators().ok_or(OffchainElectionError::SnapshotUnavailable)?;
|
||||
let snapshot_nominators =
|
||||
<Module<T>>::snapshot_nominators().ok_or(OffchainElectionError::SnapshotUnavailable)?;
|
||||
|
||||
// indexing caches
|
||||
let nominator_indices: BTreeMap<_, _> =
|
||||
snapshot_nominators.iter().enumerate().map(|(idx, account_id)| (account_id, idx)).collect();
|
||||
let validator_indices: BTreeMap<_, _> =
|
||||
snapshot_validators.iter().enumerate().map(|(idx, account_id)| (account_id, idx)).collect();
|
||||
|
||||
// all helper closures that we'd ever need.
|
||||
let nominator_index = |a: &T::AccountId| -> Option<NominatorIndex> {
|
||||
nominator_indices
|
||||
.get(a)
|
||||
.and_then(|i| <usize as TryInto<NominatorIndex>>::try_into(*i).ok())
|
||||
};
|
||||
let validator_index = |a: &T::AccountId| -> Option<ValidatorIndex> {
|
||||
validator_indices
|
||||
.get(a)
|
||||
.and_then(|i| <usize as TryInto<ValidatorIndex>>::try_into(*i).ok())
|
||||
};
|
||||
let nominator_at = |i: NominatorIndex| -> Option<T::AccountId> {
|
||||
snapshot_nominators.get(i as usize).cloned()
|
||||
};
|
||||
|
||||
let validator_at = |i: ValidatorIndex| -> Option<T::AccountId> {
|
||||
snapshot_validators.get(i as usize).cloned()
|
||||
};
|
||||
|
||||
// both conversions are safe; snapshots are not created if they exceed.
|
||||
let size = ElectionSize {
|
||||
validators: snapshot_validators.len() as ValidatorIndex,
|
||||
nominators: snapshot_nominators.len() as NominatorIndex,
|
||||
};
|
||||
|
||||
// Clean winners.
|
||||
let winners = sp_npos_elections::to_without_backing(winners);
|
||||
|
||||
// convert into absolute value and to obtain the reduced version.
|
||||
let mut staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments,
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
// reduce
|
||||
if do_reduce {
|
||||
reduce(&mut staked);
|
||||
}
|
||||
|
||||
// Convert back to ratio assignment. This takes less space.
|
||||
let low_accuracy_assignment = sp_npos_elections::assignment_staked_to_ratio_normalized(staked)
|
||||
.map_err(|e| OffchainElectionError::from(e))?;
|
||||
|
||||
// compact encode the assignment.
|
||||
let compact = CompactAssignments::from_assignment(
|
||||
low_accuracy_assignment,
|
||||
nominator_index,
|
||||
validator_index,
|
||||
)
|
||||
.map_err(|e| OffchainElectionError::from(e))?;
|
||||
|
||||
// potentially reduce the size of the compact to fit weight.
|
||||
let maximum_allowed_voters =
|
||||
maximum_compact_len::<T::WeightInfo>(winners.len() as u32, size, maximum_weight);
|
||||
|
||||
crate::log!(
|
||||
debug,
|
||||
"Maximum weight = {:?} // current weight = {:?} // maximum voters = {:?} // current votes \
|
||||
= {:?}",
|
||||
maximum_weight,
|
||||
T::WeightInfo::submit_solution_better(
|
||||
size.validators.into(),
|
||||
size.nominators.into(),
|
||||
compact.voter_count() as u32,
|
||||
winners.len() as u32,
|
||||
),
|
||||
maximum_allowed_voters,
|
||||
compact.voter_count(),
|
||||
);
|
||||
|
||||
let compact = trim_to_weight::<T, _>(maximum_allowed_voters, compact, &nominator_index)?;
|
||||
|
||||
// re-compute the score. We re-create what the chain will do. This is a bit verbose and wastes
|
||||
// CPU time, but it is necessary to ensure that the score that we claim is the same as the one
|
||||
// calculated by the chain.
|
||||
let score = {
|
||||
let compact = compact.clone();
|
||||
let assignments = compact.into_assignment(nominator_at, validator_at).unwrap();
|
||||
let staked = sp_npos_elections::assignment_ratio_to_staked(
|
||||
assignments.clone(),
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map = to_supports::<T::AccountId>(&winners, &staked)
|
||||
.map_err(|_| OffchainElectionError::ElectionFailed)?;
|
||||
support_map.evaluate()
|
||||
};
|
||||
|
||||
// winners to index. Use a simple for loop for a more expressive early exit in case of error.
|
||||
let mut winners_indexed: Vec<ValidatorIndex> = Vec::with_capacity(winners.len());
|
||||
for w in winners {
|
||||
if let Some(idx) = snapshot_validators.iter().position(|v| *v == w) {
|
||||
let compact_index: ValidatorIndex = idx
|
||||
.try_into()
|
||||
.map_err(|_| OffchainElectionError::InvalidWinner)?;
|
||||
winners_indexed.push(compact_index);
|
||||
} else {
|
||||
return Err(OffchainElectionError::InvalidWinner);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((winners_indexed, compact, score, size))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#![allow(unused_variables)]
|
||||
use super::*;
|
||||
use crate::ElectionSize;
|
||||
|
||||
struct Staking;
|
||||
|
||||
impl crate::WeightInfo for Staking {
|
||||
fn bond() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn bond_extra() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn unbond() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn withdraw_unbonded_update(s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn withdraw_unbonded_kill(s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn validate() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn nominate(n: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn chill() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_payee() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_controller() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_validator_count() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn force_no_eras() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn force_new_era() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn force_new_era_always() -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_invulnerables(v: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn force_unstake(s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn cancel_deferred_slash(s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn payout_stakers_dead_controller(n: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn payout_stakers_alive_staked(n: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn rebond(l: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_history_depth(e: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn reap_stash(s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn new_era(v: u32, n: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn submit_solution_better(v: u32, n: u32, a: u32, w: u32) -> Weight {
|
||||
(0 * v + 0 * n + 1000 * a + 0 * w) as Weight
|
||||
}
|
||||
fn kick(w: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_npos_voters(v: u32, n: u32, s: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_npos_targets(v: u32) -> Weight {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_max_voter_binary_search_works() {
|
||||
let size = ElectionSize {
|
||||
validators: 0,
|
||||
nominators: 10,
|
||||
};
|
||||
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 0), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 999), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1000), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1001), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1990), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1999), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2000), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2001), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2010), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2990), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2999), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 3000), 3);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 3333), 3);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 5500), 5);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 7777), 7);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 9999), 9);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 10_000), 10);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 10_999), 10);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 11_000), 10);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 22_000), 10);
|
||||
|
||||
let size = ElectionSize {
|
||||
validators: 0,
|
||||
nominators: 1,
|
||||
};
|
||||
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 0), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 999), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1000), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1001), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1990), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1999), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2000), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2001), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2010), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 3333), 1);
|
||||
|
||||
let size = ElectionSize {
|
||||
validators: 0,
|
||||
nominators: 2,
|
||||
};
|
||||
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 0), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 999), 0);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1000), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1001), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 1999), 1);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2000), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2001), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 2010), 2);
|
||||
assert_eq!(maximum_compact_len::<Staking>(0, size, 3333), 2);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ use frame_benchmarking::account;
|
||||
use frame_system::RawOrigin;
|
||||
use sp_io::hashing::blake2_256;
|
||||
use rand_chacha::{rand_core::{RngCore, SeedableRng}, ChaChaRng};
|
||||
use sp_npos_elections::*;
|
||||
|
||||
const SEED: u32 = 0;
|
||||
|
||||
@@ -143,7 +142,7 @@ pub fn create_validators_with_nominators_for_era<T: Config>(
|
||||
}
|
||||
|
||||
let to_nominate = to_nominate.unwrap_or(validators_stash.len() as u32) as usize;
|
||||
let validator_choosen = validators_stash[0..to_nominate].to_vec();
|
||||
let validator_chosen = validators_stash[0..to_nominate].to_vec();
|
||||
|
||||
// Create nominators
|
||||
for j in 0 .. nominators {
|
||||
@@ -155,7 +154,7 @@ pub fn create_validators_with_nominators_for_era<T: Config>(
|
||||
)?;
|
||||
|
||||
// Have them randomly validate
|
||||
let mut available_validators = validator_choosen.clone();
|
||||
let mut available_validators = validator_chosen.clone();
|
||||
let mut selected_validators: Vec<<T::Lookup as StaticLookup>::Source> =
|
||||
Vec::with_capacity(edge_per_nominator);
|
||||
|
||||
@@ -169,227 +168,10 @@ pub fn create_validators_with_nominators_for_era<T: Config>(
|
||||
|
||||
ValidatorCount::put(validators);
|
||||
|
||||
Ok(validator_choosen)
|
||||
Ok(validator_chosen)
|
||||
}
|
||||
|
||||
|
||||
/// Build a _really bad_ but acceptable solution for election. This should always yield a solution
|
||||
/// which has a less score than the seq-phragmen.
|
||||
pub fn get_weak_solution<T: Config>(
|
||||
do_reduce: bool,
|
||||
) -> (Vec<ValidatorIndex>, CompactAssignments, ElectionScore, ElectionSize) {
|
||||
let mut backing_stake_of: BTreeMap<T::AccountId, BalanceOf<T>> = BTreeMap::new();
|
||||
|
||||
// self stake
|
||||
<Validators<T>>::iter().for_each(|(who, _p)| {
|
||||
*backing_stake_of.entry(who.clone()).or_insert_with(|| Zero::zero()) +=
|
||||
<Module<T>>::slashable_balance_of(&who)
|
||||
});
|
||||
|
||||
// elect winners. We chose the.. least backed ones.
|
||||
let mut sorted: Vec<T::AccountId> = backing_stake_of.keys().cloned().collect();
|
||||
sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap());
|
||||
let winners: Vec<T::AccountId> = sorted
|
||||
.iter()
|
||||
.rev()
|
||||
.cloned()
|
||||
.take(<Module<T>>::validator_count() as usize)
|
||||
.collect();
|
||||
|
||||
let mut staked_assignments: Vec<StakedAssignment<T::AccountId>> = Vec::new();
|
||||
// you could at this point start adding some of the nominator's stake, but for now we don't.
|
||||
// This solution must be bad.
|
||||
|
||||
// add self support to winners.
|
||||
winners.iter().for_each(|w| {
|
||||
staked_assignments.push(StakedAssignment {
|
||||
who: w.clone(),
|
||||
distribution: vec![(
|
||||
w.clone(),
|
||||
<Module<T>>::slashable_balance_of_vote_weight(
|
||||
&w,
|
||||
T::Currency::total_issuance(),
|
||||
).into(),
|
||||
)],
|
||||
})
|
||||
});
|
||||
|
||||
if do_reduce {
|
||||
reduce(&mut staked_assignments);
|
||||
}
|
||||
|
||||
// helpers for building the compact
|
||||
let snapshot_validators = <Module<T>>::snapshot_validators().unwrap();
|
||||
let snapshot_nominators = <Module<T>>::snapshot_nominators().unwrap();
|
||||
|
||||
let nominator_index = |a: &T::AccountId| -> Option<NominatorIndex> {
|
||||
snapshot_nominators
|
||||
.iter()
|
||||
.position(|x| x == a)
|
||||
.and_then(|i| <usize as TryInto<NominatorIndex>>::try_into(i).ok())
|
||||
};
|
||||
let validator_index = |a: &T::AccountId| -> Option<ValidatorIndex> {
|
||||
snapshot_validators
|
||||
.iter()
|
||||
.position(|x| x == a)
|
||||
.and_then(|i| <usize as TryInto<ValidatorIndex>>::try_into(i).ok())
|
||||
};
|
||||
|
||||
// convert back to ratio assignment. This takes less space.
|
||||
let low_accuracy_assignment = assignment_staked_to_ratio_normalized(staked_assignments)
|
||||
.expect("Failed to normalize");
|
||||
|
||||
// re-calculate score based on what the chain will decode.
|
||||
let score = {
|
||||
let staked = assignment_ratio_to_staked::<_, OffchainAccuracy, _>(
|
||||
low_accuracy_assignment.clone(),
|
||||
<Module<T>>::slashable_balance_of_fn(),
|
||||
);
|
||||
|
||||
let support_map =
|
||||
to_supports::<T::AccountId>(winners.as_slice(), staked.as_slice()).unwrap();
|
||||
support_map.evaluate()
|
||||
};
|
||||
|
||||
// compact encode the assignment.
|
||||
let compact = CompactAssignments::from_assignment(
|
||||
low_accuracy_assignment,
|
||||
nominator_index,
|
||||
validator_index,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// winners to index.
|
||||
let winners = winners
|
||||
.into_iter()
|
||||
.map(|w| {
|
||||
snapshot_validators
|
||||
.iter()
|
||||
.position(|v| *v == w)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<ValidatorIndex>>();
|
||||
|
||||
let size = ElectionSize {
|
||||
validators: snapshot_validators.len() as ValidatorIndex,
|
||||
nominators: snapshot_nominators.len() as NominatorIndex,
|
||||
};
|
||||
|
||||
(winners, compact, score, size)
|
||||
}
|
||||
|
||||
/// Create a solution for seq-phragmen. This uses the same internal function as used by the offchain
|
||||
/// worker code.
|
||||
pub fn get_seq_phragmen_solution<T: Config>(
|
||||
do_reduce: bool,
|
||||
) -> (
|
||||
Vec<ValidatorIndex>,
|
||||
CompactAssignments,
|
||||
ElectionScore,
|
||||
ElectionSize,
|
||||
) {
|
||||
let iters = offchain_election::get_balancing_iters::<T>();
|
||||
|
||||
let sp_npos_elections::ElectionResult {
|
||||
winners,
|
||||
assignments,
|
||||
} = <Module<T>>::do_phragmen::<OffchainAccuracy>(iters).unwrap();
|
||||
|
||||
offchain_election::prepare_submission::<T>(
|
||||
assignments,
|
||||
winners,
|
||||
do_reduce,
|
||||
T::BlockWeights::get().max_block,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Returns a solution in which only one winner is elected with just a self vote.
|
||||
pub fn get_single_winner_solution<T: Config>(
|
||||
winner: T::AccountId,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<ValidatorIndex>,
|
||||
CompactAssignments,
|
||||
ElectionScore,
|
||||
ElectionSize,
|
||||
),
|
||||
&'static str,
|
||||
> {
|
||||
let snapshot_validators = <Module<T>>::snapshot_validators().unwrap();
|
||||
let snapshot_nominators = <Module<T>>::snapshot_nominators().unwrap();
|
||||
|
||||
let val_index = snapshot_validators
|
||||
.iter()
|
||||
.position(|x| *x == winner)
|
||||
.ok_or("not a validator")?;
|
||||
let nom_index = snapshot_nominators
|
||||
.iter()
|
||||
.position(|x| *x == winner)
|
||||
.ok_or("not a nominator")?;
|
||||
|
||||
let stake = <Staking<T>>::slashable_balance_of(&winner);
|
||||
let stake =
|
||||
<T::CurrencyToVote>::to_vote(stake, T::Currency::total_issuance()) as ExtendedBalance;
|
||||
|
||||
let val_index = val_index as ValidatorIndex;
|
||||
let nom_index = nom_index as NominatorIndex;
|
||||
|
||||
let winners = vec![val_index];
|
||||
let compact = CompactAssignments {
|
||||
votes1: vec![(nom_index, val_index)],
|
||||
..Default::default()
|
||||
};
|
||||
let score = [stake, stake, stake * stake];
|
||||
let size = ElectionSize {
|
||||
validators: snapshot_validators.len() as ValidatorIndex,
|
||||
nominators: snapshot_nominators.len() as NominatorIndex,
|
||||
};
|
||||
|
||||
Ok((winners, compact, score, size))
|
||||
}
|
||||
|
||||
/// get the active era.
|
||||
/// get the current era.
|
||||
pub fn current_era<T: Config>() -> EraIndex {
|
||||
<Module<T>>::current_era().unwrap_or(0)
|
||||
}
|
||||
|
||||
/// initialize the first era.
|
||||
pub fn init_active_era() {
|
||||
ActiveEra::put(ActiveEraInfo {
|
||||
index: 1,
|
||||
start: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create random assignments for the given list of winners. Each assignment will have
|
||||
/// MAX_NOMINATIONS edges.
|
||||
pub fn create_assignments_for_offchain<T: Config>(
|
||||
num_assignments: u32,
|
||||
winners: Vec<<T::Lookup as StaticLookup>::Source>,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<(T::AccountId, ExtendedBalance)>,
|
||||
Vec<Assignment<T::AccountId, OffchainAccuracy>>,
|
||||
),
|
||||
&'static str
|
||||
> {
|
||||
let ratio = OffchainAccuracy::from_rational(1, MAX_NOMINATIONS);
|
||||
let assignments: Vec<Assignment<T::AccountId, OffchainAccuracy>> = <Nominators<T>>::iter()
|
||||
.take(num_assignments as usize)
|
||||
.map(|(n, t)| Assignment {
|
||||
who: n,
|
||||
distribution: t.targets.iter().map(|v| (v.clone(), ratio)).collect(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
ensure!(assignments.len() == num_assignments as usize, "must bench for `a` assignments");
|
||||
|
||||
let winners = winners.into_iter().map(|v| {
|
||||
(<T::Lookup as StaticLookup>::lookup(v).unwrap(), 0)
|
||||
}).collect();
|
||||
|
||||
Ok((winners, assignments))
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
||||
//! Autogenerated weights for pallet_staking
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0
|
||||
//! DATE: 2021-03-14, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2021-03-19, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
@@ -68,7 +68,6 @@ pub trait WeightInfo {
|
||||
fn set_history_depth(e: u32, ) -> Weight;
|
||||
fn reap_stash(s: u32, ) -> Weight;
|
||||
fn new_era(v: u32, n: u32, ) -> Weight;
|
||||
fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight;
|
||||
fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight;
|
||||
fn get_npos_targets(v: u32, ) -> Weight;
|
||||
}
|
||||
@@ -77,192 +76,178 @@ pub trait WeightInfo {
|
||||
pub struct SubstrateWeight<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
fn bond() -> Weight {
|
||||
(80_317_000 as Weight)
|
||||
(82_121_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn bond_extra() -> Weight {
|
||||
(64_495_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
(61_899_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn unbond() -> Weight {
|
||||
(59_679_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||
(56_392_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn withdraw_unbonded_update(s: u32, ) -> Weight {
|
||||
(61_078_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((40_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(5 as Weight))
|
||||
(57_382_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((70_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn withdraw_unbonded_kill(s: u32, ) -> Weight {
|
||||
(95_129_000 as Weight)
|
||||
// Standard Error: 2_000
|
||||
.saturating_add((2_755_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(7 as Weight))
|
||||
(92_185_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_844_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn validate() -> Weight {
|
||||
(20_608_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
(16_892_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn kick(k: u32, ) -> Weight {
|
||||
(33_365_000 as Weight)
|
||||
// Standard Error: 11_000
|
||||
.saturating_add((18_830_000 as Weight).saturating_mul(k as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
(27_411_000 as Weight)
|
||||
// Standard Error: 14_000
|
||||
.saturating_add((19_272_000 as Weight).saturating_mul(k as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(k as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight)))
|
||||
}
|
||||
fn nominate(n: u32, ) -> Weight {
|
||||
(33_885_000 as Weight)
|
||||
// Standard Error: 22_000
|
||||
.saturating_add((5_562_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
(30_188_000 as Weight)
|
||||
// Standard Error: 24_000
|
||||
.saturating_add((5_666_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn chill() -> Weight {
|
||||
(19_741_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
(15_870_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_payee() -> Weight {
|
||||
(13_674_000 as Weight)
|
||||
(13_853_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_controller() -> Weight {
|
||||
(29_691_000 as Weight)
|
||||
(30_291_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn set_validator_count() -> Weight {
|
||||
(2_375_000 as Weight)
|
||||
(2_397_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_no_eras() -> Weight {
|
||||
(2_601_000 as Weight)
|
||||
(2_627_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_new_era() -> Weight {
|
||||
(2_605_000 as Weight)
|
||||
(2_679_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_new_era_always() -> Weight {
|
||||
(2_584_000 as Weight)
|
||||
(2_643_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_invulnerables(v: u32, ) -> Weight {
|
||||
(2_725_000 as Weight)
|
||||
(2_871_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((35_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_unstake(s: u32, ) -> Weight {
|
||||
(63_551_000 as Weight)
|
||||
// Standard Error: 7_000
|
||||
.saturating_add((2_844_000 as Weight).saturating_mul(s as Weight))
|
||||
(65_876_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_832_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn cancel_deferred_slash(s: u32, ) -> Weight {
|
||||
(5_905_400_000 as Weight)
|
||||
(5_896_640_000 as Weight)
|
||||
// Standard Error: 391_000
|
||||
.saturating_add((34_785_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add((34_808_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn payout_stakers_dead_controller(n: u32, ) -> Weight {
|
||||
(142_264_000 as Weight)
|
||||
// Standard Error: 22_000
|
||||
.saturating_add((52_542_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(11 as Weight))
|
||||
(137_975_000 as Weight)
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((54_061_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(10 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight)))
|
||||
}
|
||||
fn payout_stakers_alive_staked(n: u32, ) -> Weight {
|
||||
(180_166_000 as Weight)
|
||||
// Standard Error: 23_000
|
||||
.saturating_add((66_767_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(12 as Weight))
|
||||
(163_885_000 as Weight)
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((68_096_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(11 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((5 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(n as Weight)))
|
||||
}
|
||||
fn rebond(l: u32, ) -> Weight {
|
||||
(42_577_000 as Weight)
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((60_000 as Weight).saturating_mul(l as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
(37_847_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((89_000 as Weight).saturating_mul(l as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn set_history_depth(e: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 68_000
|
||||
.saturating_add((33_362_000 as Weight).saturating_mul(e as Weight))
|
||||
// Standard Error: 69_000
|
||||
.saturating_add((34_413_000 as Weight).saturating_mul(e as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((7 as Weight).saturating_mul(e as Weight)))
|
||||
}
|
||||
fn reap_stash(s: u32, ) -> Weight {
|
||||
(68_474_000 as Weight)
|
||||
(69_257_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_770_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add((2_819_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn new_era(v: u32, n: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 903_000
|
||||
.saturating_add((594_145_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 45_000
|
||||
.saturating_add((83_373_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(9 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(v as Weight)))
|
||||
// Standard Error: 1_013_000
|
||||
.saturating_add((382_529_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 50_000
|
||||
.saturating_add((63_170_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(10 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight)))
|
||||
.saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(13 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(9 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes((3 as Weight).saturating_mul(v as Weight)))
|
||||
}
|
||||
fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 52_000
|
||||
.saturating_add((1_460_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((754_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 52_000
|
||||
.saturating_add((74_798_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 108_000
|
||||
.saturating_add((8_108_000 as Weight).saturating_mul(w as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(a as Weight)))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(w as Weight)))
|
||||
.saturating_add(T::DbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 94_000
|
||||
.saturating_add((29_321_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 94_000
|
||||
.saturating_add((66_885_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 1_283_000
|
||||
.saturating_add((22_991_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(v as Weight)))
|
||||
// Standard Error: 90_000
|
||||
.saturating_add((27_108_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 90_000
|
||||
.saturating_add((29_962_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 1_228_000
|
||||
.saturating_add((26_080_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(v as Weight)))
|
||||
.saturating_add(T::DbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn get_npos_targets(v: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 26_000
|
||||
.saturating_add((10_972_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((11_220_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(v as Weight)))
|
||||
}
|
||||
@@ -271,192 +256,178 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
// For backwards compatibility and tests
|
||||
impl WeightInfo for () {
|
||||
fn bond() -> Weight {
|
||||
(80_317_000 as Weight)
|
||||
(82_121_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
||||
}
|
||||
fn bond_extra() -> Weight {
|
||||
(64_495_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
(61_899_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn unbond() -> Weight {
|
||||
(59_679_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||
(56_392_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn withdraw_unbonded_update(s: u32, ) -> Weight {
|
||||
(61_078_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((40_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(5 as Weight))
|
||||
(57_382_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((70_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn withdraw_unbonded_kill(s: u32, ) -> Weight {
|
||||
(95_129_000 as Weight)
|
||||
// Standard Error: 2_000
|
||||
.saturating_add((2_755_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(7 as Weight))
|
||||
(92_185_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_844_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn validate() -> Weight {
|
||||
(20_608_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
(16_892_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn kick(k: u32, ) -> Weight {
|
||||
(33_365_000 as Weight)
|
||||
// Standard Error: 11_000
|
||||
.saturating_add((18_830_000 as Weight).saturating_mul(k as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
(27_411_000 as Weight)
|
||||
// Standard Error: 14_000
|
||||
.saturating_add((19_272_000 as Weight).saturating_mul(k as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(k as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight)))
|
||||
}
|
||||
fn nominate(n: u32, ) -> Weight {
|
||||
(33_885_000 as Weight)
|
||||
// Standard Error: 22_000
|
||||
.saturating_add((5_562_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
(30_188_000 as Weight)
|
||||
// Standard Error: 24_000
|
||||
.saturating_add((5_666_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn chill() -> Weight {
|
||||
(19_741_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
(15_870_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn set_payee() -> Weight {
|
||||
(13_674_000 as Weight)
|
||||
(13_853_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_controller() -> Weight {
|
||||
(29_691_000 as Weight)
|
||||
(30_291_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn set_validator_count() -> Weight {
|
||||
(2_375_000 as Weight)
|
||||
(2_397_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_no_eras() -> Weight {
|
||||
(2_601_000 as Weight)
|
||||
(2_627_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_new_era() -> Weight {
|
||||
(2_605_000 as Weight)
|
||||
(2_679_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_new_era_always() -> Weight {
|
||||
(2_584_000 as Weight)
|
||||
(2_643_000 as Weight)
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn set_invulnerables(v: u32, ) -> Weight {
|
||||
(2_725_000 as Weight)
|
||||
(2_871_000 as Weight)
|
||||
// Standard Error: 0
|
||||
.saturating_add((35_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn force_unstake(s: u32, ) -> Weight {
|
||||
(63_551_000 as Weight)
|
||||
// Standard Error: 7_000
|
||||
.saturating_add((2_844_000 as Weight).saturating_mul(s as Weight))
|
||||
(65_876_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_832_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn cancel_deferred_slash(s: u32, ) -> Weight {
|
||||
(5_905_400_000 as Weight)
|
||||
(5_896_640_000 as Weight)
|
||||
// Standard Error: 391_000
|
||||
.saturating_add((34_785_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add((34_808_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as Weight))
|
||||
}
|
||||
fn payout_stakers_dead_controller(n: u32, ) -> Weight {
|
||||
(142_264_000 as Weight)
|
||||
// Standard Error: 22_000
|
||||
.saturating_add((52_542_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(11 as Weight))
|
||||
(137_975_000 as Weight)
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((54_061_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(10 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(n as Weight)))
|
||||
}
|
||||
fn payout_stakers_alive_staked(n: u32, ) -> Weight {
|
||||
(180_166_000 as Weight)
|
||||
// Standard Error: 23_000
|
||||
.saturating_add((66_767_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(12 as Weight))
|
||||
(163_885_000 as Weight)
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((68_096_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(11 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((5 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(n as Weight)))
|
||||
}
|
||||
fn rebond(l: u32, ) -> Weight {
|
||||
(42_577_000 as Weight)
|
||||
// Standard Error: 12_000
|
||||
.saturating_add((60_000 as Weight).saturating_mul(l as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
(37_847_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((89_000 as Weight).saturating_mul(l as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as Weight))
|
||||
}
|
||||
fn set_history_depth(e: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 68_000
|
||||
.saturating_add((33_362_000 as Weight).saturating_mul(e as Weight))
|
||||
// Standard Error: 69_000
|
||||
.saturating_add((34_413_000 as Weight).saturating_mul(e as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((7 as Weight).saturating_mul(e as Weight)))
|
||||
}
|
||||
fn reap_stash(s: u32, ) -> Weight {
|
||||
(68_474_000 as Weight)
|
||||
(69_257_000 as Weight)
|
||||
// Standard Error: 1_000
|
||||
.saturating_add((2_770_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add((2_819_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(8 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn new_era(v: u32, n: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 903_000
|
||||
.saturating_add((594_145_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 45_000
|
||||
.saturating_add((83_373_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(9 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(v as Weight)))
|
||||
// Standard Error: 1_013_000
|
||||
.saturating_add((382_529_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 50_000
|
||||
.saturating_add((63_170_000 as Weight).saturating_mul(n as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(10 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(13 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes(9 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().writes((3 as Weight).saturating_mul(v as Weight)))
|
||||
}
|
||||
fn submit_solution_better(v: u32, n: u32, a: u32, w: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 52_000
|
||||
.saturating_add((1_460_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 20_000
|
||||
.saturating_add((754_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 52_000
|
||||
.saturating_add((74_798_000 as Weight).saturating_mul(a as Weight))
|
||||
// Standard Error: 108_000
|
||||
.saturating_add((8_108_000 as Weight).saturating_mul(w as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(6 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(a as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(w as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().writes(2 as Weight))
|
||||
}
|
||||
fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 94_000
|
||||
.saturating_add((29_321_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 94_000
|
||||
.saturating_add((66_885_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 1_283_000
|
||||
.saturating_add((22_991_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(2 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(v as Weight)))
|
||||
// Standard Error: 90_000
|
||||
.saturating_add((27_108_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 90_000
|
||||
.saturating_add((29_962_000 as Weight).saturating_mul(n as Weight))
|
||||
// Standard Error: 1_228_000
|
||||
.saturating_add((26_080_000 as Weight).saturating_mul(s as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(3 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(v as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().reads((3 as Weight).saturating_mul(n as Weight)))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(s as Weight)))
|
||||
}
|
||||
fn get_npos_targets(v: u32, ) -> Weight {
|
||||
(0 as Weight)
|
||||
// Standard Error: 26_000
|
||||
.saturating_add((10_972_000 as Weight).saturating_mul(v as Weight))
|
||||
// Standard Error: 32_000
|
||||
.saturating_add((11_220_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads(1 as Weight))
|
||||
.saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(v as Weight)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user