diff --git a/Cargo.lock b/Cargo.lock index caad06f6805e1..7dfafef08f7e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 742b1f87dbdc7..9675070a516fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 12de6d54aaf3f..fd25c900da4e3 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -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; 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; } @@ -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, Event}, TransactionPayment: pallet_transaction_payment::{Pallet, Storage}, ElectionProviderMultiPhase: pallet_election_provider_multi_phase::{Pallet, Call, Storage, Event, ValidateUnsigned}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event}, Council: pallet_collective::::{Pallet, Call, Storage, Origin, Event, Config}, diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 0029b51abf399..93b4af00b5dc3 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -208,12 +208,6 @@ impl pallet_staking::Config for Test { type EraPayout = pallet_staking::ConvertCurve; 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; type WeightInfo = (); } diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 4ff224d86076a..b570c4482814b 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -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); diff --git a/frame/election-provider-multi-phase/src/weights.rs b/frame/election-provider-multi-phase/src/weights.rs index e13b82f53a177..3d3a5cede3293 100644 --- a/frame/election-provider-multi-phase/src/weights.rs +++ b/frame/election-provider-multi-phase/src/weights.rs @@ -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(PhantomData); impl WeightInfo for SubstrateWeight { 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 WeightInfo for SubstrateWeight { // 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)) } } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 3d7c2dbac90aa..1a4a293a3270d 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -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 { diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index 9e8bf3b8e0ca6..af9d7f0fe425c 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -54,7 +54,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, 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; 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; type WeightInfo = (); } diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index f430330f767b9..83275da593e90 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -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::::put_election_status(ElectionStatus::Closed); - let mut deferred_offences = vec![]; let offenders = make_offenders::(o, n)?.0; let offence_details = offenders.into_iter() diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 1260fcba2fec6..1fe8db5aaaa29 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -172,13 +172,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type ElectionLookahead = (); - type Call = Call; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = (); - type MaxIterations = (); - type MinSolutionScoreBump = (); - type OffchainSolutionWeightLimit = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } @@ -222,7 +216,7 @@ frame_support::construct_runtime!( { System: system::{Pallet, Call, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, ImOnline: pallet_im_online::{Pallet, Call, Storage, Event, ValidateUnsigned, Config}, Offences: pallet_offences::{Pallet, Call, Storage, Event}, diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 8ba6b3c04b711..af5d8f6a0936b 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -39,7 +39,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: pallet_staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, } ); @@ -177,13 +177,7 @@ impl pallet_staking::Config for Test { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type ElectionLookahead = (); - type Call = Call; type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator; - type UnsignedPriority = UnsignedPriority; - type MaxIterations = (); - type MinSolutionScoreBump = (); - type OffchainSolutionWeightLimit = (); type ElectionProvider = onchain::OnChainSequentialPhragmen; type WeightInfo = (); } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index b4c2819403720..24909b35f53cf 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -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 } diff --git a/frame/staking/fuzzer/.gitignore b/frame/staking/fuzzer/.gitignore deleted file mode 100644 index 3ebcb104d4a50..0000000000000 --- a/frame/staking/fuzzer/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -hfuzz_target -hfuzz_workspace diff --git a/frame/staking/fuzzer/Cargo.lock b/frame/staking/fuzzer/Cargo.lock deleted file mode 100644 index e451e12d10131..0000000000000 --- a/frame/staking/fuzzer/Cargo.lock +++ /dev/null @@ -1,2294 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "ahash" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" -dependencies = [ - "const-random", -] - -[[package]] -name = "aho-corasick" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -dependencies = [ - "memchr", -] - -[[package]] -name = "alga" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f823d037a7ec6ea2197046bafd4ae150e6bc36f9ca347404f46a46823fa84f2" -dependencies = [ - "approx", - "num-complex", - "num-traits", -] - -[[package]] -name = "approx" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" -dependencies = [ - "num-traits", -] - -[[package]] -name = "arbitrary" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75153c95fdedd7db9732dfbfc3702324a1627eec91ba56e37cd0ac78314ab2ed" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - -[[package]] -name = "arrayvec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "backtrace" -version = "0.3.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e" -dependencies = [ - "backtrace-sys", - "cfg-if", - "libc", - "rustc-demangle", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "bitmask" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da9b3d9f6f585199287a473f4f8dfab6566cf827d15c00c219f53c645687ead" - -[[package]] -name = "bitvec" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" -dependencies = [ - "either", - "radium", -] - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -dependencies = [ - "arrayvec 0.4.12", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "bumpalo" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" - -[[package]] -name = "byte-slice-cast" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "clear_on_drop" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -dependencies = [ - "cc", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "const-random" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" -dependencies = [ - "const-random-macro", - "proc-macro-hack", -] - -[[package]] -name = "const-random-macro" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" -dependencies = [ - "getrandom", - "proc-macro-hack", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-mac" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -dependencies = [ - "generic-array", - "subtle 1.0.0", -] - -[[package]] -name = "curve25519-dalek" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" -dependencies = [ - "byteorder", - "digest", - "rand_core 0.5.1", - "subtle 2.2.2", - "zeroize", -] - -[[package]] -name = "derive_more" -version = "0.99.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2323f3f47db9a0e77ce7a300605d8d2098597fc451ed1a97bb1f6411bb550a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.0-pre.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" -dependencies = [ - "clear_on_drop", - "curve25519-dalek", - "rand 0.7.3", - "sha2", -] - -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" - -[[package]] -name = "environmental" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516aa8d7a71cb00a1c4146f0798549b93d083d4f189b3ced8f3de6b8f11ee6c4" - -[[package]] -name = "failure" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fixed-hash" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32529fc42e86ec06e5047092082aab9ad459b070c5d2a76b14f4f5ce70bf2e84" -dependencies = [ - "byteorder", - "rand 0.7.3", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "frame-benchmarking" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "linregress", - "parity-scale-codec", - "sp-api", - "sp-io", - "sp-runtime", - "sp-runtime-interface", - "sp-std", -] - -[[package]] -name = "frame-metadata" -version = "11.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-std", -] - -[[package]] -name = "frame-support" -version = "2.0.0-alpha.5" -dependencies = [ - "bitmask", - "frame-metadata", - "frame-support-procedural", - "impl-trait-for-tuples", - "log", - "once_cell", - "parity-scale-codec", - "paste", - "serde", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-state-machine", - "sp-std", - "tracing", -] - -[[package]] -name = "frame-support-procedural" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support-procedural-tools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-support-procedural-tools" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support-procedural-tools-derive", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-support-procedural-tools-derive" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "frame-system" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "impl-trait-for-tuples", - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-version", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "futures" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" - -[[package]] -name = "futures-executor" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", - "num_cpus", -] - -[[package]] -name = "futures-io" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" - -[[package]] -name = "futures-macro" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" - -[[package]] -name = "futures-task" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" - -[[package]] -name = "futures-util" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hash-db" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - -[[package]] -name = "hash256-std-hasher" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" -dependencies = [ - "crunchy", -] - -[[package]] -name = "hashbrown" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" -dependencies = [ - "ahash", - "autocfg 0.1.7", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "hermit-abi" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" - -[[package]] -name = "hmac" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "hmac-drbg" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -dependencies = [ - "digest", - "generic-array", - "hmac", -] - -[[package]] -name = "impl-codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-serde" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-serde" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "integer-sqrt" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" - -[[package]] -name = "js-sys" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" - -[[package]] -name = "libfuzzer-sys" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d718794b8e23533b9069bd2c4597d69e41cc7ab1c02700a502971aca0cdcf24" -dependencies = [ - "arbitrary", - "cc", -] - -[[package]] -name = "libm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" - -[[package]] -name = "libsecp256k1" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" -dependencies = [ - "arrayref", - "crunchy", - "digest", - "hmac-drbg", - "rand 0.7.3", - "sha2", - "subtle 2.2.2", - "typenum", -] - -[[package]] -name = "linregress" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9290cf6f928576eeb9c096c6fad9d8d452a0a1a70a2bbffa6e36064eedc0aac9" -dependencies = [ - "failure", - "nalgebra", - "statrs", -] - -[[package]] -name = "lock_api" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matrixmultiply" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4f7ec66360130972f34830bfad9ef05c6610a43938a467bcc9ab9369ab3478f" -dependencies = [ - "rawpointer", -] - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" - -[[package]] -name = "memory-db" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58381b20ebe2c578e75dececd9da411414903415349548ccc46aac3209cdfbc" -dependencies = [ - "ahash", - "hash-db", - "hashbrown", - "parity-util-mem", -] - -[[package]] -name = "memory_units" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" - -[[package]] -name = "merlin" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6feca46f4fa3443a01769d768727f10c10a20fdb65e52dc16a81f0c8269bb78" -dependencies = [ - "byteorder", - "keccak", - "rand_core 0.5.1", - "zeroize", -] - -[[package]] -name = "nalgebra" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa9fddbc34c8c35dd2108515587b8ce0cab396f17977b8c738568e4edb521a2" -dependencies = [ - "alga", - "approx", - "generic-array", - "matrixmultiply", - "num-complex", - "num-rational", - "num-traits", - "rand 0.6.5", - "typenum", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg 1.0.0", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" -dependencies = [ - "autocfg 1.0.0", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -dependencies = [ - "autocfg 1.0.0", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" -dependencies = [ - "autocfg 1.0.0", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -dependencies = [ - "autocfg 1.0.0", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" -dependencies = [ - "parking_lot 0.9.0", -] - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "pallet-authorship" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-authorship", - "sp-core", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-balances" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "parity-scale-codec", - "serde", - "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-indices" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-keyring", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-session" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "pallet-timestamp", - "parity-scale-codec", - "serde", - "sp-io", - "sp-runtime", - "sp-staking", - "sp-std", - "sp-trie", -] - -[[package]] -name = "pallet-staking" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-support", - "frame-system", - "pallet-authorship", - "pallet-indices", - "pallet-session", - "parity-scale-codec", - "rand 0.7.3", - "serde", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-staking", - "sp-std", - "static_assertions", -] - -[[package]] -name = "pallet-staking-fuzz" -version = "0.0.0" -dependencies = [ - "frame-support", - "frame-system", - "libfuzzer-sys", - "pallet-balances", - "pallet-indices", - "pallet-session", - "pallet-staking", - "pallet-staking-reward-curve", - "pallet-timestamp", - "parity-scale-codec", - "rand 0.7.3", - "sp-core", - "sp-io", - "sp-npos-elections", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-staking-reward-curve" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pallet-timestamp" -version = "2.0.0-alpha.5" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "parity-scale-codec", - "serde", - "sp-inherents", - "sp-runtime", - "sp-std", - "sp-timestamp", -] - -[[package]] -name = "parity-scale-codec" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c8f7f4244ddb5c37c103641027a76c530e65e8e4b8240b29f81ea40508b17" -dependencies = [ - "arrayvec 0.5.1", - "bitvec", - "byte-slice-cast", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "parity-util-mem" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e42755f26e5ea21a6a819d9e63cbd70713e9867a2b767ec2cc65ca7659532c5" -dependencies = [ - "cfg-if", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot 0.10.0", - "primitive-types", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - -[[package]] -name = "parity-wasm" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc878dac00da22f8f61e7af3157988424567ab01d9920b962ef7dcbd7cd865" - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api", - "parking_lot_core 0.6.2", - "rustc_version", -] - -[[package]] -name = "parking_lot" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" -dependencies = [ - "lock_api", - "parking_lot_core 0.7.0", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "rustc_version", - "smallvec 0.6.13", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "smallvec 1.2.0", - "winapi", -] - -[[package]] -name = "paste" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092d791bf7847f70bbd49085489fba25fc2c193571752bff9e36e74e72403932" -dependencies = [ - "paste-impl", - "proc-macro-hack", -] - -[[package]] -name = "paste-impl" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406c23fb4c45cc6f68a9bbabb8ec7bd6f8cfcbd17e9e8f72c2460282f8325729" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pbkdf2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" -dependencies = [ - "byteorder", - "crypto-mac", -] - -[[package]] -name = "pin-utils" -version = "0.1.0-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" - -[[package]] -name = "ppv-lite86" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" - -[[package]] -name = "primitive-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e4b9943a2da369aec5e96f7c10ebc74fcf434d39590d974b0a3460e6f67fbb" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-serde 0.3.0", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10d4b51f154c8a7fb96fd6dad097cb74b863943ec010ac94b9fd1be8861fe1e" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" - -[[package]] -name = "proc-macro-nested" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" - -[[package]] -name = "proc-macro2" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "winapi", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rawpointer" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" - -[[package]] -name = "regex" -version = "1.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "schnorrkel" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" -dependencies = [ - "arrayref", - "arrayvec 0.5.1", - "curve25519-dalek", - "getrandom", - "merlin", - "rand 0.7.3", - "rand_core 0.5.1", - "sha2", - "subtle 2.2.2", - "zeroize", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "send_wrapper" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" - -[[package]] -name = "serde" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "smallvec" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" - -[[package]] -name = "sp-api" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "parity-scale-codec", - "sp-api-proc-macro", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-version", -] - -[[package]] -name = "sp-api-proc-macro" -version = "2.0.0-alpha.5" -dependencies = [ - "blake2-rfc", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-application-crypto" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-core", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-arithmetic" -version = "2.0.0-alpha.5" -dependencies = [ - "integer-sqrt", - "num-traits", - "parity-scale-codec", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-authorship" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "sp-inherents", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-core" -version = "2.0.0-alpha.5" -dependencies = [ - "base58", - "blake2-rfc", - "byteorder", - "ed25519-dalek", - "futures", - "hash-db", - "hash256-std-hasher", - "hex", - "impl-serde 0.3.0", - "lazy_static", - "libsecp256k1", - "log", - "num-traits", - "parity-scale-codec", - "parity-util-mem", - "parking_lot 0.10.0", - "primitive-types", - "rand 0.7.3", - "regex", - "schnorrkel", - "serde", - "sha2", - "sp-debug-derive", - "sp-externalities", - "sp-runtime-interface", - "sp-std", - "sp-storage", - "substrate-bip39", - "tiny-bip39", - "tiny-keccak", - "twox-hash", - "wasmi", - "zeroize", -] - -[[package]] -name = "sp-debug-derive" -version = "2.0.0-alpha.5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-externalities" -version = "0.8.0-alpha.5" -dependencies = [ - "environmental", - "sp-std", - "sp-storage", -] - -[[package]] -name = "sp-inherents" -version = "2.0.0-alpha.5" -dependencies = [ - "derive_more", - "parity-scale-codec", - "parking_lot 0.10.0", - "sp-core", - "sp-std", -] - -[[package]] -name = "sp-io" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "libsecp256k1", - "log", - "parity-scale-codec", - "sp-core", - "sp-externalities", - "sp-runtime-interface", - "sp-state-machine", - "sp-std", - "sp-trie", - "sp-wasm-interface", -] - -[[package]] -name = "sp-keyring" -version = "2.0.0-alpha.5" -dependencies = [ - "lazy_static", - "sp-core", - "sp-runtime", - "strum", -] - -[[package]] -name = "sp-panic-handler" -version = "2.0.0-alpha.5" -dependencies = [ - "backtrace", - "log", -] - -[[package]] -name = "sp-npos-elections" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "serde", - "sp-npos-elections-compact", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-npos-elections-compact" -version = "2.0.0-rc3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-runtime" -version = "2.0.0-alpha.5" -dependencies = [ - "hash256-std-hasher", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "parity-util-mem", - "paste", - "rand 0.7.3", - "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-inherents", - "sp-io", - "sp-std", -] - -[[package]] -name = "sp-runtime-interface" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "primitive-types", - "sp-externalities", - "sp-runtime-interface-proc-macro", - "sp-std", - "sp-wasm-interface", - "static_assertions", -] - -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "2.0.0-alpha.5" -dependencies = [ - "Inflector", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sp-staking" -version = "2.0.0-alpha.5" -dependencies = [ - "parity-scale-codec", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-state-machine" -version = "0.8.0-alpha.5" -dependencies = [ - "hash-db", - "log", - "num-traits", - "parity-scale-codec", - "parking_lot 0.10.0", - "rand 0.7.3", - "sp-core", - "sp-externalities", - "sp-panic-handler", - "sp-trie", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-std" -version = "2.0.0-alpha.5" - -[[package]] -name = "sp-storage" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-serde 0.2.3", - "serde", - "sp-debug-derive", - "sp-std", -] - -[[package]] -name = "sp-timestamp" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-api", - "sp-inherents", - "sp-runtime", - "sp-std", - "wasm-timer", -] - -[[package]] -name = "sp-trie" -version = "2.0.0-alpha.5" -dependencies = [ - "hash-db", - "memory-db", - "parity-scale-codec", - "sp-core", - "sp-std", - "trie-db", - "trie-root", -] - -[[package]] -name = "sp-version" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-serde 0.2.3", - "parity-scale-codec", - "serde", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-wasm-interface" -version = "2.0.0-alpha.5" -dependencies = [ - "impl-trait-for-tuples", - "parity-scale-codec", - "sp-std", - "wasmi", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "statrs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10102ac8d55e35db2b3fafc26f81ba8647da2e15879ab686a67e6d19af2685e8" -dependencies = [ - "rand 0.5.6", -] - -[[package]] -name = "strum" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "substrate-bip39" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c004e8166d6e0aa3a9d5fa673e5b7098ff25f930de1013a21341988151e681bb" -dependencies = [ - "hmac", - "pbkdf2", - "schnorrkel", - "sha2", -] - -[[package]] -name = "subtle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" - -[[package]] -name = "subtle" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" - -[[package]] -name = "syn" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "tiny-bip39" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0165e045cc2ae1660270ca65e1676dbaab60feb0f91b10f7d0665e9b47e31f2" -dependencies = [ - "failure", - "hmac", - "once_cell", - "pbkdf2", - "rand 0.7.3", - "rustc-hash", - "sha2", - "unicode-normalization", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1721cc8cf7d770cc4257872507180f35a4797272f5962f24c806af9e7faf52ab" -dependencies = [ - "cfg-if", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbad39da2f9af1cae3016339ad7f2c7a9e870f12e8fd04c4fd7ef35b30c0d2b" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa83a9a47081cd522c09c81b31aec2c9273424976f922ad61c053b58350b715" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "trie-db" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9222c50cc325855621271157c973da27a0dcd26fa06f8edf81020bd2333df0" -dependencies = [ - "hash-db", - "hashbrown", - "log", - "rustc-hex", - "smallvec 1.2.0", -] - -[[package]] -name = "trie-root" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652931506d2c1244d7217a70b99f56718a7b4161b37f04e7cd868072a99f68cd" -dependencies = [ - "hash-db", -] - -[[package]] -name = "twox-hash" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" -dependencies = [ - "rand 0.7.3", -] - -[[package]] -name = "typenum" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" - -[[package]] -name = "uint" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" -dependencies = [ - "byteorder", - "crunchy", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" -dependencies = [ - "smallvec 1.2.0", -] - -[[package]] -name = "unicode-segmentation" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" - -[[package]] -name = "unicode-xid" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasm-bindgen" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639" - -[[package]] -name = "wasm-timer" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c5e65a08699c9c4334ba136597ab22b85dccd4b65dd1e36ccf8f723a95b54" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.9.0", - "pin-utils", - "send_wrapper", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasmi" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf617d864d25af3587aa745529f7aaa541066c876d57e050c0d0c85c61c92aff" -dependencies = [ - "libc", - "memory_units", - "num-rational", - "num-traits", - "parity-wasm", - "wasmi-validation", -] - -[[package]] -name = "wasmi-validation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea78c597064ba73596099281e2f4cfc019075122a65cdda3205af94f0b264d93" -dependencies = [ - "parity-wasm", -] - -[[package]] -name = "web-sys" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/frame/staking/fuzzer/Cargo.toml b/frame/staking/fuzzer/Cargo.toml deleted file mode 100644 index fb36327e5e919..0000000000000 --- a/frame/staking/fuzzer/Cargo.toml +++ /dev/null @@ -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" diff --git a/frame/staking/fuzzer/src/submit_solution.rs b/frame/staking/fuzzer/src/submit_solution.rs deleted file mode 100644 index 63ec189d44b07..0000000000000 --- a/frame/staking/fuzzer/src/submit_solution.rs +++ /dev/null @@ -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::() - .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::( - num_validators, - num_nominators, - edge_per_voter as usize, - true, - None, - )); - - >::put(ElectionStatus::Open(1)); - assert!(>::create_stakers_snapshot().0); - - let origin = RawOrigin::Signed(create_funded_user::("fuzzer", 0, 100)); - - // stuff to submit - let (winners, compact, score, size) = match mode { - Mode::InitialSubmission => { - // No need to setup anything - get_seq_phragmen_solution::(do_reduce) - }, - Mode::StrongerSubmission => { - let (winners, compact, score, size) = get_weak_solution::(false); - println!("Weak on chain score = {:?}", score); - assert_ok!( - >::submit_election_solution( - origin.clone().into(), - winners, - compact, - score, - current_era::(), - size, - ) - ); - get_seq_phragmen_solution::(do_reduce) - }, - Mode::WeakerSubmission => { - let (winners, compact, score, size) = get_seq_phragmen_solution::(do_reduce); - println!("Strong on chain score = {:?}", score); - assert_ok!( - >::submit_election_solution( - origin.clone().into(), - winners, - compact, - score, - current_era::(), - size, - ) - ); - get_weak_solution::(false) - } - }; - - // must have chosen correct number of winners. - assert_eq!(winners.len() as u32, >::validator_count()); - - // final call and origin - let call = StakingCall::::submit_election_solution( - winners, - compact, - score, - current_era::(), - 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())); - } - }; - }) - }); - } -} diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 8e0273622b059..83a67abb3c8e1 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -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( // Start a new Era let new_validators = Staking::::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:: { @@ -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::( - v, - n, - MAX_NOMINATIONS, - false, - Some(w), - )?; - - // needed for the solution to be generates. - assert!(>::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::(a, winners)?; - - let ( - winners, - compact, - score, - size - ) = offchain_election::prepare_submission::( - 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 - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - - let era = >::current_era().unwrap_or(0); - let caller: T::AccountId = account("caller", n, SEED); - whitelist_account!(caller); - }: { - let result = >::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!(>::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::( - v, - n, - MAX_NOMINATIONS, - false, - Some(w), - )?; - - // needed for the solution to be generates. - assert!(>::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::(a, winners)?; - - let single_winner = winners[0].0.clone(); - - let ( - winners, - compact, - score, - size - ) = offchain_election::prepare_submission::( - 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 - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - - let era = >::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::(single_winner)?; - assert!( - >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ).is_ok()); - - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - ValidatorCount::put(w); - } - }: { - let result = >::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!(>::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::(v, n, MAX_NOMINATIONS, false, None)?; - - // needed for the solution to be generates. - assert!(>::create_stakers_snapshot().0); - - // needed for the solution to be accepted - >::put(ElectionStatus::Open(T::BlockNumber::from(1u32))); - let era = >::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::(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!( - >::submit_election_solution( - RawOrigin::Signed(caller.clone()).into(), - winners, - compact, - score.clone(), - era, - size, - ).is_ok() - ); - - // new solution has been accepted. - assert_eq!(>::queued_score().unwrap(), score); - } - - // prepare a bad solution. This will be very early rejected. - let (winners, compact, score, size) = get_weak_solution::(true); - }: { - assert!( - >::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::()); - assert_ok!(test_benchmark_submit_solution_weaker::()); - }); - } } impl_benchmark_test_suite!( diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 6fdb20e2bb830..77ef928b92aae 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -278,7 +278,6 @@ pub mod testing_utils; pub mod benchmarking; pub mod slashing; -pub mod offchain_election; pub mod inflation; pub mod weights; @@ -292,16 +291,16 @@ use sp_std::{ use codec::{HasCompact, Encode, Decode}; use frame_support::{ decl_module, decl_event, decl_storage, ensure, decl_error, - weights::{Weight, constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}}, - storage::IterableStorageMap, - dispatch::{ - DispatchResult, DispatchResultWithPostInfo, DispatchErrorWithPostInfo, - WithPostDispatchInfo, + weights::{ + Weight, + constants::{WEIGHT_PER_MICROS, WEIGHT_PER_NANOS}, }, + storage::IterableStorageMap, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, traits::{ Currency, LockIdentifier, LockableCurrency, WithdrawReasons, OnUnbalanced, Imbalance, Get, - UnixTime, EstimateNextNewSession, EnsureOrigin, CurrencyToVote, IsSubType, - } + UnixTime, EstimateNextNewSession, EnsureOrigin, CurrencyToVote, + }, }; use pallet_session::historical; use sp_runtime::{ @@ -309,11 +308,7 @@ use sp_runtime::{ curve::PiecewiseLinear, traits::{ Convert, Zero, StaticLookup, CheckedSub, Saturating, SaturatedConversion, - AtLeast32BitUnsigned, Dispatchable, - }, - transaction_validity::{ - TransactionValidityError, TransactionValidity, ValidTransaction, InvalidTransaction, - TransactionSource, TransactionPriority, + AtLeast32BitUnsigned, }, }; use sp_staking::{ @@ -323,15 +318,10 @@ use sp_staking::{ #[cfg(feature = "std")] use sp_runtime::{Serialize, Deserialize}; use frame_system::{ - self as system, ensure_signed, ensure_root, ensure_none, + self as system, ensure_signed, ensure_root, offchain::SendTransactionTypes, }; -use sp_npos_elections::{ - ExtendedBalance, Assignment, ElectionScore, ElectionResult as PrimitiveElectionResult, - to_supports, EvaluateSupport, seq_phragmen, generate_solution_type, is_score_better, Supports, - VoteWeight, CompactSolution, PerThing128, -}; -use frame_election_provider_support::{ElectionProvider, data_provider}; +use frame_election_provider_support::{ElectionProvider, VoteWeight, Supports, data_provider}; pub use weights::WeightInfo; const STAKING_ID: LockIdentifier = *b"staking "; @@ -343,7 +333,7 @@ macro_rules! log { ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { log::$level!( target: crate::LOG_TARGET, - concat!("💸 ", $patter) $(, $values)* + concat!("[{:?}] 💸 ", $patter), >::block_number() $(, $values)* ) }; } @@ -361,8 +351,6 @@ static_assertions::const_assert!(size_of::() <= size_of::() static_assertions::const_assert!(size_of::() <= size_of::()); /// Maximum number of stakers that can be stored in a snapshot. -pub(crate) const MAX_VALIDATORS: usize = ValidatorIndex::max_value() as usize; -pub(crate) const MAX_NOMINATORS: usize = NominatorIndex::max_value() as usize; pub const MAX_NOMINATIONS: usize = ::LIMIT; @@ -375,14 +363,11 @@ pub type EraIndex = u32; pub type RewardPoint = u32; // Note: Maximum nomination limit is set here -- 16. -generate_solution_type!( +sp_npos_elections::generate_solution_type!( #[compact] pub struct CompactAssignments::(16) ); -/// Accuracy used for on-chain election. -pub type ChainAccuracy = Perbill; - /// Accuracy used for off-chain election. This better be small. pub type OffchainAccuracy = PerU16; @@ -670,78 +655,6 @@ pub struct UnappliedSlash { payout: Balance, } -/// Indicate how an election round was computed. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] -pub enum ElectionCompute { - /// Result was forcefully computed on chain at the end of the session. - OnChain, - /// Result was submitted and accepted to the chain via a signed transaction. - Signed, - /// Result was submitted and accepted to the chain via an unsigned transaction (by an - /// authority). - Unsigned, -} - -/// The result of an election round. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -pub struct ElectionResult { - /// Flat list of validators who have been elected. - elected_stashes: Vec, - /// Flat list of new exposures, to be updated in the [`Exposure`] storage. - exposures: Vec<(AccountId, Exposure)>, - /// Type of the result. This is kept on chain only to track and report the best score's - /// submission type. An optimisation could remove this. - compute: ElectionCompute, -} - -/// The status of the upcoming (offchain) election. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -pub enum ElectionStatus { - /// Nothing has and will happen for now. submission window is not open. - Closed, - /// The submission window has been open since the contained block number. - Open(BlockNumber), -} - -/// Some indications about the size of the election. This must be submitted with the solution. -/// -/// Note that these values must reflect the __total__ number, not only those that are present in the -/// solution. In short, these should be the same size as the size of the values dumped in -/// `SnapshotValidators` and `SnapshotNominators`. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, Default)] -pub struct ElectionSize { - /// Number of validators in the snapshot of the current election round. - #[codec(compact)] - pub validators: ValidatorIndex, - /// Number of nominators in the snapshot of the current election round. - #[codec(compact)] - pub nominators: NominatorIndex, -} - - -impl ElectionStatus { - pub fn is_open_at(&self, n: BlockNumber) -> bool { - *self == Self::Open(n) - } - - pub fn is_closed(&self) -> bool { - match self { - Self::Closed => true, - _ => false - } - } - - pub fn is_open(&self) -> bool { - !self.is_closed() - } -} - -impl Default for ElectionStatus { - fn default() -> Self { - Self::Closed - } -} - /// Means for interacting with a specialized version of the `session` trait. /// /// This is needed because `Staking` sets the `ValidatorIdOf` of the `pallet_session::Config` @@ -892,45 +805,12 @@ pub trait Config: frame_system::Config + SendTransactionTypes> { /// Something that can estimate the next session change, accurately or as a best effort guess. type NextNewSession: EstimateNextNewSession; - /// The number of blocks before the end of the era from which election submissions are allowed. - /// - /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will - /// be used. - /// - /// This is bounded by being within the last session. Hence, setting it to a value more than the - /// length of a session will be pointless. - type ElectionLookahead: Get; - - /// The overarching call type. - type Call: Dispatchable + From> + IsSubType> + Clone; - - /// Maximum number of balancing iterations to run in the offchain submission. - /// - /// If set to 0, balance_solution will not be executed at all. - type MaxIterations: Get; - - /// The threshold of improvement that should be provided for a new solution to be accepted. - type MinSolutionScoreBump: Get; - /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim /// their reward. This used to limit the i/o cost for the nominator payout. type MaxNominatorRewardedPerValidator: Get; - /// A configuration for base priority of unsigned transactions. - /// - /// This is exposed so that it can be tuned for particular runtime, when - /// multiple pallets send unsigned transactions. - type UnsignedPriority: Get; - - /// Maximum weight that the unsigned transaction can have. - /// - /// Chose this value with care. On one hand, it should be as high as possible, so the solution - /// can contain as many nominators/validators as possible. On the other hand, it should be small - /// enough to fit in the block. - type OffchainSolutionWeightLimit: Get; - /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -964,12 +844,13 @@ enum Releases { V2_0_0, V3_0_0, V4_0_0, - V5_0_0, + V5_0_0, // blockable validators. + V6_0_0, // removal of all storage associated with offchain phragmen. } impl Default for Releases { fn default() -> Self { - Releases::V5_0_0 + Releases::V6_0_0 } } @@ -1134,47 +1015,11 @@ decl_storage! { /// This is basically in sync with the call to [`SessionManager::new_session`]. pub CurrentPlannedSession get(fn current_planned_session): SessionIndex; - /// Snapshot of validators at the beginning of the current election window. This should only - /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub SnapshotValidators get(fn snapshot_validators): Option>; - - /// Snapshot of nominators at the beginning of the current election window. This should only - /// have a value when [`EraElectionStatus`] == `ElectionStatus::Open(_)`. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub SnapshotNominators get(fn snapshot_nominators): Option>; - - /// The next validator set. At the end of an era, if this is available (potentially from the - /// result of an offchain worker), it is immediately used. Otherwise, the on-chain election - /// is executed. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub QueuedElected get(fn queued_elected): Option>>; - - /// The score of the current [`QueuedElected`]. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub QueuedScore get(fn queued_score): Option; - - /// Flag to control the execution of the offchain election. When `Open(_)`, we accept - /// solutions to be submitted. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub EraElectionStatus get(fn era_election_status): ElectionStatus; - - /// True if the current **planned** session is final. Note that this does not take era - /// forcing into account. - /// - /// TWO_PHASE_NOTE: should be removed once we switch to multi-phase. - pub IsCurrentSessionFinal get(fn is_current_session_final): bool = false; - /// True if network has been upgraded to this version. /// Storage version of the pallet. /// - /// This is set to v5.0.0 for new networks. - StorageVersion build(|_: &GenesisConfig| Releases::V5_0_0): Releases; + /// This is set to v6.0.0 for new networks. + StorageVersion build(|_: &GenesisConfig| Releases::V6_0_0): Releases; } add_extra_genesis { config(stakers): @@ -1213,23 +1058,61 @@ decl_storage! { pub mod migrations { use super::*; - #[derive(Decode)] - struct OldValidatorPrefs { - #[codec(compact)] - pub commission: Perbill - } - impl OldValidatorPrefs { - fn upgraded(self) -> ValidatorPrefs { - ValidatorPrefs { - commission: self.commission, - .. Default::default() + pub mod v6 { + use super::*; + use frame_support::{traits::Get, weights::Weight, pallet_prelude::*}; + + macro_rules! generate_storage_types { + ($name:ident => Value<$value:ty>) => { + paste::paste! { + struct [<$name Instance>]; + impl frame_support::traits::StorageInstance for [<$name Instance>] { + fn pallet_prefix() -> &'static str { + "Staking" + } + const STORAGE_PREFIX: &'static str = stringify!($name); + } + type $name = StorageValue<[<$name Instance>], $value, ValueQuery>; + } } } - } - pub fn migrate_to_blockable() -> frame_support::weights::Weight { - Validators::::translate::(|_, p| Some(p.upgraded())); - ErasValidatorPrefs::::translate::(|_, _, p| Some(p.upgraded())); - T::BlockWeights::get().max_block + + // NOTE: value type doesn't matter, we just set it to () here. + generate_storage_types!(SnapshotValidators => Value<()>); + generate_storage_types!(SnapshotNominators => Value<()>); + generate_storage_types!(QueuedElected => Value<()>); + generate_storage_types!(QueuedScore => Value<()>); + generate_storage_types!(EraElectionStatus => Value<()>); + generate_storage_types!(IsCurrentSessionFinal => Value<()>); + + /// check to execute prior to migration. + pub fn pre_migrate() -> Result<(), &'static str> { + // these may or may not exist. + log!(info, "SnapshotValidators.exits()? {:?}", SnapshotValidators::exists()); + log!(info, "SnapshotNominators.exits()? {:?}", SnapshotNominators::exists()); + log!(info, "QueuedElected.exits()? {:?}", QueuedElected::exists()); + log!(info, "QueuedScore.exits()? {:?}", QueuedScore::exists()); + // these must exist. + assert!(IsCurrentSessionFinal::exists(), "IsCurrentSessionFinal storage item not found!"); + assert!(EraElectionStatus::exists(), "EraElectionStatus storage item not found!"); + Ok(()) + } + + /// Migrate storage to v6. + pub fn migrate() -> Weight { + log!(info, "Migrating staking to Releases::V6_0_0"); + + SnapshotValidators::kill(); + SnapshotNominators::kill(); + QueuedElected::kill(); + QueuedScore::kill(); + EraElectionStatus::kill(); + IsCurrentSessionFinal::kill(); + + StorageVersion::put(Releases::V6_0_0); + log!(info, "Done."); + T::DbWeight::get().writes(6 + 1) + } } } @@ -1247,10 +1130,8 @@ decl_event!( /// An old slashing report from a prior era was discarded because it could /// not be processed. \[session_index\] OldSlashingReportDiscarded(SessionIndex), - /// A new set of stakers was elected with the given \[compute\]. - StakingElection(ElectionCompute), - /// A new solution for the upcoming election has been stored. \[compute\] - SolutionStored(ElectionCompute), + /// A new set of stakers was elected. + StakingElection, /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, @@ -1299,37 +1180,6 @@ decl_error! { NotSortedAndUnique, /// Rewards for this era have already been claimed for this validator. AlreadyClaimed, - /// The submitted result is received out of the open window. - OffchainElectionEarlySubmission, - /// The submitted result is not as good as the one stored on chain. - OffchainElectionWeakSubmission, - /// The snapshot data of the current window is missing. - SnapshotUnavailable, - /// Incorrect number of winners were presented. - OffchainElectionBogusWinnerCount, - /// One of the submitted winners is not an active candidate on chain (index is out of range - /// in snapshot). - OffchainElectionBogusWinner, - /// Error while building the assignment type from the compact. This can happen if an index - /// is invalid, or if the weights _overflow_. - OffchainElectionBogusCompact, - /// One of the submitted nominators is not an active nominator on chain. - OffchainElectionBogusNominator, - /// One of the submitted nominators has an edge to which they have not voted on chain. - OffchainElectionBogusNomination, - /// One of the submitted nominators has an edge which is submitted before the last non-zero - /// slash of the target. - OffchainElectionSlashedNomination, - /// A self vote must only be originated from a validator to ONLY themselves. - OffchainElectionBogusSelfVote, - /// The submitted result has unknown edges that are not among the presented winners. - OffchainElectionBogusEdge, - /// The claimed score does not match with the one computed from the data. - OffchainElectionBogusScore, - /// The election size is invalid. - OffchainElectionBogusElectionSize, - /// The call is not allowed at the given time due to restrictions of election period. - CallNotAllowed, /// Incorrect previous history depth input provided. IncorrectHistoryDepth, /// Incorrect number of slashing spans provided. @@ -1358,23 +1208,6 @@ decl_module! { /// intervention. const SlashDeferDuration: EraIndex = T::SlashDeferDuration::get(); - /// The number of blocks before the end of the era from which election submissions are allowed. - /// - /// Setting this to zero will disable the offchain compute and only on-chain seq-phragmen will - /// be used. - /// - /// This is bounded by being within the last session. Hence, setting it to a value more than the - /// length of a session will be pointless. - const ElectionLookahead: T::BlockNumber = T::ElectionLookahead::get(); - - /// Maximum number of balancing iterations to run in the offchain submission. - /// - /// If set to 0, balance_solution will not be executed at all. - const MaxIterations: u32 = T::MaxIterations::get(); - - /// The threshold of improvement that should be provided for a new solution to be accepted. - const MinSolutionScoreBump: Perbill = T::MinSolutionScoreBump::get(); - /// The maximum number of nominators rewarded for each validator. /// /// For each validator only the `$MaxNominatorRewardedPerValidator` biggest stakers can claim @@ -1385,82 +1218,11 @@ decl_module! { fn deposit_event() = default; - fn on_runtime_upgrade() -> frame_support::weights::Weight { - if StorageVersion::get() == Releases::V4_0_0 { - StorageVersion::put(Releases::V5_0_0); - migrations::migrate_to_blockable::() + fn on_runtime_upgrade() -> Weight { + if StorageVersion::get() == Releases::V5_0_0 { + migrations::v6::migrate::() } else { - 0 - } - } - - /// sets `ElectionStatus` to `Open(now)` where `now` is the block number at which the - /// election window has opened, if we are at the last session and less blocks than - /// `T::ElectionLookahead` is remaining until the next new session schedule. The offchain - /// worker, if applicable, will execute at the end of the current block, and solutions may - /// be submitted. - fn on_initialize(now: T::BlockNumber) -> Weight { - let mut consumed_weight = 0; - let mut add_weight = |reads, writes, weight| { - consumed_weight += T::DbWeight::get().reads_writes(reads, writes); - consumed_weight += weight; - }; - - if - // if we don't have any ongoing offchain compute. - Self::era_election_status().is_closed() && - // either current session final based on the plan, or we're forcing. - (Self::is_current_session_final() || Self::will_era_be_forced()) - { - let (maybe_next_session_change, estimate_next_new_session_weight) = - T::NextNewSession::estimate_next_new_session(now); - - if let Some(next_session_change) = maybe_next_session_change { - if let Some(remaining) = next_session_change.checked_sub(&now) { - if remaining <= T::ElectionLookahead::get() && !remaining.is_zero() { - // create snapshot. - let (did_snapshot, snapshot_weight) = Self::create_stakers_snapshot(); - add_weight(0, 0, snapshot_weight); - if did_snapshot { - // Set the flag to make sure we don't waste any compute here in the same era - // after we have triggered the offline compute. - >::put( - ElectionStatus::::Open(now) - ); - add_weight(0, 1, 0); - log!(info, "Election window is Open({:?}). Snapshot created", now); - } else { - log!(warn, "Failed to create snapshot at {:?}.", now); - } - } - } - } else { - log!(warn, "Estimating next session change failed."); - } - add_weight(0, 0, estimate_next_new_session_weight) - } - // For `era_election_status`, `is_current_session_final`, `will_era_be_forced` - add_weight(3, 0, 0); - // Additional read from `on_finalize` - add_weight(1, 0, 0); - consumed_weight - } - - /// Check if the current block number is the one at which the election window has been set - /// to open. If so, it runs the offchain worker code. - fn offchain_worker(now: T::BlockNumber) { - use offchain_election::{set_check_offchain_execution_status, compute_offchain_election}; - if Self::era_election_status().is_open_at(now) { - let offchain_status = set_check_offchain_execution_status::(now); - if let Err(why) = offchain_status { - log!(warn, "skipping offchain worker in open election window due to [{}]", why); - } else { - if let Err(e) = compute_offchain_election::() { - log!(error, "Error in election offchain worker: {:?}", e); - } else { - log!(debug, "Executed offchain worker thread without errors."); - } - } + T::DbWeight::get().reads(1) } } @@ -1488,17 +1250,7 @@ decl_module! { ); use sp_runtime::UpperOf; - // see the documentation of `Assignment::try_normalize`. Now we can ensure that this - // will always return `Ok`. - // 1. Maximum sum of Vec must fit into `UpperOf`. - assert!( - >>::try_into(MAX_NOMINATIONS) - .unwrap() - .checked_mul(::one().deconstruct().try_into().unwrap()) - .is_some() - ); - - // 2. Maximum sum of Vec must fit into `UpperOf`. + // 1. Maximum sum of Vec must fit into `UpperOf`. assert!( >>::try_into(MAX_NOMINATIONS) .unwrap() @@ -1599,7 +1351,6 @@ decl_module! { /// # #[weight = T::WeightInfo::bond_extra()] fn bond_extra(origin, #[compact] max_additional: BalanceOf) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let stash = ensure_signed(origin)?; let controller = Self::bonded(&stash).ok_or(Error::::NotStash)?; @@ -1652,7 +1403,6 @@ decl_module! { /// #[weight = T::WeightInfo::unbond()] fn unbond(origin, #[compact] value: BalanceOf) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( @@ -1712,7 +1462,6 @@ decl_module! { /// # #[weight = T::WeightInfo::withdraw_unbonded_kill(*num_slashing_spans)] fn withdraw_unbonded(origin, num_slashing_spans: u32) -> DispatchResultWithPostInfo { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let (stash, old_total) = (ledger.stash.clone(), ledger.total); @@ -1767,7 +1516,6 @@ decl_module! { /// # #[weight = T::WeightInfo::validate()] pub fn validate(origin, prefs: ValidatorPrefs) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -1796,7 +1544,6 @@ decl_module! { /// # #[weight = T::WeightInfo::nominate(targets.len() as u32)] pub fn nominate(origin, targets: Vec<::Source>) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -1844,7 +1591,6 @@ decl_module! { /// # #[weight = T::WeightInfo::chill()] fn chill(origin) { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; Self::chill_stash(&ledger.stash); @@ -2088,7 +1834,6 @@ decl_module! { /// # #[weight = T::WeightInfo::payout_stakers_alive_staked(T::MaxNominatorRewardedPerValidator::get())] fn payout_stakers(origin, validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); ensure_signed(origin)?; Self::do_payout_stakers(validator_stash, era) } @@ -2109,7 +1854,6 @@ decl_module! { /// # #[weight = T::WeightInfo::rebond(MAX_UNLOCKING_CHUNKS as u32)] fn rebond(origin, #[compact] value: BalanceOf) -> DispatchResultWithPostInfo { - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let controller = ensure_signed(origin)?; let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!(!ledger.unlocking.is_empty(), Error::::NoUnlockChunk); @@ -2188,121 +1932,6 @@ decl_module! { T::Currency::remove_lock(STAKING_ID, &stash); } - /// Submit an election result to the chain. If the solution: - /// - /// 1. is valid. - /// 2. has a better score than a potentially existing solution on chain. - /// - /// then, it will be _put_ on chain. - /// - /// A solution consists of two pieces of data: - /// - /// 1. `winners`: a flat vector of all the winners of the round. - /// 2. `assignments`: the compact version of an assignment vector that encodes the edge - /// weights. - /// - /// Both of which may be computed using _phragmen_, or any other algorithm. - /// - /// Additionally, the submitter must provide: - /// - /// - The `score` that they claim their solution has. - /// - /// Both validators and nominators will be represented by indices in the solution. The - /// indices should respect the corresponding types ([`ValidatorIndex`] and - /// [`NominatorIndex`]). Moreover, they should be valid when used to index into - /// [`SnapshotValidators`] and [`SnapshotNominators`]. Any invalid index will cause the - /// solution to be rejected. These two storage items are set during the election window and - /// may be used to determine the indices. - /// - /// A solution is valid if: - /// - /// 0. It is submitted when [`EraElectionStatus`] is `Open`. - /// 1. Its claimed score is equal to the score computed on-chain. - /// 2. Presents the correct number of winners. - /// 3. All indexes must be value according to the snapshot vectors. All edge values must - /// also be correct and should not overflow the granularity of the ratio type (i.e. 256 - /// or billion). - /// 4. For each edge, all targets are actually nominated by the voter. - /// 5. Has correct self-votes. - /// - /// A solutions score is consisted of 3 parameters: - /// - /// 1. `min { support.total }` for each support of a winner. This value should be maximized. - /// 2. `sum { support.total }` for each support of a winner. This value should be minimized. - /// 3. `sum { support.total^2 }` for each support of a winner. This value should be - /// minimized (to ensure less variance) - /// - /// # - /// The transaction is assumed to be the longest path, a better solution. - /// - Initial solution is almost the same. - /// - Worse solution is retraced in pre-dispatch-checks which sets its own weight. - /// # - #[weight = T::WeightInfo::submit_solution_better( - size.validators.into(), - size.nominators.into(), - compact.voter_count() as u32, - winners.len() as u32, - )] - pub fn submit_election_solution( - origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - era: EraIndex, - size: ElectionSize, - ) -> DispatchResultWithPostInfo { - let _who = ensure_signed(origin)?; - Self::check_and_replace_solution( - winners, - compact, - ElectionCompute::Signed, - score, - era, - size, - ) - } - - /// Unsigned version of `submit_election_solution`. - /// - /// Note that this must pass the [`ValidateUnsigned`] check which only allows transactions - /// from the local node to be included. In other words, only the block author can include a - /// transaction in the block. - /// - /// # - /// See [`submit_election_solution`]. - /// # - #[weight = T::WeightInfo::submit_solution_better( - size.validators.into(), - size.nominators.into(), - compact.voter_count() as u32, - winners.len() as u32, - )] - pub fn submit_election_solution_unsigned( - origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - era: EraIndex, - size: ElectionSize, - ) -> DispatchResultWithPostInfo { - ensure_none(origin)?; - let adjustments = Self::check_and_replace_solution( - winners, - compact, - ElectionCompute::Unsigned, - score, - era, - size, - ).expect( - "An unsigned solution can only be submitted by validators; A validator should \ - always produce correct solutions, else this block should not be imported, thus \ - effectively depriving the validators from their authoring reward. Hence, this panic - is expected." - ); - - Ok(adjustments) - } - /// Remove the given nominations from the calling validator. /// /// Effects will be felt at the beginning of the next era. @@ -2319,7 +1948,6 @@ decl_module! { #[weight = T::WeightInfo::kick(who.len() as u32)] pub fn kick(origin, who: Vec<::Source>) -> DispatchResult { let controller = ensure_signed(origin)?; - ensure!(Self::era_election_status().is_closed(), Error::::CallNotAllowed); let ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; let stash = &ledger.stash; @@ -2369,52 +1997,6 @@ impl Module { }) } - /// Dump the list of validators and nominators into vectors and keep them on-chain. - /// - /// This data is used to efficiently evaluate election results. returns `true` if the operation - /// is successful. - pub fn create_stakers_snapshot() -> (bool, Weight) { - let mut consumed_weight = 0; - let mut add_db_reads_writes = |reads, writes| { - consumed_weight += T::DbWeight::get().reads_writes(reads, writes); - }; - let validators = >::iter().map(|(v, _)| v).collect::>(); - let mut nominators = >::iter().map(|(n, _)| n).collect::>(); - - let num_validators = validators.len(); - let num_nominators = nominators.len(); - add_db_reads_writes((num_validators + num_nominators) as Weight, 0); - - if - num_validators > MAX_VALIDATORS || - num_nominators.saturating_add(num_validators) > MAX_NOMINATORS - { - log!( - warn, - "Snapshot size too big [{} <> {}][{} <> {}].", - num_validators, - MAX_VALIDATORS, - num_nominators, - MAX_NOMINATORS, - ); - (false, consumed_weight) - } else { - // all validators nominate themselves; - nominators.extend(validators.clone()); - - >::put(validators); - >::put(nominators); - add_db_reads_writes(0, 2); - (true, consumed_weight) - } - } - - /// Clears both snapshots of stakers. - fn kill_stakers_snapshot() { - >::kill(); - >::kill(); - } - fn do_payout_stakers(validator_stash: T::AccountId, era: EraIndex) -> DispatchResult { // Validate input data let current_era = CurrentEra::get().ok_or(Error::::InvalidEraToReward)?; @@ -2571,18 +2153,15 @@ impl Module { .unwrap_or(0); // Must never happen. match ForceEra::get() { + // Will set to default again, which is `NotForcing`. Forcing::ForceNew => ForceEra::kill(), + // Short circuit to `new_era`. Forcing::ForceAlways => (), + // Only go to `new_era` if deadline reached. Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (), _ => { - // Either `ForceNone`, or `NotForcing && era_length < T::SessionsPerEra::get()`. - if era_length + 1 == T::SessionsPerEra::get() { - IsCurrentSessionFinal::put(true); - } else if era_length >= T::SessionsPerEra::get() { - // Should only happen when we are ready to trigger an era but we have ForceNone, - // otherwise previous arm would short circuit. - Self::close_election_window(); - } + // either `Forcing::ForceNone`, + // or `Forcing::NotForcing if era_length >= T::SessionsPerEra::get()`. return None }, } @@ -2591,219 +2170,11 @@ impl Module { Self::new_era(session_index) } else { // Set initial era + log!(debug, "Starting the first era."); Self::new_era(session_index) } } - /// Basic and cheap checks that we perform in validate unsigned, and in the execution. - /// - /// State reads: ElectionState, CurrentEr, QueuedScore. - /// - /// This function does weight refund in case of errors, which is based upon the fact that it is - /// called at the very beginning of the call site's function. - pub fn pre_dispatch_checks(score: ElectionScore, era: EraIndex) -> DispatchResultWithPostInfo { - // discard solutions that are not in-time - // check window open - ensure!( - Self::era_election_status().is_open(), - Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(1)), - ); - - // check current era. - if let Some(current_era) = Self::current_era() { - ensure!( - current_era == era, - Error::::OffchainElectionEarlySubmission.with_weight(T::DbWeight::get().reads(2)), - ) - } - - // assume the given score is valid. Is it better than what we have on-chain, if we have any? - if let Some(queued_score) = Self::queued_score() { - ensure!( - is_score_better(score, queued_score, T::MinSolutionScoreBump::get()), - Error::::OffchainElectionWeakSubmission.with_weight(T::DbWeight::get().reads(3)), - ) - } - - Ok(None.into()) - } - - /// Checks a given solution and if correct and improved, writes it on chain as the queued result - /// of the next round. This may be called by both a signed and an unsigned transaction. - pub fn check_and_replace_solution( - winners: Vec, - compact_assignments: CompactAssignments, - compute: ElectionCompute, - claimed_score: ElectionScore, - era: EraIndex, - election_size: ElectionSize, - ) -> DispatchResultWithPostInfo { - // Do the basic checks. era, claimed score and window open. - let _ = Self::pre_dispatch_checks(claimed_score, era)?; - - // before we read any further state, we check that the unique targets in compact is same as - // compact. is a all in-memory check and easy to do. Moreover, it ensures that the solution - // is not full of bogus edges that can cause lots of reads to SlashingSpans. Thus, we can - // assume that the storage access of this function is always O(|winners|), not - // O(|compact.edge_count()|). - ensure!( - compact_assignments.unique_targets().len() == winners.len(), - Error::::OffchainElectionBogusWinnerCount, - ); - - // Check that the number of presented winners is sane. Most often we have more candidates - // than we need. Then it should be `Self::validator_count()`. Else it should be all the - // candidates. - let snapshot_validators_length = >::decode_len() - .map(|l| l as u32) - .ok_or_else(|| Error::::SnapshotUnavailable)?; - - // size of the solution must be correct. - ensure!( - snapshot_validators_length == u32::from(election_size.validators), - Error::::OffchainElectionBogusElectionSize, - ); - - // check the winner length only here and when we know the length of the snapshot validators - // length. - let desired_winners = Self::validator_count().min(snapshot_validators_length); - ensure!(winners.len() as u32 == desired_winners, Error::::OffchainElectionBogusWinnerCount); - - let snapshot_nominators_len = >::decode_len() - .map(|l| l as u32) - .ok_or_else(|| Error::::SnapshotUnavailable)?; - - // rest of the size of the solution must be correct. - ensure!( - snapshot_nominators_len == election_size.nominators, - Error::::OffchainElectionBogusElectionSize, - ); - - // decode snapshot validators. - let snapshot_validators = Self::snapshot_validators() - .ok_or(Error::::SnapshotUnavailable)?; - - // check if all winners were legit; this is rather cheap. Replace with accountId. - let winners = winners.into_iter().map(|widx| { - // NOTE: at the moment, since staking is explicitly blocking any offence until election - // is closed, we don't check here if the account id at `snapshot_validators[widx]` is - // actually a validator. If this ever changes, this loop needs to also check this. - snapshot_validators.get(widx as usize).cloned().ok_or(Error::::OffchainElectionBogusWinner) - }).collect::, Error>>()?; - - // decode the rest of the snapshot. - let snapshot_nominators = Self::snapshot_nominators() - .ok_or(Error::::SnapshotUnavailable)?; - - // helpers - let nominator_at = |i: NominatorIndex| -> Option { - snapshot_nominators.get(i as usize).cloned() - }; - let validator_at = |i: ValidatorIndex| -> Option { - snapshot_validators.get(i as usize).cloned() - }; - - // un-compact. - let assignments = compact_assignments.into_assignment( - nominator_at, - validator_at, - ).map_err(|e| { - // log the error since it is not propagated into the runtime error. - log!(warn, "un-compacting solution failed due to {:?}", e); - Error::::OffchainElectionBogusCompact - })?; - - // check all nominators actually including the claimed vote. Also check correct self votes. - // Note that we assume all validators and nominators in `assignments` are properly bonded, - // because they are coming from the snapshot via a given index. - for Assignment { who, distribution } in assignments.iter() { - let is_validator = >::contains_key(&who); - let maybe_nomination = Self::nominators(&who); - - if !(maybe_nomination.is_some() ^ is_validator) { - // all of the indices must map to either a validator or a nominator. If this is ever - // not the case, then the locking system of staking is most likely faulty, or we - // have bigger problems. - log!(error, "detected an error in the staking locking and snapshot."); - // abort. - return Err(Error::::OffchainElectionBogusNominator.into()); - } - - if !is_validator { - // a normal vote - let nomination = maybe_nomination.expect( - "exactly one of `maybe_validator` and `maybe_nomination.is_some` is true. \ - is_validator is false; maybe_nomination is some; qed" - ); - - // NOTE: we don't really have to check here if the sum of all edges are the - // nominator correct. Un-compacting assures this by definition. - - for (t, _) in distribution { - // each target in the provided distribution must be actually nominated by the - // nominator after the last non-zero slash. - if nomination.targets.iter().find(|&tt| tt == t).is_none() { - return Err(Error::::OffchainElectionBogusNomination.into()); - } - - if ::SlashingSpans::get(&t).map_or( - false, - |spans| nomination.submitted_in < spans.last_nonzero_slash(), - ) { - return Err(Error::::OffchainElectionSlashedNomination.into()); - } - } - } else { - // a self vote - ensure!(distribution.len() == 1, Error::::OffchainElectionBogusSelfVote); - ensure!(distribution[0].0 == *who, Error::::OffchainElectionBogusSelfVote); - // defensive only. A compact assignment of length one does NOT encode the weight and - // it is always created to be 100%. - ensure!( - distribution[0].1 == OffchainAccuracy::one(), - Error::::OffchainElectionBogusSelfVote, - ); - } - } - - // convert into staked assignments. - let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( - assignments, - Self::slashable_balance_of_fn(), - ); - - // build the support map thereof in order to evaluate. - let supports = to_supports(&winners, &staked_assignments) - .map_err(|_| Error::::OffchainElectionBogusEdge)?; - - // Check if the score is the same as the claimed one. - let submitted_score = (&supports).evaluate(); - ensure!(submitted_score == claimed_score, Error::::OffchainElectionBogusScore); - - // At last, alles Ok. Exposures and store the result. - let exposures = Self::collect_exposures(supports); - log!( - info, - "A better solution (with compute {:?} and score {:?}) has been validated and stored \ - on chain.", - compute, - submitted_score, - ); - - // write new results. - >::put(ElectionResult { - elected_stashes: winners, - exposures, - compute, - }); - QueuedScore::put(submitted_score); - - // emit event. - Self::deposit_event(RawEvent::SolutionStored(compute)); - - Ok(None.into()) - } - /// Start a session potentially starting an era. fn start_session(start_session: SessionIndex) { let next_active_era = Self::active_era().map(|e| e.index + 1).unwrap_or(0); @@ -2912,251 +2283,27 @@ impl Module { } // Set staking information for new era. - let maybe_new_validators = Self::select_and_update_validators(current_era); - // TWO_PHASE_NOTE: use this later on. - let _unused_new_validators = Self::enact_election(current_era); + let maybe_new_validators = Self::enact_election(current_era); maybe_new_validators } - /// Remove all the storage items associated with the election. - fn close_election_window() { - // Close window. - >::put(ElectionStatus::Closed); - // Kill snapshots. - Self::kill_stakers_snapshot(); - // Don't track final session. - IsCurrentSessionFinal::put(false); - } - - /// Select the new validator set at the end of the era. - /// - /// Runs [`try_do_phragmen`] and updates the following storage items: - /// - [`EraElectionStatus`]: with `None`. - /// - [`ErasStakers`]: with the new staker set. - /// - [`ErasStakersClipped`]. - /// - [`ErasValidatorPrefs`]. - /// - [`ErasTotalStake`]: with the new total stake. - /// - [`SnapshotValidators`] and [`SnapshotNominators`] are both removed. - /// - /// Internally, [`QueuedElected`], snapshots and [`QueuedScore`] are also consumed. - /// - /// If the election has been successful, It passes the new set upwards. + /// Enact and process the election using the `ElectionProvider` type. /// - /// This should only be called at the end of an era. - fn select_and_update_validators(current_era: EraIndex) -> Option> { - if let Some(ElectionResult::> { - elected_stashes, - exposures, - compute, - }) = Self::try_do_election() { - // Totally close the election round and data. - Self::close_election_window(); - - // Populate Stakers and write slot stake. - let mut total_stake: BalanceOf = Zero::zero(); - exposures.into_iter().for_each(|(stash, exposure)| { - total_stake = total_stake.saturating_add(exposure.total); - >::insert(current_era, &stash, &exposure); - - let mut exposure_clipped = exposure; - let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize; - if exposure_clipped.others.len() > clipped_max_len { - exposure_clipped.others.sort_by(|a, b| a.value.cmp(&b.value).reverse()); - exposure_clipped.others.truncate(clipped_max_len); - } - >::insert(¤t_era, &stash, exposure_clipped); - }); - - // Insert current era staking information - >::insert(¤t_era, total_stake); - - // collect the pref of all winners - for stash in &elected_stashes { - let pref = Self::validators(stash); - >::insert(¤t_era, stash, pref); - } - - // emit event - Self::deposit_event(RawEvent::StakingElection(compute)); - - if current_era > 0 { - log!( - info, - "new validator set of size {:?} has been elected via {:?} for staring era {:?}", - elected_stashes.len(), - compute, - current_era, + /// This will also process the election, as noted in [`process_election`]. + fn enact_election(current_era: EraIndex) -> Option> { + T::ElectionProvider::elect() + .map_err(|e| { + log!(warn, "election provider failed due to {:?}", e) + }) + .and_then(|(res, weight)| { + >::register_extra_weight_unchecked( + weight, + frame_support::weights::DispatchClass::Mandatory, ); - } - - Some(elected_stashes) - } else { - None - } - } - - /// Select a new validator set from the assembled stakers and their role preferences. It tries - /// first to peek into [`QueuedElected`]. Otherwise, it runs a new on-chain phragmen election. - /// - /// If [`QueuedElected`] and [`QueuedScore`] exists, they are both removed. No further storage - /// is updated. - fn try_do_election() -> Option>> { - // an election result from either a stored submission or locally executed one. - let next_result = >::take().or_else(|| - Self::do_on_chain_phragmen() - ); - - // either way, kill this. We remove it here to make sure it always has the exact same - // lifetime as `QueuedElected`. - QueuedScore::kill(); - - next_result - } - - /// Execute election and return the new results. The edge weights are processed into support - /// values. - /// - /// This is basically a wrapper around [`Self::do_phragmen`] which translates - /// `PrimitiveElectionResult` into `ElectionResult`. - /// - /// No storage item is updated. - pub fn do_on_chain_phragmen() -> Option>> { - if let Some(phragmen_result) = Self::do_phragmen::(0) { - let elected_stashes = phragmen_result.winners.iter() - .map(|(s, _)| s.clone()) - .collect::>(); - let assignments = phragmen_result.assignments; - - let staked_assignments = sp_npos_elections::assignment_ratio_to_staked( - assignments, - Self::slashable_balance_of_fn(), - ); - - let supports = to_supports( - &elected_stashes, - &staked_assignments, - ) - .map_err(|_| - log!( - error, - "on-chain phragmen is failing due to a problem in the result. This must be a bug." - ) - ) - .ok()?; - - // collect exposures - let exposures = Self::collect_exposures(supports); - - // In order to keep the property required by `on_session_ending` that we must return the - // new validator set even if it's the same as the old, as long as any underlying - // economic conditions have changed, we don't attempt to do any optimization where we - // compare against the prior set. - Some(ElectionResult::> { - elected_stashes, - exposures, - compute: ElectionCompute::OnChain, + Self::process_election(res, current_era) }) - } else { - // There were not enough candidates for even our minimal level of functionality. This is - // bad. We should probably disable all functionality except for block production and let - // the chain keep producing blocks until we can decide on a sufficiently substantial - // set. TODO: #2494 - None - } - } - - /// Execute phragmen election and return the new results. No post-processing is applied and the - /// raw edge weights are returned. - /// - /// Self votes are added and nominations before the most recent slashing span are ignored. - /// - /// No storage item is updated. - pub fn do_phragmen( - iterations: usize, - ) -> Option> { - let weight_of = Self::slashable_balance_of_fn(); - let mut all_nominators: Vec<(T::AccountId, VoteWeight, Vec)> = Vec::new(); - let mut all_validators = Vec::new(); - for (validator, _) in >::iter() { - // append self vote - let self_vote = (validator.clone(), weight_of(&validator), vec![validator.clone()]); - all_nominators.push(self_vote); - all_validators.push(validator); - } - - let nominator_votes = >::iter().map(|(nominator, nominations)| { - let Nominations { submitted_in, mut targets, suppressed: _ } = nominations; - - // Filter out nomination targets which were nominated before the most recent - // slashing span. - targets.retain(|stash| { - ::SlashingSpans::get(&stash).map_or( - true, - |spans| submitted_in >= spans.last_nonzero_slash(), - ) - }); - - (nominator, targets) - }); - all_nominators.extend(nominator_votes.map(|(n, ns)| { - let s = weight_of(&n); - (n, s, ns) - })); - - if all_validators.len() < Self::minimum_validator_count().max(1) as usize { - // If we don't have enough candidates, nothing to do. - log!( - warn, - "chain does not have enough staking candidates to operate. Era {:?}.", - Self::current_era() - ); - None - } else { - seq_phragmen::<_, Accuracy>( - Self::validator_count() as usize, - all_validators, - all_nominators, - Some((iterations, 0)), // exactly run `iterations` rounds. - ) - .map_err(|err| log!(error, "Call to seq-phragmen failed due to {:?}", err)) .ok() - } - } - - /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a - /// [`Exposure`]. - fn collect_exposures( - supports: Supports, - ) -> Vec<(T::AccountId, Exposure>)> { - let total_issuance = T::Currency::total_issuance(); - let to_currency = |e: ExtendedBalance| T::CurrencyToVote::to_currency(e, total_issuance); - - supports.into_iter().map(|(validator, support)| { - // build `struct exposure` from `support` - let mut others = Vec::with_capacity(support.voters.len()); - let mut own: BalanceOf = Zero::zero(); - let mut total: BalanceOf = Zero::zero(); - support.voters - .into_iter() - .map(|(nominator, weight)| (nominator, to_currency(weight))) - .for_each(|(nominator, stake)| { - if nominator == validator { - own = own.saturating_add(stake); - } else { - others.push(IndividualExposure { who: nominator, value: stake }); - } - total = total.saturating_add(stake); - }); - - let exposure = Exposure { - own, - others, - total, - }; - - (validator, exposure) - }).collect::)>>() } /// Process the output of the election. @@ -3166,8 +2313,6 @@ impl Module { /// /// Returns `Err(())` if less than [`MinimumValidatorCount`] validators have been elected, `Ok` /// otherwise. - // TWO_PHASE_NOTE: remove the dead code. - #[allow(dead_code)] pub fn process_election( flat_supports: sp_npos_elections::Supports, current_era: EraIndex, @@ -3175,18 +2320,21 @@ impl Module { let exposures = Self::collect_exposures(flat_supports); let elected_stashes = exposures.iter().cloned().map(|(x, _)| x).collect::>(); - if (elected_stashes.len() as u32) <= Self::minimum_validator_count() { + if (elected_stashes.len() as u32) < Self::minimum_validator_count().max(1) { + // Session will panic if we ever return an empty validator set, thus max(1) ^^. if current_era > 0 { log!( warn, - "chain does not have enough staking candidates to operate for era {:?}", + "chain does not have enough staking candidates to operate for era {:?} ({} elected, minimum is {})", current_era, + elected_stashes.len(), + Self::minimum_validator_count(), ); } return Err(()); } - // Populate Stakers and write slot stake. + // Populate stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); exposures.into_iter().for_each(|(stash, exposure)| { total_stake = total_stake.saturating_add(exposure.total); @@ -3211,28 +2359,54 @@ impl Module { } // emit event - // TWO_PHASE_NOTE: remove the inner value. - Self::deposit_event(RawEvent::StakingElection(ElectionCompute::Signed)); - - log!( - info, - "new validator set of size {:?} has been processed for era {:?}", - elected_stashes.len(), - current_era, - ); + Self::deposit_event(RawEvent::StakingElection); + + if current_era > 0 { + log!( + info, + "new validator set of size {:?} has been processed for era {:?}", + elected_stashes.len(), + current_era, + ); + } Ok(elected_stashes) } - /// Enact and process the election using the `ElectionProvider` type. - /// - /// This will also process the election, as noted in [`process_election`]. - fn enact_election(_current_era: EraIndex) -> Option> { - let _outcome = T::ElectionProvider::elect().map(|_| ()); - log!(debug, "Experimental election provider outputted {:?}", _outcome); - // TWO_PHASE_NOTE: This code path shall not return anything for now. Later on, redirect the - // results to `process_election`. - None + /// Consume a set of [`Supports`] from [`sp_npos_elections`] and collect them into a + /// [`Exposure`]. + fn collect_exposures( + supports: Supports, + ) -> Vec<(T::AccountId, Exposure>)> { + let total_issuance = T::Currency::total_issuance(); + let to_currency = |e: frame_election_provider_support::ExtendedBalance| { + T::CurrencyToVote::to_currency(e, total_issuance) + }; + + supports + .into_iter() + .map(|(validator, support)| { + // build `struct exposure` from `support` + let mut others = Vec::with_capacity(support.voters.len()); + let mut own: BalanceOf = Zero::zero(); + let mut total: BalanceOf = Zero::zero(); + support + .voters + .into_iter() + .map(|(nominator, weight)| (nominator, to_currency(weight))) + .for_each(|(nominator, stake)| { + if nominator == validator { + own = own.saturating_add(stake); + } else { + others.push(IndividualExposure { who: nominator, value: stake }); + } + total = total.saturating_add(stake); + }); + + let exposure = Exposure { own, others, total }; + (validator, exposure) + }) + .collect::)>>() } /// Remove all associated data of a stash account from the staking system. @@ -3319,13 +2493,6 @@ impl Module { } } - fn will_era_be_forced() -> bool { - match ForceEra::get() { - Forcing::ForceAlways | Forcing::ForceNew => true, - Forcing::ForceNone | Forcing::NotForcing => false, - } - } - #[cfg(feature = "runtime-benchmarks")] pub fn add_era_stakers( current_era: EraIndex, @@ -3335,11 +2502,6 @@ impl Module { >::insert(¤t_era, &controller, &exposure); } - #[cfg(feature = "runtime-benchmarks")] - pub fn put_election_status(status: ElectionStatus::) { - >::put(status); - } - #[cfg(feature = "runtime-benchmarks")] pub fn set_slash_reward_fraction(fraction: Perbill) { SlashRewardFraction::put(fraction); @@ -3365,13 +2527,17 @@ impl Module { all_voters.push(self_vote); } + // collect all slashing spans into a BTreeMap for further queries. + let slashing_spans = >::iter().collect::>(); + for (nominator, nominations) in >::iter() { let Nominations { submitted_in, mut targets, suppressed: _ } = nominations; // Filter out nomination targets which were nominated before the most recent // slashing span. targets.retain(|stash| { - Self::slashing_spans(&stash) + slashing_spans + .get(stash) .map_or(true, |spans| submitted_in >= spans.last_nonzero_slash()) }); @@ -3513,31 +2679,16 @@ impl frame_election_provider_support::ElectionDataProvider pallet_session::SessionManager for Module { fn new_session(new_index: SessionIndex) -> Option> { - log!( - trace, - "[{:?}] planning new_session({})", - >::block_number(), - new_index, - ); + log!(trace, "planning new_session({})", new_index); CurrentPlannedSession::put(new_index); Self::new_session(new_index) } fn start_session(start_index: SessionIndex) { - log!( - trace, - "[{:?}] starting start_session({})", - >::block_number(), - start_index, - ); + log!(trace, "starting start_session({})", start_index); Self::start_session(start_index) } fn end_session(end_index: SessionIndex) { - log!( - trace, - "[{:?}] ending end_session({})", - >::block_number(), - end_index, - ); + log!(trace, "ending end_session({})", end_index); Self::end_session(end_index) } } @@ -3752,8 +2903,8 @@ where } fn can_report() -> bool { - // TWO_PHASE_NOTE: we can get rid of this API - Self::era_election_status().is_closed() + // TODO: https://github.com/paritytech/substrate/issues/8343 + true } } @@ -3789,100 +2940,7 @@ where } } -#[allow(deprecated)] -impl frame_support::unsigned::ValidateUnsigned for Module { - type Call = Call; - fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_election_solution_unsigned( - _, - _, - score, - era, - _, - ) = call { - use offchain_election::DEFAULT_LONGEVITY; - - // discard solution not coming from the local OCW. - match source { - TransactionSource::Local | TransactionSource::InBlock => { /* allowed */ } - _ => { - log!(debug, "rejecting unsigned transaction because it is not local/in-block."); - return InvalidTransaction::Call.into(); - } - } - - if let Err(error_with_post_info) = Self::pre_dispatch_checks(*score, *era) { - let invalid = to_invalid(error_with_post_info); - log!( - debug, - "💸 validate unsigned pre dispatch checks failed due to error #{:?}.", - invalid, - ); - return invalid.into(); - } - - log!(debug, "validateUnsigned succeeded for a solution at era {}.", era); - - ValidTransaction::with_tag_prefix("StakingOffchain") - // The higher the score[0], the better a solution is. - .priority(T::UnsignedPriority::get().saturating_add(score[0].saturated_into())) - // Defensive only. A single solution can exist in the pool per era. Each validator - // will run OCW at most once per era, hence there should never exist more than one - // transaction anyhow. - .and_provides(era) - // Note: this can be more accurate in the future. We do something like - // `era_end_block - current_block` but that is not needed now as we eagerly run - // offchain workers now and the above should be same as `T::ElectionLookahead` - // without the need to query more storage in the validation phase. If we randomize - // offchain worker, then we might re-consider this. - .longevity(TryInto::::try_into( - T::ElectionLookahead::get()).unwrap_or(DEFAULT_LONGEVITY) - ) - // We don't propagate this. This can never the validated at a remote node. - .propagate(false) - .build() - } else { - InvalidTransaction::Call.into() - } - } - - fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> { - if let Call::submit_election_solution_unsigned( - _, - _, - score, - era, - _, - ) = call { - // IMPORTANT NOTE: These checks are performed in the dispatch call itself, yet we need - // to duplicate them here to prevent a block producer from putting a previously - // validated, yet no longer valid solution on chain. - // OPTIMISATION NOTE: we could skip this in the `submit_election_solution_unsigned` - // since we already do it here. The signed version needs it though. Yer for now we keep - // this duplicate check here so both signed and unsigned can use a singular - // `check_and_replace_solution`. - Self::pre_dispatch_checks(*score, *era) - .map(|_| ()) - .map_err(to_invalid) - .map_err(Into::into) - } else { - Err(InvalidTransaction::Call.into()) - } - } -} - /// Check that list is sorted and has no duplicates. fn is_sorted_and_unique(list: &[u32]) -> bool { list.windows(2).all(|w| w[0] < w[1]) } - -/// convert a DispatchErrorWithPostInfo to a custom InvalidTransaction with the inner code being the -/// error number. -fn to_invalid(error_with_post_info: DispatchErrorWithPostInfo) -> InvalidTransaction { - let error = error_with_post_info.error; - let error_number = match error { - DispatchError::Module { error, ..} => error, - _ => 0, - }; - InvalidTransaction::Custom(error_number) -} diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 68612c8f96fdb..b4c84059a2106 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -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}, Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Staking: staking::{Pallet, Call, Config, Storage, Event, ValidateUnsigned}, + Staking: staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, } ); @@ -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; 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; 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, ElectionScore) { - let mut backing_stake_of: BTreeMap = BTreeMap::new(); - - // self stake - >::iter().for_each(|(who, _p)| { - *backing_stake_of.entry(who).or_insert(Zero::zero()) += Staking::slashable_balance_of(&who) - }); - - // add nominator stuff - >::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 = backing_stake_of.keys().cloned().collect(); - sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); - let winners: Vec = sorted - .iter() - .cloned() - .take(Staking::validator_count() as usize) - .collect(); - - // create assignments - let mut staked_assignment: Vec> = Vec::new(); - >::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::(&winners, &staked_assignment).unwrap(); - let score = support.evaluate(); - - assert!(sp_npos_elections::is_score_better::( - 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 { - snapshot_nominators.iter().position(|x| x == a).map(|i| i as NominatorIndex) - }; - let validator_index = |a: &AccountId| -> Option { - 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::(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::>(); - - (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>), -) -> (CompactAssignments, Vec, ElectionScore) { - // run election on the default stuff. - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(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 { - 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 { - 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::>(); - - (compact, winners, score) -} - /// Make all validator and nominator request their payment pub(crate) fn make_all_reward_payment(era: EraIndex) { let validators_with_reward = diff --git a/frame/staking/src/offchain_election.rs b/frame/staking/src/offchain_election.rs deleted file mode 100644 index 8fe3fc7367d93..0000000000000 --- a/frame/staking/src/offchain_election.rs +++ /dev/null @@ -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 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( - 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>| { - 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() -> Result<(), OffchainElectionError> { - let iters = get_balancing_iters::(); - // compute raw solution. Note that we use `OffchainAccuracy`. - let ElectionResult { - winners, - assignments, - } = >::do_phragmen::(iters) - .ok_or(OffchainElectionError::ElectionFailed)?; - - // process and prepare it for submission. - let (winners, compact, score, size) = prepare_submission::( - 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 = >::current_era().unwrap_or_default(); - - // send it. - let call = Call::submit_election_solution_unsigned( - winners, - compact, - score, - current_era, - size, - ).into(); - - SubmitTransaction::>::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() -> usize { - match T::MaxIterations::get() { - 0 => 0, - max @ _ => { - let seed = sp_io::offchain::random_seed(); - let random = ::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( - 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 { - 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( - maximum_allowed_voters: u32, - mut compact: CompactAssignments, - nominator_index: FN, -) -> Result -where - for<'r> FN: Fn(&'r T::AccountId) -> Option, -{ - 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 = >::slashable_balance_of_fn(); - let mut voters_sorted = >::iter() - .map(|(who, _)| (who.clone(), balance_of(&who))) - .collect::>(); - 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( - assignments: Vec>, - winners: Vec<(T::AccountId, ExtendedBalance)>, - do_reduce: bool, - maximum_weight: Weight, -) -> Result< - (Vec, CompactAssignments, ElectionScore, ElectionSize), - OffchainElectionError, -> { - // make sure that the snapshot is available. - let snapshot_validators = - >::snapshot_validators().ok_or(OffchainElectionError::SnapshotUnavailable)?; - let snapshot_nominators = - >::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 { - nominator_indices - .get(a) - .and_then(|i| >::try_into(*i).ok()) - }; - let validator_index = |a: &T::AccountId| -> Option { - validator_indices - .get(a) - .and_then(|i| >::try_into(*i).ok()) - }; - let nominator_at = |i: NominatorIndex| -> Option { - snapshot_nominators.get(i as usize).cloned() - }; - - let validator_at = |i: ValidatorIndex| -> Option { - 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, - >::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::(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::(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(), - >::slashable_balance_of_fn(), - ); - - let support_map = to_supports::(&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 = 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::(0, size, 0), 0); - assert_eq!(maximum_compact_len::(0, size, 1), 0); - assert_eq!(maximum_compact_len::(0, size, 999), 0); - assert_eq!(maximum_compact_len::(0, size, 1000), 1); - assert_eq!(maximum_compact_len::(0, size, 1001), 1); - assert_eq!(maximum_compact_len::(0, size, 1990), 1); - assert_eq!(maximum_compact_len::(0, size, 1999), 1); - assert_eq!(maximum_compact_len::(0, size, 2000), 2); - assert_eq!(maximum_compact_len::(0, size, 2001), 2); - assert_eq!(maximum_compact_len::(0, size, 2010), 2); - assert_eq!(maximum_compact_len::(0, size, 2990), 2); - assert_eq!(maximum_compact_len::(0, size, 2999), 2); - assert_eq!(maximum_compact_len::(0, size, 3000), 3); - assert_eq!(maximum_compact_len::(0, size, 3333), 3); - assert_eq!(maximum_compact_len::(0, size, 5500), 5); - assert_eq!(maximum_compact_len::(0, size, 7777), 7); - assert_eq!(maximum_compact_len::(0, size, 9999), 9); - assert_eq!(maximum_compact_len::(0, size, 10_000), 10); - assert_eq!(maximum_compact_len::(0, size, 10_999), 10); - assert_eq!(maximum_compact_len::(0, size, 11_000), 10); - assert_eq!(maximum_compact_len::(0, size, 22_000), 10); - - let size = ElectionSize { - validators: 0, - nominators: 1, - }; - - assert_eq!(maximum_compact_len::(0, size, 0), 0); - assert_eq!(maximum_compact_len::(0, size, 1), 0); - assert_eq!(maximum_compact_len::(0, size, 999), 0); - assert_eq!(maximum_compact_len::(0, size, 1000), 1); - assert_eq!(maximum_compact_len::(0, size, 1001), 1); - assert_eq!(maximum_compact_len::(0, size, 1990), 1); - assert_eq!(maximum_compact_len::(0, size, 1999), 1); - assert_eq!(maximum_compact_len::(0, size, 2000), 1); - assert_eq!(maximum_compact_len::(0, size, 2001), 1); - assert_eq!(maximum_compact_len::(0, size, 2010), 1); - assert_eq!(maximum_compact_len::(0, size, 3333), 1); - - let size = ElectionSize { - validators: 0, - nominators: 2, - }; - - assert_eq!(maximum_compact_len::(0, size, 0), 0); - assert_eq!(maximum_compact_len::(0, size, 1), 0); - assert_eq!(maximum_compact_len::(0, size, 999), 0); - assert_eq!(maximum_compact_len::(0, size, 1000), 1); - assert_eq!(maximum_compact_len::(0, size, 1001), 1); - assert_eq!(maximum_compact_len::(0, size, 1999), 1); - assert_eq!(maximum_compact_len::(0, size, 2000), 2); - assert_eq!(maximum_compact_len::(0, size, 2001), 2); - assert_eq!(maximum_compact_len::(0, size, 2010), 2); - assert_eq!(maximum_compact_len::(0, size, 3333), 2); - } -} diff --git a/frame/staking/src/testing_utils.rs b/frame/staking/src/testing_utils.rs index afe36f55b1dcf..c4daf88098e75 100644 --- a/frame/staking/src/testing_utils.rs +++ b/frame/staking/src/testing_utils.rs @@ -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( } 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( )?; // Have them randomly validate - let mut available_validators = validator_choosen.clone(); + let mut available_validators = validator_chosen.clone(); let mut selected_validators: Vec<::Source> = Vec::with_capacity(edge_per_nominator); @@ -169,227 +168,10 @@ pub fn create_validators_with_nominators_for_era( 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( - do_reduce: bool, -) -> (Vec, CompactAssignments, ElectionScore, ElectionSize) { - let mut backing_stake_of: BTreeMap> = BTreeMap::new(); - - // self stake - >::iter().for_each(|(who, _p)| { - *backing_stake_of.entry(who.clone()).or_insert_with(|| Zero::zero()) += - >::slashable_balance_of(&who) - }); - - // elect winners. We chose the.. least backed ones. - let mut sorted: Vec = backing_stake_of.keys().cloned().collect(); - sorted.sort_by_key(|x| backing_stake_of.get(x).unwrap()); - let winners: Vec = sorted - .iter() - .rev() - .cloned() - .take(>::validator_count() as usize) - .collect(); - - let mut staked_assignments: Vec> = 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(), - >::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 = >::snapshot_validators().unwrap(); - let snapshot_nominators = >::snapshot_nominators().unwrap(); - - let nominator_index = |a: &T::AccountId| -> Option { - snapshot_nominators - .iter() - .position(|x| x == a) - .and_then(|i| >::try_into(i).ok()) - }; - let validator_index = |a: &T::AccountId| -> Option { - snapshot_validators - .iter() - .position(|x| x == a) - .and_then(|i| >::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(), - >::slashable_balance_of_fn(), - ); - - let support_map = - to_supports::(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::>(); - - 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( - do_reduce: bool, -) -> ( - Vec, - CompactAssignments, - ElectionScore, - ElectionSize, -) { - let iters = offchain_election::get_balancing_iters::(); - - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = >::do_phragmen::(iters).unwrap(); - - offchain_election::prepare_submission::( - 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( - winner: T::AccountId, -) -> Result< - ( - Vec, - CompactAssignments, - ElectionScore, - ElectionSize, - ), - &'static str, -> { - let snapshot_validators = >::snapshot_validators().unwrap(); - let snapshot_nominators = >::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 = >::slashable_balance_of(&winner); - let stake = - ::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() -> EraIndex { >::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( - num_assignments: u32, - winners: Vec<::Source>, -) -> Result< - ( - Vec<(T::AccountId, ExtendedBalance)>, - Vec>, - ), - &'static str -> { - let ratio = OffchainAccuracy::from_rational(1, MAX_NOMINATIONS); - let assignments: Vec> = >::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| { - (::lookup(v).unwrap(), 0) - }).collect(); - - Ok((winners, assignments)) -} diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 43ce2259fac7d..df3456bf29926 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -25,10 +25,11 @@ use sp_runtime::{ use sp_staking::offence::OffenceDetails; use frame_support::{ assert_ok, assert_noop, StorageMap, - traits::{Currency, ReservableCurrency, OnInitialize, OnFinalize}, + traits::{Currency, ReservableCurrency, OnInitialize}, }; use pallet_balances::Error as BalancesError; use substrate_test_utils::assert_eq_uvec; +use frame_election_provider_support::Support; #[test] fn force_unstake_works() { @@ -1806,7 +1807,7 @@ fn bond_with_little_staked_value_bounded() { } #[test] -fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { +fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { ExtBuilder::default() .validator_count(2) .nominate(false) @@ -1817,43 +1818,43 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election() { assert_ok!(Staking::chill(Origin::signed(100))); // make stakes equal. assert_ok!(Staking::bond_extra(Origin::signed(31), 999)); - + // ensure all have equal stake. assert_eq!( >::iter() .map(|(v, _)| (v, Staking::ledger(v - 1).unwrap().total)) .collect::>(), vec![(31, 1000), (21, 1000), (11, 1000)], ); + // no nominators shall exist. assert!(>::iter().map(|(n, _)| n).collect::>().is_empty()); - // give the man some money + // give the man some money. let initial_balance = 1000; - for i in [1, 2, 3, 4,].iter() { + for i in [1, 2, 3, 4].iter() { let _ = Balances::make_free_balance_be(i, initial_balance); } assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - // 11 should not be elected. All of these count as ONE vote. - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31,])); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31])); assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); - // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(0).unwrap(); - let winners = sp_npos_elections::to_without_backing(winners); - - assert_eq!(winners, vec![31, 21]); - // only distribution to 21 and 31. - assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + // winners should be 21 and 31. Otherwise this election is taking duplicates into + // account. + let supports = ::ElectionProvider::elect().unwrap().0; + assert_eq!( + supports, + vec![ + (21, Support { total: 1800, voters: vec![(21, 1000), (3, 400), (1, 400)] }), + (31, Support { total: 2200, voters: vec![(31, 1000), (3, 600), (1, 600)] }) + ], + ); }); } #[test] -fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { +fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { // same as above but ensures that even when the duple is being elected, everything is sane. ExtBuilder::default() .validator_count(2) @@ -1863,39 +1864,39 @@ fn bond_with_duplicate_vote_should_be_ignored_by_npos_election_elected() { .execute_with(|| { // disable the nominator assert_ok!(Staking::chill(Origin::signed(100))); - // make stakes equal. + // 31/30 will have less stake assert_ok!(Staking::bond_extra(Origin::signed(31), 99)); - + // ensure all have equal stake. assert_eq!( >::iter() .map(|(v, _)| (v, Staking::ledger(v - 1).unwrap().total)) .collect::>(), vec![(31, 100), (21, 1000), (11, 1000)], ); + // no nominators shall exist. assert!(>::iter().map(|(n, _)| n).collect::>().is_empty()); - // give the man some money + // give the man some money. let initial_balance = 1000; for i in [1, 2, 3, 4,].iter() { let _ = Balances::make_free_balance_be(i, initial_balance); } assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31,])); + assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31])); assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); - // winners should be 21 and 31. Otherwise this election is taking duplicates into account. - let sp_npos_elections::ElectionResult { - winners, - assignments, - } = Staking::do_phragmen::(0).unwrap(); - - let winners = sp_npos_elections::to_without_backing(winners); - assert_eq!(winners, vec![21, 11]); - // only distribution to 21 and 31. - assert_eq!(assignments.iter().find(|a| a.who == 1).unwrap().distribution.len(), 2); + // winners should be 21 and 11. + let supports = ::ElectionProvider::elect().unwrap().0; + assert_eq!( + supports, + vec![ + (11, Support { total: 1500, voters: vec![(11, 1000), (1, 500)] }), + (21, Support { total: 2500, voters: vec![(21, 1000), (3, 1000), (1, 500)] }) + ], + ); }); } @@ -2905,1298 +2906,6 @@ fn remove_multi_deferred() { }) } -mod offchain_election { - use crate::*; - use codec::Encode; - use frame_support::{ - assert_noop, assert_ok, assert_err_with_weight, - dispatch::DispatchResultWithPostInfo, - }; - use sp_runtime::transaction_validity::TransactionSource; - use mock::*; - use parking_lot::RwLock; - use sp_core::offchain::{ - testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, - OffchainWorkerExt, TransactionPoolExt, OffchainDbExt, - }; - use sp_io::TestExternalities; - use sp_npos_elections::StakedAssignment; - use frame_support::traits::OffchainWorker; - use std::sync::Arc; - use substrate_test_utils::assert_eq_uvec; - - fn percent(x: u16) -> OffchainAccuracy { - OffchainAccuracy::from_percent(x) - } - - /// setup a new set of validators and nominator storage items independent of the parent mock - /// file. This produces a edge graph that can be reduced. - pub fn build_offchain_election_test_ext() { - for i in (10..=40).step_by(10) { - // Note: we respect the convention of the mock (10, 11 pairs etc.) since these accounts - // have corresponding keys in session which makes everything more ergonomic and - // realistic. - bond_validator(i + 1, i, 100); - } - - let mut voter = 1; - bond_nominator(voter, 1000 + voter, 100, vec![11]); - voter = 2; - bond_nominator(voter, 1000 + voter, 100, vec![11, 11]); - voter = 3; - bond_nominator(voter, 1000 + voter, 100, vec![21, 41]); - voter = 4; - bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); - voter = 5; - bond_nominator(voter, 1000 + voter, 100, vec![21, 31, 41]); - } - - /// convert an externalities to one that can handle offchain worker tests. - fn offchainify(ext: &mut TestExternalities, iterations: u32) -> Arc> { - let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, pool_state) = TestTransactionPoolExt::new(); - - let mut seed = [0_u8; 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.register_extension(TransactionPoolExt::new(pool)); - - pool_state - } - - fn election_size() -> ElectionSize { - ElectionSize { - validators: Staking::snapshot_validators().unwrap().len() as ValidatorIndex, - nominators: Staking::snapshot_nominators().unwrap().len() as NominatorIndex, - } - } - - fn submit_solution( - origin: Origin, - winners: Vec, - compact: CompactAssignments, - score: ElectionScore, - ) -> DispatchResultWithPostInfo { - Staking::submit_election_solution( - origin, - winners, - compact, - score, - current_era(), - election_size(), - ) - } - - #[test] - fn is_current_session_final_works() { - ExtBuilder::default() - .session_per_era(3) - .build() - .execute_with(|| { - mock::start_active_era(1); - assert_eq!(Session::current_index(), 3); - assert_eq!(Staking::current_era(), Some(1)); - assert_eq!(Staking::is_current_session_final(), false); - - start_session(4); - assert_eq!(Session::current_index(), 4); - assert_eq!(Staking::current_era(), Some(1)); - assert_eq!(Staking::is_current_session_final(), true); - - start_session(5); - assert_eq!(Session::current_index(), 5); - // era changed. - assert_eq!(Staking::current_era(), Some(2)); - assert_eq!(Staking::is_current_session_final(), false); - }) - } - - #[test] - fn offchain_window_is_triggered() { - ExtBuilder::default() - .session_per_era(5) - .period(10) - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(7); - assert_session_era!(0, 0); - - run_to_block(10); - assert_session_era!(1, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - run_to_block(36); - assert_session_era!(3, 0); - - // fist era has session 0, which has 0 blocks length, so we have in total 40 blocks - // in the era. - run_to_block(37); - assert_session_era!(3, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - assert!(Staking::snapshot_nominators().is_some()); - assert!(Staking::snapshot_validators().is_some()); - - run_to_block(38); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - - run_to_block(39); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - - run_to_block(40); - assert_session_era!(4, 1); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - run_to_block(86); - assert_session_era!(8, 1); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - - // second era onwards has 50 blocks per era. - run_to_block(87); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(87)); - assert!(Staking::snapshot_nominators().is_some()); - assert!(Staking::snapshot_validators().is_some()); - - run_to_block(90); - assert_session_era!(9, 2); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(Staking::snapshot_nominators().is_none()); - assert!(Staking::snapshot_validators().is_none()); - }) - } - - #[test] - fn offchain_window_is_triggered_when_forcing() { - ExtBuilder::default() - .session_per_era(5) - .period(10) - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(12); - ForceEra::put(Forcing::ForceNew); - run_to_block(13); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(17); // instead of 47 - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); - - run_to_block(20); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - }) - } - - #[test] - fn offchain_window_is_triggered_when_force_always() { - ExtBuilder::default() - .session_per_era(5) - .period(10) - .election_lookahead(3) - .build() - .execute_with(|| { - ForceEra::put(Forcing::ForceAlways); - run_to_block(16); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(17); // instead of 37 - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(17)); - - run_to_block(20); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(26); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - run_to_block(27); // next one again - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(27)); - }) - } - - #[test] - fn offchain_window_closes_when_forcenone() { - ExtBuilder::default() - .session_per_era(5) - .period(10) - .election_lookahead(3) - .build() - .execute_with(|| { - ForceEra::put(Forcing::ForceNone); - - run_to_block(36); - assert_session_era!(3, 0); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // opens - run_to_block(37); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(37)); - assert!(Staking::is_current_session_final()); - assert!(Staking::snapshot_validators().is_some()); - - // closes normally - run_to_block(40); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert!(!Staking::is_current_session_final()); - assert!(Staking::snapshot_validators().is_none()); - assert_session_era!(4, 0); - - run_to_block(47); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(4, 0); - - run_to_block(57); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(5, 0); - - run_to_block(67); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // Will not open again as scheduled - run_to_block(87); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(8, 0); - - run_to_block(90); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - assert_session_era!(9, 0); - }) - } - - #[test] - fn offchain_window_on_chain_fallback_works() { - ExtBuilder::default().build_and_execute(|| { - start_session(1); - start_session(2); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - // some election must have happened by now. - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let mock::Event::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::OnChain), - ); - }) - } - - #[test] - #[ignore] - fn offchain_wont_work_if_snapshot_fails() { - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - assert!(Staking::snapshot_validators().is_some()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - // validate more than the limit - let limit: NominatorIndex = ValidatorIndex::max_value() as NominatorIndex + 1; - let ctrl = 1_000_000; - for i in 0..limit { - bond_validator((1000 + i).into(), (1000 + i + ctrl).into(), 100); - } - - // window stays closed since no snapshot was taken. - run_to_block(27); - assert!(Staking::snapshot_validators().is_none()); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - }) - } - - #[test] - fn staking_is_locked_when_election_window_open() { - ExtBuilder::default() - .offchain_election_ext() - .election_lookahead(3) - .build() - .execute_with(|| { - run_to_block(12); - assert!(Staking::snapshot_validators().is_some()); - // given - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - // chill et. al. are now not allowed. - assert_noop!( - Staking::chill(Origin::signed(10)), - Error::::CallNotAllowed, - ); - }) - } - - #[test] - fn signed_result_can_be_submitted() { - // should check that we have a new validator set normally, event says that it comes from - // offchain. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - assert!(Staking::snapshot_validators().is_some()); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - let queued_result = Staking::queued_elected().unwrap(); - assert_eq!(queued_result.compute, ElectionCompute::Signed); - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let mock::Event::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::SolutionStored(ElectionCompute::Signed), - ); - - run_to_block(15); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let mock::Event::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::Signed), - ); - }) - } - - #[test] - fn signed_result_can_be_submitted_later() { - // same as `signed_result_can_be_submitted` but at a later block. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(14); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution(Origin::signed(10), winners, compact, score)); - - let queued_result = Staking::queued_elected().unwrap(); - assert_eq!(queued_result.compute, ElectionCompute::Signed); - - run_to_block(15); - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - assert_eq!( - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| { - if let mock::Event::staking(inner) = e { - Some(inner) - } else { - None - } - }) - .last() - .unwrap(), - RawEvent::StakingElection(ElectionCompute::Signed), - ); - }) - } - - #[test] - fn early_solution_submission_is_rejected() { - // should check that we have a new validator set normally, event says that it comes from - // offchain. - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(11); - // submission is not yet allowed - assert_eq!(Staking::era_election_status(), ElectionStatus::Closed); - - // create all the indices just to build the solution. - Staking::create_stakers_snapshot(); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - Staking::kill_stakers_snapshot(); - - assert_err_with_weight!( - Staking::submit_election_solution( - Origin::signed(10), - winners.clone(), - compact.clone(), - score, - current_era(), - ElectionSize::default(), - ), - Error::::OffchainElectionEarlySubmission, - Some(::DbWeight::get().reads(1)), - ); - }) - } - - #[test] - fn weak_solution_is_rejected() { - // A solution which is weaker than what we currently have on-chain is rejected. - ExtBuilder::default() - .offchain_election_ext() - .has_stakers(false) - .validator_count(4) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // a good solution - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a bad solution - let (compact, winners, score) = horrible_npos_solution(false); - assert_err_with_weight!( - submit_solution( - Origin::signed(10), - winners.clone(), - compact.clone(), - score, - ), - Error::::OffchainElectionWeakSubmission, - Some(::DbWeight::get().reads(3)) - ); - }) - } - - #[test] - fn better_solution_is_accepted() { - // A solution which is better than what we currently have on-chain is accepted. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // a meeeeh solution - let (compact, winners, score) = horrible_npos_solution(false); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a better solution - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - }) - } - - #[test] - fn offchain_worker_runs_when_window_open() { - // at the end of the first finalized block with ElectionStatus::open(_), it should execute. - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .build(); - let state = offchainify(&mut ext, 0); - ext.execute_with(|| { - run_to_block(12); - - // local key 11 is in the elected set. - assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(state.read().transactions.len(), 0); - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - _ => unreachable!(), - }; - - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Ok(ValidTransaction { - priority: UnsignedPriority::get() + 1125, // the proposed slot stake. - requires: vec![], - provides: vec![("StakingOffchain", current_era()).encode()], - longevity: 3, - propagate: false, - }) - ) - }) - } - - #[test] - fn offchain_worker_runs_with_balancing() { - // Offchain worker balances based on the number provided by randomness. See the difference - // in the priority, which comes from the computed score. - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .max_offchain_iterations(2) - .build(); - let state = offchainify(&mut ext, 2); - ext.execute_with(|| { - run_to_block(12); - - // local key 11 is in the elected set. - assert_eq_uvec!(Session::validators(), vec![11, 21]); - assert_eq!(state.read().transactions.len(), 0); - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - _ => unreachable!(), - }; - - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Ok(ValidTransaction { - // the proposed slot stake, with balance_solution. - priority: UnsignedPriority::get() + 1250, - requires: vec![], - provides: vec![("StakingOffchain", active_era()).encode()], - longevity: 3, - propagate: false, - }) - ) - }) - } - - #[test] - fn mediocre_submission_from_authority_is_early_rejected() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let state = offchainify(&mut ext, 0); - ext.execute_with(|| { - run_to_block(12); - // put a good solution on-chain - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - ),); - - // now run the offchain worker in the same chain state. - Staking::offchain_worker(12); - assert_eq!(state.read().transactions.len(), 1); - - let encoded = state.read().transactions[0].clone(); - let extrinsic: Extrinsic = Decode::decode(&mut &*encoded).unwrap(); - - let call = extrinsic.call; - let inner = match call { - mock::Call::Staking(inner) => inner, - _ => unreachable!(), - }; - - // pass this call to ValidateUnsigned - assert_eq!( - ::validate_unsigned( - TransactionSource::Local, - &inner, - ), - TransactionValidity::Err( - InvalidTransaction::Custom(>::OffchainElectionWeakSubmission.as_u8()).into(), - ), - ) - }) - } - - #[test] - fn invalid_election_correct_number_of_winners() { - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - ValidatorCount::put(3); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - ValidatorCount::put(4); - - assert_eq!(winners.len(), 3); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_solution_size() { - ExtBuilder::default() - .offchain_election_ext() - .build() - .execute_with(|| { - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - assert_noop!( - Staking::submit_election_solution( - Origin::signed(10), - winners, - compact, - score, - current_era(), - ElectionSize::default(), - ), - Error::::OffchainElectionBogusElectionSize, - ); - }) - } - - #[test] - fn invalid_election_correct_number_of_winners_1() { - // if we have too little validators, then the number of candidates is the bound. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(8) // we simply cannot elect 8 - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - ValidatorCount::put(3); - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - ValidatorCount::put(4); - - assert_eq!(winners.len(), 3); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_correct_number_of_winners_2() { - // if we have too little validators, then the number of candidates is the bound. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(8) // we simply cannot elect 8 - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - assert_eq!(winners.len(), 4); - - // all good. We chose 4 and it works. - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - ),); - }) - } - - #[test] - fn invalid_election_out_of_bound_nominator_index() { - // A nominator index which is simply invalid - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 9 doesn't exist. - compact.votes1.push((9, 2)); - - // The error type sadly cannot be more specific now. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_out_of_bound_validator_index() { - // A validator index which is out of bound - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (mut compact, winners, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 4 doesn't exist. - compact.votes1.iter_mut().for_each(|(_, vidx)| if *vidx == 1 { *vidx = 4 }); - - // The error type sadly cannot be more specific now. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_out_of_bound_winner_index() { - // A winner index which is simply invalid - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (compact, _, score) = prepare_submission_with(true, true, 2, |_| {}); - - // index 4 doesn't exist. - let winners = vec![0, 1, 2, 4]; - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinner, - ); - }) - } - - #[test] - fn invalid_election_non_winner_validator_index() { - // An edge that points to a correct validator index who is NOT a winner. This is very - // similar to the test that raises `OffchainElectionBogusNomination`. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) // we select only 2. - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { - // swap all 11 and 41s in the distribution with non-winners. Note that it is - // important that the count of winners and the count of unique targets remain - // valid. - a.iter_mut().for_each(| StakedAssignment { who, distribution } | - distribution.iter_mut().for_each(|(t, _)| { - if *t == 41 { *t = 31 } else { *t = 21 } - // if it is self vote, correct that. - if *who == 41 { *who = 31 } - if *who == 11 { *who = 21 } - }) - ); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusNomination, - ); - }) - } - - #[test] - fn offchain_election_unique_target_count_is_checked() { - // Number of unique targets and and winners.len must match. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(2) // we select only 2. - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - assert_eq!(Staking::snapshot_nominators().unwrap().len(), 5 + 4); - assert_eq!(Staking::snapshot_validators().unwrap().len(), 4); - - let (compact, winners, score) = prepare_submission_with(false, true, 2, |a| { - a.iter_mut() - .find(|x| x.who == 5) - // just add any new target. - .map(|x| { - // old value. - assert_eq!(x.distribution, vec![(41, 100)]); - // new value. - x.distribution = vec![(21, 50), (41, 50)] - }); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusWinnerCount, - ); - }) - } - - #[test] - fn invalid_election_wrong_self_vote() { - // A self vote for someone else. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { - // mutate a self vote to target someone else. That someone else is still among the - // winners - a.iter_mut().find(|x| x.who == 11).map(|x| { - x.distribution - .iter_mut() - .find(|y| y.0 == 11) - .map(|y| y.0 = 21) - }); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusSelfVote, - ); - }) - } - - #[test] - fn invalid_election_wrong_self_vote_2() { - // A self validator voting for someone else next to self vote. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, true, 2, |a| { - // Remove the self vote. - a.retain(|x| x.who != 11); - // add is as a new double vote - a.push(StakedAssignment { - who: 11, - distribution: vec![(11, 50), (21, 50)], - }); - }); - - // This raises score issue. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusSelfVote, - ); - }) - } - - #[test] - fn invalid_election_over_stake() { - // Someone's edge ratios sums to more than 100%. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - // Note: we don't reduce here to be able to tweak votes3. votes3 will vanish if you - // reduce. - let (mut compact, winners, score) = prepare_submission_with(true, false, 0, |_| {}); - - if let Some(c) = compact.votes3.iter_mut().find(|x| x.0 == 0) { - // by default it should have been (0, [(2, 33%), (1, 33%)], 0) - // now the sum is above 100% - c.1 = [(2, percent(66)), (1, percent(66))]; - } - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusCompact, - ); - }) - } - - #[test] - fn invalid_election_under_stake() { - // at the time of this writing, we cannot under stake someone. The compact assignment works - // in a way that some of the stakes are presented by the submitter, and the last one is read - // from chain by subtracting the rest from total. Hence, the sum is always correct. - // This test is only here as a demonstration. - } - - #[test] - fn invalid_election_invalid_target_stealing() { - // A valid voter who voted for someone who is a candidate, and is a correct winner, but is - // actually NOT nominated by this nominator. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // 3 only voted for 20 and 40. We add a fake vote to 30. The stake sum is still - // correctly 100. - a.iter_mut() - .find(|x| x.who == 3) - .map(|x| x.distribution = vec![(21, 50), (41, 30), (31, 20)]); - }); - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusNomination, - ); - }) - } - - #[test] - fn nomination_slash_filter_is_checked() { - // If a nominator has voted for someone who has been recently slashed, that particular - // nomination should be disabled for the upcoming election. A solution must respect this - // rule. - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - - // finalize the round with fallback. This is needed since all nominator submission - // are in era zero and we want this one to pass with no problems. - run_to_block(15); - - // go to the next session to trigger mock::start_era and bump the active era - run_to_block(20); - - // slash 10. This must happen outside of the election window. - let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 11); - on_offence_now( - &[OffenceDetails { - offender: (11, offender_expo.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(50)], - ); - - // validate 10 again for the next round. But this guy will not have the votes that - // it should have had from 1 and 2. - assert_ok!(Staking::validate( - Origin::signed(10), - Default::default() - )); - - // open the election window and create snapshots. - run_to_block(32); - - // a solution that has been prepared after the slash. - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // no one is allowed to vote for 10, except for itself. - a.into_iter() - .filter(|s| s.who != 11) - .for_each(|s| - assert!(s.distribution.iter().find(|(t, _)| *t == 11).is_none()) - ); - }); - - // can be submitted. - assert_ok!(submit_solution( - Origin::signed(10), - winners, - compact, - score, - )); - - // a wrong solution. - let (compact, winners, score) = prepare_submission_with(true, false, 0, |a| { - // add back the vote that has been filtered out. - a.push(StakedAssignment { - who: 1, - distribution: vec![(11, 100)] - }); - }); - - // is rejected. - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionSlashedNomination, - ); - }) - } - - #[test] - fn invalid_election_wrong_score() { - // A valid voter who's total distributed stake is more than what they bond - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - build_offchain_election_test_ext(); - run_to_block(12); - - let (compact, winners, mut score) = prepare_submission_with(true, true, 2, |_| {}); - score[0] += 1; - - assert_noop!( - submit_solution( - Origin::signed(10), - winners, - compact, - score, - ), - Error::::OffchainElectionBogusScore, - ); - }) - } - - #[test] - fn offchain_storage_is_set() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let state = offchainify(&mut ext, 0); - - ext.execute_with(|| { - use offchain_election::OFFCHAIN_HEAD_DB; - use sp_runtime::offchain::storage::StorageValueRef; - - run_to_block(12); - - Staking::offchain_worker(12); - // it works - assert_eq!(state.read().transactions.len(), 1); - - // and it is set - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - assert_eq!(storage.get::().unwrap().unwrap(), 12); - }) - } - - #[test] - fn offchain_storage_prevents_duplicate() { - let mut ext = ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .build(); - let _ = offchainify(&mut ext, 0); - - ext.execute_with(|| { - use offchain_election::OFFCHAIN_HEAD_DB; - use sp_runtime::offchain::storage::StorageValueRef; - let storage = StorageValueRef::persistent(&OFFCHAIN_HEAD_DB); - - run_to_block(12); - - // first run -- ok - assert_eq!( - offchain_election::set_check_offchain_execution_status::(12), - Ok(()), - ); - assert_eq!(storage.get::().unwrap().unwrap(), 12); - - // re-execute after the next. not allowed. - assert_eq!( - offchain_election::set_check_offchain_execution_status::(13), - Err("recently executed."), - ); - - // a fork like situation -- re-execute 10, 11, 12. But it won't go through. - assert_eq!( - offchain_election::set_check_offchain_execution_status::(10), - Err("fork."), - ); - assert_eq!( - offchain_election::set_check_offchain_execution_status::(11), - Err("fork."), - ); - assert_eq!( - offchain_election::set_check_offchain_execution_status::(12), - Err("recently executed."), - ); - }) - } - - #[test] - #[should_panic] - fn offence_is_blocked_when_window_open() { - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - run_to_block(12); - assert_eq!(Staking::era_election_status(), ElectionStatus::Open(12)); - - let offender_expo = Staking::eras_stakers(Staking::active_era().unwrap().index, 10); - - // panic from the impl in mock - on_offence_now( - &[OffenceDetails { - offender: (10, offender_expo.clone()), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); - }) - } -} - #[test] fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_validator() { ExtBuilder::default().build_and_execute(|| { @@ -4704,39 +3413,6 @@ fn offences_weight_calculated_correctly() { }); } -#[test] -fn on_initialize_weight_is_correct() { - ExtBuilder::default().has_stakers(false).build_and_execute(|| { - assert_eq!(Validators::::iter().count(), 0); - assert_eq!(Nominators::::iter().count(), 0); - // When this pallet has nothing, we do 4 reads each block - let base_weight = ::DbWeight::get().reads(4); - assert_eq!(base_weight, Staking::on_initialize(0)); - }); - - ExtBuilder::default() - .offchain_election_ext() - .validator_count(4) - .has_stakers(false) - .build() - .execute_with(|| { - crate::tests::offchain_election::build_offchain_election_test_ext(); - run_to_block(11); - Staking::on_finalize(System::block_number()); - System::set_block_number((System::block_number() + 1).into()); - Timestamp::set_timestamp(System::block_number() * 1000 + INIT_TIMESTAMP); - Session::on_initialize(System::block_number()); - - assert_eq!(Validators::::iter().count(), 4); - assert_eq!(Nominators::::iter().count(), 5); - // With 4 validators and 5 nominator, we should increase weight by: - // - (4 + 5) reads - // - 3 Writes - let final_weight = ::DbWeight::get().reads_writes(4 + 9, 3); - assert_eq!(final_weight, Staking::on_initialize(System::block_number())); - }); -} - #[test] fn payout_creates_controller() { ExtBuilder::default().has_stakers(false).build_and_execute(|| { @@ -5021,6 +3697,39 @@ mod election_data_provider { use super::*; use frame_election_provider_support::ElectionDataProvider; + #[test] + fn targets_2sec_block() { + let mut validators = 1000; + while ::WeightInfo::get_npos_targets(validators) + < 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + { + validators += 1; + } + + println!("Can create a snapshot of {} validators in 2sec block", validators); + } + + #[test] + fn voters_2sec_block() { + // we assume a network only wants up to 1000 validators in most cases, thus having 2000 + // candidates is as high as it gets. + let validators = 2000; + // we assume the worse case: each validator also has a slashing span. + let slashing_spans = validators; + let mut nominators = 1000; + + while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) + < 2 * frame_support::weights::constants::WEIGHT_PER_SECOND + { + nominators += 1; + } + + println!( + "Can create a snapshot of {} nominators [{} validators, each 1 slashing] in 2sec block", + nominators, validators + ); + } + #[test] fn voters_include_self_vote() { ExtBuilder::default().nominate(false).build().execute_with(|| { @@ -5102,7 +3811,7 @@ mod election_data_provider { assert_eq!(staking_events().len(), 1); assert_eq!( *staking_events().last().unwrap(), - RawEvent::StakingElection(ElectionCompute::OnChain) + RawEvent::StakingElection ); for b in 21..45 { @@ -5116,7 +3825,7 @@ mod election_data_provider { assert_eq!(staking_events().len(), 3); assert_eq!( *staking_events().last().unwrap(), - RawEvent::StakingElection(ElectionCompute::OnChain) + RawEvent::StakingElection ); }) } diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index e895a9e4d51ea..520bef8c539b2 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -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(PhantomData); impl WeightInfo for SubstrateWeight { 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 WeightInfo for SubstrateWeight { // 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))) }