From 3f6bf3f207d17c4f9aa68eacc45d29d9e9f379d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sun, 13 Oct 2024 15:34:54 +0200 Subject: [PATCH 01/95] init: adds EPM-MB, multipaged types and primitives --- Cargo.lock | 23 + Cargo.toml | 2 + .../election-provider-multi-block/Cargo.toml | 72 ++ .../election-provider-multi-block/README.md | 1 + .../integration-tests/Cargo.toml | 54 + .../integration-tests/src/lib.rs | 125 ++ .../integration-tests/src/mock.rs | 998 +++++++++++++++ .../src/benchmarking.rs | 318 +++++ .../src/helpers.rs | 331 +++++ .../election-provider-multi-block/src/lib.rs | 1139 +++++++++++++++++ .../src/mock/mod.rs | 594 +++++++++ .../src/mock/staking.rs | 235 ++++ .../src/signed/benchmarking.rs | 66 + .../src/signed/mod.rs | 676 ++++++++++ .../src/signed/tests.rs | 309 +++++ .../src/types.rs | 255 ++++ .../src/unsigned/benchmarking.rs | 88 ++ .../src/unsigned/miner.rs | 811 ++++++++++++ .../src/unsigned/mod.rs | 360 ++++++ .../src/unsigned/tests.rs | 216 ++++ .../src/unsigned/weights.rs | 85 ++ .../src/verifier/benchmarking.rs | 315 +++++ .../src/verifier/impls.rs | 764 +++++++++++ .../src/verifier/mod.rs | 287 +++++ .../src/verifier/tests.rs | 121 ++ .../src/verifier/weights.rs | 249 ++++ .../src/weights.rs | 188 +++ .../election-provider-support/Cargo.toml | 2 + .../solution-type/src/codec.rs | 1 + .../solution-type/src/single_page.rs | 2 +- .../election-provider-support/src/lib.rs | 335 +++-- .../election-provider-support/src/onchain.rs | 199 +-- .../primitives/npos-elections/src/lib.rs | 56 +- substrate/primitives/staking/Cargo.toml | 2 + substrate/primitives/staking/src/lib.rs | 63 + 35 files changed, 9154 insertions(+), 188 deletions(-) create mode 100644 substrate/frame/election-provider-multi-block/Cargo.toml create mode 100644 substrate/frame/election-provider-multi-block/README.md create mode 100644 substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml create mode 100644 substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs create mode 100644 substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs create mode 100644 substrate/frame/election-provider-multi-block/src/benchmarking.rs create mode 100644 substrate/frame/election-provider-multi-block/src/helpers.rs create mode 100644 substrate/frame/election-provider-multi-block/src/lib.rs create mode 100644 substrate/frame/election-provider-multi-block/src/mock/mod.rs create mode 100644 substrate/frame/election-provider-multi-block/src/mock/staking.rs create mode 100644 substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs create mode 100644 substrate/frame/election-provider-multi-block/src/signed/mod.rs create mode 100644 substrate/frame/election-provider-multi-block/src/signed/tests.rs create mode 100644 substrate/frame/election-provider-multi-block/src/types.rs create mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs create mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/miner.rs create mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/mod.rs create mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/tests.rs create mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/weights.rs create mode 100644 substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs create mode 100644 substrate/frame/election-provider-multi-block/src/verifier/impls.rs create mode 100644 substrate/frame/election-provider-multi-block/src/verifier/mod.rs create mode 100644 substrate/frame/election-provider-multi-block/src/verifier/tests.rs create mode 100644 substrate/frame/election-provider-multi-block/src/verifier/weights.rs create mode 100644 substrate/frame/election-provider-multi-block/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index ca71985b69f07..ba5f04aaf9997 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6288,6 +6288,7 @@ dependencies = [ "sp-io 30.0.0", "sp-npos-elections", "sp-runtime 31.0.1", + "sp-std 14.0.0", ] [[package]] @@ -11447,6 +11448,27 @@ dependencies = [ "sp-tracing 16.0.0", ] +[[package]] +name = "pallet-election-provider-multi-block" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "parking_lot 0.12.3", + "scale-info", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-npos-elections", + "sp-runtime 31.0.1", + "sp-std 14.0.0", + "sp-tracing 16.0.0", +] + [[package]] name = "pallet-election-provider-multi-phase" version = "27.0.0" @@ -22707,6 +22729,7 @@ dependencies = [ "serde", "sp-core 28.0.0", "sp-runtime 31.0.1", + "sp-std 14.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fde05e90ca6e6..b493fceec83e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -339,6 +339,7 @@ members = [ "substrate/frame/core-fellowship", "substrate/frame/delegated-staking", "substrate/frame/democracy", + "substrate/frame/election-provider-multi-block", "substrate/frame/election-provider-multi-phase", "substrate/frame/election-provider-multi-phase/test-staking-e2e", "substrate/frame/election-provider-support", @@ -911,6 +912,7 @@ pallet-default-config-example = { path = "substrate/frame/examples/default-confi pallet-delegated-staking = { path = "substrate/frame/delegated-staking", default-features = false } pallet-democracy = { path = "substrate/frame/democracy", default-features = false } pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features = false } +pallet-election-provider-multi-block = { path = "substrate/frame/election-provider-multi-block", default-features = false } pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } diff --git a/substrate/frame/election-provider-multi-block/Cargo.toml b/substrate/frame/election-provider-multi-block/Cargo.toml new file mode 100644 index 0000000000000..e665a714008b5 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/Cargo.toml @@ -0,0 +1,72 @@ +[package] +name = "pallet-election-provider-multi-block" +version = "4.0.0-dev" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository.workspace = true +description = "FRAME pallet election provider multi-block" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.10.0", default-features = false, features = [ + "derive", +] } +log = { version = "0.4.17", default-features = false } + +frame-support = { path = "../support", default-features = false } +frame-system = { path = "../system", default-features = false } +frame-benchmarking = { path = "../benchmarking", default-features = false } + +sp-io = { path = "../../primitives/io", default-features = false } +sp-std = { path = "../../primitives/std", default-features = false } +sp-core = { path = "../../primitives/core", default-features = false } +sp-runtime = { path = "../../primitives/runtime", default-features = false } + +frame-election-provider-support = { default-features = false, path = "../election-provider-support" } +sp-npos-elections = { default-features = false, path = "../../primitives/npos-elections" } + +[dev-dependencies] +sp-tracing = { path = "../../primitives/tracing" } +pallet-balances = { path = "../balances", default-features = false } +parking_lot = "0.12.1" + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking/std", + "frame-election-provider-support/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-balances/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-npos-elections/std", + "sp-runtime/std", + "sp-std/std", +] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-election-provider-support/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] + +try-runtime = [ + "frame-election-provider-support/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/election-provider-multi-block/README.md b/substrate/frame/election-provider-multi-block/README.md new file mode 100644 index 0000000000000..9aff2b4bb152a --- /dev/null +++ b/substrate/frame/election-provider-multi-block/README.md @@ -0,0 +1 @@ +# Election Provider multi-block diff --git a/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml b/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml new file mode 100644 index 0000000000000..15aa841666209 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "pallet-election-tests" +version = "1.0.0" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage.workspace = true +repository.workspace = true +description = "FRAME election provider multi block pallet tests with staking pallet, bags-list and session pallets" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dev-dependencies] +parking_lot = { workspace = true, default-features = true } +codec = { features = ["derive"], workspace = true, default-features = true } +scale-info = { features = ["derive"], workspace = true, default-features = true } +log = { workspace = true } + +sp-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true, default-features = true } +sp-std = { workspace = true, default-features = true } +sp-staking = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-npos-elections = { workspace = true } +sp-tracing = { workspace = true, default-features = true } + +frame-system = { workspace = true, default-features = true } +frame-support = { workspace = true, default-features = true } +frame-election-provider-support = { workspace = true, default-features = true } + +pallet-election-provider-multi-block = { workspace = true, default-features = true } +pallet-staking = { workspace = true, default-features = true } +pallet-nomination-pools = { workspace = true, default-features = true } +pallet-bags-list = { workspace = true, default-features = true } +pallet-balances = { workspace = true, default-features = true } +pallet-timestamp = { workspace = true, default-features = true } +pallet-session = { workspace = true, default-features = true } + +[features] +try-runtime = [ + "frame-election-provider-support/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-bags-list/try-runtime", + "pallet-balances/try-runtime", + #"pallet-election-provider-multi-block/try-runtime", + "pallet-nomination-pools/try-runtime", + "pallet-session/try-runtime", + "pallet-staking/try-runtime", + "pallet-timestamp/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs new file mode 100644 index 0000000000000..3cd56def8e066 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs @@ -0,0 +1,125 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#![cfg(test)] +mod mock; + +pub(crate) const LOG_TARGET: &str = "integration-tests::epm-staking"; + +use mock::*; + +use frame_election_provider_support::{bounds::ElectionBoundsBuilder, ElectionDataProvider}; + +use frame_support::{assert_ok, traits::UnixTime}; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("🛠️ ", $patter) $(, $values)* + ) + }; +} + +fn log_current_time() { + log!( + info, + "block: {:?}, session: {:?}, era: {:?}, EPM phase: {:?} ts: {:?}", + System::block_number(), + Session::current_index(), + Staking::current_era(), + ElectionProvider::current_phase(), + Timestamp::now() + ); +} + +#[test] +fn block_progression_works() { + let (mut ext, _pool_state, _) = ExtBuilder::default().build_offchainify(); + ext.execute_with(|| {}) +} + +#[test] +fn verify_snapshot() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Pages::get(), 3); + + // manually get targets and voters from staking to see the inspect the issue with the + // DataProvider. + let bounds = ElectionBoundsBuilder::default() + .targets_count((TargetSnapshotPerBlock::get() as u32).into()) + .voters_count((VoterSnapshotPerBlock::get() as u32).into()) + .build(); + + assert_ok!(::electable_targets(bounds.targets, 2)); + assert_ok!(::electing_voters(bounds.voters, 2)); + }) +} + +mod staking_integration { + use super::*; + use pallet_election_provider_multi_block::Phase; + + #[test] + fn call_elect_multi_block() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Pages::get(), 3); + assert_eq!(ElectionProvider::current_round(), 0); + assert_eq!(Staking::current_era(), Some(0)); + + let export_starts_at = election_prediction() - Pages::get(); + + assert!(Staking::election_data_lock().is_none()); + + // check that the election data provider lock is set during the snapshot phase and + // released afterwards. + roll_to_phase(Phase::Snapshot(Pages::get() - 1), false); + assert!(Staking::election_data_lock().is_some()); + + roll_one(None, false); + assert!(Staking::election_data_lock().is_some()); + roll_one(None, false); + assert!(Staking::election_data_lock().is_some()); + // snapshot phase done, election data lock was released. + roll_one(None, false); + assert_eq!(ElectionProvider::current_phase(), Phase::Signed); + assert!(Staking::election_data_lock().is_none()); + + // last block where phase is waiting for unsignned submissions. + roll_to(election_prediction() - 4, false); + assert_eq!(ElectionProvider::current_phase(), Phase::Unsigned(17)); + + // staking prepares first page of exposures. + roll_to(export_starts_at, false); + assert_eq!(ElectionProvider::current_phase(), Phase::Export(export_starts_at)); + + // staking prepares second page of exposures. + roll_to(election_prediction() - 2, false); + assert_eq!(ElectionProvider::current_phase(), Phase::Export(export_starts_at)); + + // staking prepares third page of exposures. + roll_to(election_prediction() - 1, false); + + // election successfully, round & era progressed. + assert_eq!(ElectionProvider::current_phase(), Phase::Off); + assert_eq!(ElectionProvider::current_round(), 1); + assert_eq!(Staking::current_era(), Some(1)); + }) + } +} diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs new file mode 100644 index 0000000000000..29dd2733250e3 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs @@ -0,0 +1,998 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +#![allow(dead_code)] + +use frame_support::{ + assert_ok, parameter_types, traits, + traits::{Hooks, VariantCountOf}, + weights::constants, +}; +use frame_system::EnsureRoot; +use sp_core::{ConstU32, Get}; +use sp_npos_elections::VoteWeight; +use sp_runtime::{ + offchain::{ + testing::{OffchainState, PoolState, TestOffchainExt, TestTransactionPoolExt}, + OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, + }, + testing, + traits::Zero, + transaction_validity, BuildStorage, PerU16, Perbill, Percent, +}; +use sp_staking::{ + offence::{OffenceDetails, OnOffenceHandler}, + EraIndex, SessionIndex, +}; +use std::collections::BTreeMap; + +use codec::Decode; +use frame_election_provider_support::{ + bounds::ElectionBoundsBuilder, onchain, ElectionDataProvider, ExtendedBalance, PageIndex, + SequentialPhragmen, Weight, +}; +use sp_npos_elections::ElectionScore; + +use pallet_election_provider_multi_block::{ + self as epm_core_pallet, + signed::{self as epm_signed_pallet}, + unsigned::{self as epm_unsigned_pallet, miner}, + verifier::{self as epm_verifier_pallet}, + Config, Phase, +}; + +use pallet_staking::StakerStatus; +use parking_lot::RwLock; +use std::sync::Arc; + +use frame_support::derive_impl; + +use crate::{log, log_current_time}; + +pub const INIT_TIMESTAMP: BlockNumber = 30_000; +pub const BLOCK_TIME: BlockNumber = 1000; + +type Block = frame_system::mocking::MockBlockU32; +type Extrinsic = testing::TestXt; +pub(crate) type T = Runtime; + +frame_support::construct_runtime!( + pub enum Runtime { + System: frame_system, + + // EPM core and sub-pallets + ElectionProvider: epm_core_pallet, + VerifierPallet: epm_verifier_pallet, + SignedPallet: epm_signed_pallet, + UnsignedPallet: epm_unsigned_pallet, + + Pools: pallet_nomination_pools, + Staking: pallet_staking, + Balances: pallet_balances, + BagsList: pallet_bags_list, + Session: pallet_session, + Historical: pallet_session::historical, + Timestamp: pallet_timestamp, + } +); + +pub(crate) type AccountId = u64; +pub(crate) type AccountIndex = u32; +pub(crate) type BlockNumber = u32; +pub(crate) type Balance = u64; +pub(crate) type VoterIndex = u16; +pub(crate) type TargetIndex = u16; +pub(crate) type Moment = u32; + +pub type Solver = SequentialPhragmen; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +parameter_types! { + pub static ExistentialDeposit: Balance = 1; + pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights + ::with_sensible_defaults( + Weight::from_parts(2u64 * constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), + NORMAL_DISPATCH_RATIO, + ); +} + +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] +impl pallet_balances::Config for Runtime { + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxFreezes = VariantCountOf; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = RuntimeFreezeReason; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = Moment; + type OnTimestampSet = (); + type MinimumPeriod = traits::ConstU32<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static Period: u32 = 30; + pub static Offset: u32 = 0; +} + +sp_runtime::impl_opaque_keys! { + pub struct SessionKeys { + pub other: OtherSessionHandler, + } +} + +impl pallet_session::Config for Runtime { + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type Keys = SessionKeys; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionHandler = (OtherSessionHandler,); + type RuntimeEvent = RuntimeEvent; + type ValidatorId = AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type WeightInfo = (); +} +impl pallet_session::historical::Config for Runtime { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +frame_election_provider_support::generate_solution_type!( + #[compact] + pub struct MockNposSolution::< + VoterIndex = VoterIndex, + TargetIndex = TargetIndex, + Accuracy = PerU16, + MaxVoters = ConstU32::<2_000> + >(6) +); + +parameter_types! { + pub static SignedPhase: BlockNumber = 10; + pub static UnsignedPhase: BlockNumber = 10; + pub static SignedValidationPhase: BlockNumber = Pages::get().into(); + pub static Lookhaead: BlockNumber = Pages::get(); + pub static VoterSnapshotPerBlock: VoterIndex = 4; + pub static TargetSnapshotPerBlock: TargetIndex = 8; + pub static Pages: PageIndex = 3; + pub static ExportPhaseLimit: BlockNumber = (Pages::get() * 2u32).into(); + + // TODO: remove what's not needed from here down: + + // we expect a minimum of 3 blocks in signed phase and unsigned phases before trying + // entering in emergency phase after the election failed. + pub static MinBlocksBeforeEmergency: BlockNumber = 3; + #[derive(Debug)] + pub static MaxVotesPerVoter: u32 = 16; + pub static SignedFixedDeposit: Balance = 1; + pub static SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); + pub static ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = ElectionBoundsBuilder::default() + .voters_count(1_000.into()).targets_count(1_000.into()).build(); +} + +pub struct EPMBenchmarkingConfigs; +impl pallet_election_provider_multi_block::BenchmarkingConfig for EPMBenchmarkingConfigs { + const VOTERS: u32 = 100; + const TARGETS: u32 = 50; + const VOTERS_PER_PAGE: [u32; 2] = [1, 5]; + const TARGETS_PER_PAGE: [u32; 2] = [1, 8]; +} + +impl epm_core_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type SignedValidationPhase = SignedValidationPhase; + type Lookhaead = Lookhaead; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type TargetSnapshotPerBlock = TargetSnapshotPerBlock; + type Pages = Pages; + type ExportPhaseLimit = ExportPhaseLimit; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + type MinerConfig = Self; + type Fallback = frame_election_provider_support::NoElection<( + AccountId, + BlockNumber, + Staking, + MaxWinnersPerPage, + MaxBackersPerWinner, + )>; + type Verifier = VerifierPallet; + type DataProvider = Staking; + type BenchmarkingConfig = EPMBenchmarkingConfigs; + type WeightInfo = (); +} + +parameter_types! { + pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); + pub static MaxWinnersPerPage: u32 = 4; + pub static MaxBackersPerWinner: u32 = 16; +} + +impl epm_verifier_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForceOrigin = frame_system::EnsureRoot; + type SolutionImprovementThreshold = SolutionImprovementThreshold; + type SolutionDataProvider = SignedPallet; + type WeightInfo = (); +} + +parameter_types! { + pub static DepositBase: Balance = 10; + pub static DepositPerPage: Balance = 1; + pub static Reward: Balance = 10; + pub static MaxSubmissions: u32 = 5; +} + +impl epm_signed_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type EstimateCallFee = ConstU32<8>; + type OnSlash = (); // burn + type DepositBase = ConstDepositBase; + type DepositPerPage = DepositPerPage; + type Reward = Reward; + type MaxSubmissions = MaxSubmissions; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = (); +} + +pub struct ConstDepositBase; +impl sp_runtime::traits::Convert for ConstDepositBase { + fn convert(_a: usize) -> Balance { + DepositBase::get() + } +} + +parameter_types! { + pub static OffchainRepeatInterval: BlockNumber = 0; + pub static TransactionPriority: transaction_validity::TransactionPriority = 1; + pub static MinerMaxLength: u32 = 256; + pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; +} + +impl epm_unsigned_pallet::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OffchainRepeatInterval = OffchainRepeatInterval; + type MinerTxPriority = TransactionPriority; + type MaxLength = MinerMaxLength; + type MaxWeight = MinerMaxWeight; + type WeightInfo = (); +} + +impl miner::Config for Runtime { + type AccountId = AccountId; + type Solution = MockNposSolution; + type Solver = Solver; + type Pages = Pages; + type MaxVotesPerVoter = ConstU32<16>; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type TargetSnapshotPerBlock = TargetSnapshotPerBlock; + type MaxWeight = MinerMaxWeight; + type MaxLength = MinerMaxLength; +} + +const THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; + +parameter_types! { + pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; + pub const SessionsPerEra: sp_staking::SessionIndex = 2; + pub const BondingDuration: sp_staking::EraIndex = 28; + pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. +} + +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type ScoreProvider = Staking; + type BagThresholds = BagThresholds; + type Score = VoteWeight; +} + +pub struct BalanceToU256; +impl sp_runtime::traits::Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl sp_runtime::traits::Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub const PoolsPalletId: frame_support::PalletId = frame_support::PalletId(*b"py/nopls"); + pub static MaxUnbonding: u32 = 8; +} + +impl pallet_nomination_pools::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type RuntimeFreezeReason = RuntimeFreezeReason; + type RewardCounter = sp_runtime::FixedU128; + type BalanceToU256 = BalanceToU256; + type U256ToBalance = U256ToBalance; + type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; + type PostUnbondingPoolsWindow = ConstU32<2>; + type PalletId = PoolsPalletId; + type MaxMetadataLen = ConstU32<256>; + type MaxUnbonding = MaxUnbonding; + type MaxPointsToBalance = frame_support::traits::ConstU8<10>; + type AdminOrigin = frame_system::EnsureRoot; +} + +parameter_types! { + pub static MaxUnlockingChunks: u32 = 32; + pub MaxControllersInDeprecationBatch: u32 = 5900; + pub static MaxValidatorSet: u32 = 500; +} + +/// Upper limit on the number of NPOS nominations. +const MAX_QUOTA_NOMINATIONS: u32 = 16; +/// Disabling factor set explicitly to byzantine threshold +pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3; + +#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] +impl pallet_staking::Config for Runtime { + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = Timestamp; + type SessionsPerEra = SessionsPerEra; + type BondingDuration = BondingDuration; + type SlashDeferDuration = SlashDeferDuration; + type AdminOrigin = EnsureRoot; // root can cancel slashes + type SessionInterface = Self; + type EraPayout = (); + type NextNewSession = Session; + type MaxExposurePageSize = ConstU32<256>; + type MaxValidatorSet = MaxValidatorSet; + type ElectionProvider = ElectionProvider; + type GenesisElectionProvider = onchain::OnChainExecution; + type VoterList = BagsList; + type NominationsQuota = pallet_staking::FixedNominationsQuota; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = MaxUnlockingChunks; + type EventListeners = Pools; + type WeightInfo = pallet_staking::weights::SubstrateWeight; + type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; +} + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type OverarchingCall = RuntimeCall; + type Extrinsic = Extrinsic; +} + +pub struct OnChainSeqPhragmen; + +parameter_types! { + pub static VotersBound: u32 = 600; + pub static TargetsBound: u32 = 400; +} + +impl onchain::Config for OnChainSeqPhragmen { + type System = Runtime; + type Solver = Solver; + type DataProvider = Staking; + type WeightInfo = (); + type Bounds = ElectionBounds; + type MaxBackersPerWinner = MaxBackersPerWinner; + type MaxWinnersPerPage = MaxWinnersPerPage; +} + +pub struct OtherSessionHandler; +impl traits::OneSessionHandler for OtherSessionHandler { + type Key = testing::UintAuthorityId; + + fn on_genesis_session<'a, I: 'a>(_: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_disabled(_validator_index: u32) {} +} + +impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { + type Public = testing::UintAuthorityId; +} + +pub struct StakingExtBuilder { + validator_count: u32, + minimum_validator_count: u32, + min_nominator_bond: Balance, + min_validator_bond: Balance, + status: BTreeMap>, + stakes: BTreeMap, + stakers: Vec<(AccountId, AccountId, Balance, StakerStatus)>, +} + +impl Default for StakingExtBuilder { + fn default() -> Self { + let stakers = vec![ + // (stash, ctrl, stake, status) + (11, 11, 1000, StakerStatus::::Validator), + (21, 21, 1000, StakerStatus::::Validator), + (31, 31, 500, StakerStatus::::Validator), + (41, 41, 1500, StakerStatus::::Validator), + (51, 51, 1500, StakerStatus::::Validator), + (61, 61, 1500, StakerStatus::::Validator), + (71, 71, 1500, StakerStatus::::Validator), + (81, 81, 1500, StakerStatus::::Validator), + (91, 91, 1500, StakerStatus::::Validator), + (101, 101, 500, StakerStatus::::Validator), + // idle validators + (201, 201, 1000, StakerStatus::::Idle), + (301, 301, 1000, StakerStatus::::Idle), + // nominators + (10, 10, 2000, StakerStatus::::Nominator(vec![11, 21])), + (20, 20, 2000, StakerStatus::::Nominator(vec![31])), + (30, 30, 2000, StakerStatus::::Nominator(vec![91, 101])), + (40, 40, 2000, StakerStatus::::Nominator(vec![11, 101])), + ]; + + Self { + validator_count: 6, + minimum_validator_count: 0, + min_nominator_bond: ExistentialDeposit::get(), + min_validator_bond: ExistentialDeposit::get(), + status: Default::default(), + stakes: Default::default(), + stakers, + } + } +} + +impl StakingExtBuilder { + pub fn validator_count(mut self, n: u32) -> Self { + self.validator_count = n; + self + } +} + +pub struct EpmExtBuilder {} + +impl Default for EpmExtBuilder { + fn default() -> Self { + EpmExtBuilder {} + } +} + +impl EpmExtBuilder { + pub fn disable_emergency_throttling(self) -> Self { + ::set(0); + self + } + + pub fn phases(self, signed: BlockNumber, unsigned: BlockNumber) -> Self { + ::set(signed); + ::set(unsigned); + self + } +} + +pub struct BalancesExtBuilder { + balances: Vec<(AccountId, Balance)>, +} + +impl Default for BalancesExtBuilder { + fn default() -> Self { + let balances = vec![ + // (account_id, balance) + (1, 10), + (2, 20), + (3, 300), + (4, 400), + // nominators + (10, 10_000), + (20, 10_000), + (30, 10_000), + (40, 10_000), + (50, 10_000), + (60, 10_000), + (70, 10_000), + (80, 10_000), + (90, 10_000), + (100, 10_000), + (200, 10_000), + // validators + (11, 1000), + (21, 2000), + (31, 3000), + (41, 4000), + (51, 5000), + (61, 6000), + (71, 7000), + (81, 8000), + (91, 9000), + (101, 10000), + (201, 20000), + (301, 20000), + // This allows us to have a total_payout different from 0. + (999, 1_000_000_000_000), + ]; + Self { balances } + } +} + +pub struct ExtBuilder { + staking_builder: StakingExtBuilder, + epm_builder: EpmExtBuilder, + balances_builder: BalancesExtBuilder, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + staking_builder: StakingExtBuilder::default(), + epm_builder: EpmExtBuilder::default(), + balances_builder: BalancesExtBuilder::default(), + } + } +} + +impl ExtBuilder { + pub fn build(&self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let _ = pallet_balances::GenesisConfig:: { + balances: self.balances_builder.balances.clone(), + } + .assimilate_storage(&mut storage); + + let mut stakers = self.staking_builder.stakers.clone(); + self.staking_builder.status.clone().into_iter().for_each(|(stash, status)| { + let (_, _, _, ref mut prev_status) = stakers + .iter_mut() + .find(|s| s.0 == stash) + .expect("set_status staker should exist; qed"); + *prev_status = status; + }); + // replaced any of the stakes if needed. + self.staking_builder.stakes.clone().into_iter().for_each(|(stash, stake)| { + let (_, _, ref mut prev_stake, _) = stakers + .iter_mut() + .find(|s| s.0 == stash) + .expect("set_stake staker should exits; qed."); + *prev_stake = stake; + }); + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + validator_count: self.staking_builder.validator_count, + minimum_validator_count: self.staking_builder.minimum_validator_count, + slash_reward_fraction: Perbill::from_percent(10), + min_nominator_bond: self.staking_builder.min_nominator_bond, + min_validator_bond: self.staking_builder.min_validator_bond, + ..Default::default() + } + .assimilate_storage(&mut storage); + + let _ = pallet_session::GenesisConfig:: { + // set the keys for the first session. + keys: stakers + .into_iter() + .map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() })) + .collect(), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + // We consider all test to start after timestamp is initialized This must be ensured by + // having `timestamp::on_initialize` called before `staking::on_initialize`. + ext.execute_with(|| { + System::set_block_number(1); + Session::on_initialize(1); + >::on_initialize(1); + Timestamp::set_timestamp(INIT_TIMESTAMP); + }); + + ext + } + + pub fn staking(mut self, builder: StakingExtBuilder) -> Self { + self.staking_builder = builder; + self + } + + pub fn epm(mut self, builder: EpmExtBuilder) -> Self { + self.epm_builder = builder; + self + } + + pub fn balances(mut self, builder: BalancesExtBuilder) -> Self { + self.balances_builder = builder; + self + } + + pub fn build_offchainify( + self, + ) -> (sp_io::TestExternalities, Arc>, Arc>) { + // add offchain and pool externality extensions. + let mut ext = self.build(); + let (offchain, offchain_state) = TestOffchainExt::new(); + let (pool, pool_state) = TestTransactionPoolExt::new(); + + ext.register_extension(OffchainDbExt::new(offchain.clone())); + ext.register_extension(OffchainWorkerExt::new(offchain)); + ext.register_extension(TransactionPoolExt::new(pool)); + + (ext, pool_state, offchain_state) + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = self.build(); + ext.execute_with(test); + + #[cfg(feature = "try-runtime")] + ext.execute_with(|| { + let bn = System::block_number(); + + assert_ok!(>::try_state(bn)); + assert_ok!(>::try_state(bn)); + assert_ok!(>::try_state(bn)); + }); + } +} + +// Progress to given block, triggering session and era changes as we progress and ensuring that +// there is a solution queued when expected. +pub fn roll_to(n: BlockNumber, delay_solution: bool) { + for b in (System::block_number()) + 1..=n { + System::set_block_number(b); + Session::on_initialize(b); + Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); + + if ElectionProvider::current_phase() == Phase::Signed && !delay_solution { + let _ = try_submit_paged_solution().map_err(|e| { + log!(info, "failed to mine/queue solution: {:?}", e); + }); + }; + + ElectionProvider::on_initialize(b); + VerifierPallet::on_initialize(b); + SignedPallet::on_initialize(b); + UnsignedPallet::on_initialize(b); + + Staking::on_initialize(b); + if b != n { + Staking::on_finalize(System::block_number()); + } + + log_current_time(); + } +} + +// Progress to given block, triggering session and era changes as we progress and ensuring that +// there is a solution queued when expected. +pub fn roll_to_with_ocw(n: BlockNumber, pool: Arc>, delay_solution: bool) { + for b in (System::block_number()) + 1..=n { + System::set_block_number(b); + Session::on_initialize(b); + Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); + + ElectionProvider::on_initialize(b); + VerifierPallet::on_initialize(b); + SignedPallet::on_initialize(b); + UnsignedPallet::on_initialize(b); + + ElectionProvider::offchain_worker(b); + + if !delay_solution && pool.read().transactions.len() > 0 { + // decode submit_unsigned callable that may be queued in the pool by ocw. skip all + // other extrinsics in the pool. + for encoded in &pool.read().transactions { + let _extrinsic = Extrinsic::decode(&mut &encoded[..]).unwrap(); + + // TODO(gpestana): fix when EPM sub-pallets are ready + //let _ = match extrinsic.call { + // RuntimeCall::ElectionProvider( + // call @ Call::submit_unsigned { .. }, + // ) => { + // // call submit_unsigned callable in OCW pool. + // assert_ok!(call.dispatch_bypass_filter(RuntimeOrigin::none())); + // }, + // _ => (), + //}; + } + + pool.try_write().unwrap().transactions.clear(); + } + + Staking::on_initialize(b); + if b != n { + Staking::on_finalize(System::block_number()); + } + + log_current_time(); + } +} +// helper to progress one block ahead. +pub fn roll_one(pool: Option>>, delay_solution: bool) { + let bn = System::block_number().saturating_add(1); + match pool { + None => roll_to(bn, delay_solution), + Some(pool) => roll_to_with_ocw(bn, pool, delay_solution), + } +} + +/// Progresses from the current block number (whatever that may be) to the block where the session +/// `session_index` starts. +pub(crate) fn start_session( + session_index: SessionIndex, + pool: Arc>, + delay_solution: bool, +) { + let end = if Offset::get().is_zero() { + Period::get() * session_index + } else { + Offset::get() * session_index + Period::get() * session_index + }; + + assert!(end >= System::block_number()); + + roll_to_with_ocw(end, pool, delay_solution); + + // session must have progressed properly. + assert_eq!( + Session::current_index(), + session_index, + "current session index = {}, expected = {}", + Session::current_index(), + session_index, + ); +} + +/// Go one session forward. +pub(crate) fn advance_session(pool: Arc>) { + let current_index = Session::current_index(); + start_session(current_index + 1, pool, false); +} + +pub(crate) fn advance_session_delayed_solution(pool: Arc>) { + let current_index = Session::current_index(); + start_session(current_index + 1, pool, true); +} + +pub(crate) fn start_next_active_era(pool: Arc>) -> Result<(), ()> { + start_active_era(active_era() + 1, pool, false) +} + +pub(crate) fn start_next_active_era_delayed_solution( + pool: Arc>, +) -> Result<(), ()> { + start_active_era(active_era() + 1, pool, true) +} + +pub(crate) fn advance_eras(n: usize, pool: Arc>) { + for _ in 0..n { + assert_ok!(start_next_active_era(pool.clone())); + } +} + +/// Progress until the given era. +pub(crate) fn start_active_era( + era_index: EraIndex, + pool: Arc>, + delay_solution: bool, +) -> Result<(), ()> { + let era_before = current_era(); + + start_session((era_index * >::get()).into(), pool, delay_solution); + + log!( + info, + "start_active_era - era_before: {}, current era: {} -> progress to: {} -> after era: {}", + era_before, + active_era(), + era_index, + current_era(), + ); + + // if the solution was not delayed, era should have progressed. + if !delay_solution && (active_era() != era_index || current_era() != active_era()) { + Err(()) + } else { + Ok(()) + } +} + +pub(crate) fn active_era() -> EraIndex { + Staking::active_era().unwrap().index +} + +pub(crate) fn current_era() -> EraIndex { + Staking::current_era().unwrap() +} + +// Fast forward until a given election phase. +pub fn roll_to_phase(phase: Phase, delay: bool) { + while ElectionProvider::current_phase() != phase { + roll_to(System::block_number() + 1, delay); + } +} + +pub fn election_prediction() -> BlockNumber { + <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number(), + ) +} + +parameter_types! { + pub static LastSolutionSubmittedFor: Option = None; +} + +pub(crate) fn try_submit_paged_solution() -> Result<(), ()> { + let submit = || { + // TODO: to finish. + let (paged_solution, _) = + miner::Miner::<::MinerConfig>::mine_paged_solution_with_snapshot( + voters_snapshot, + targets_snapshot, + Pages::get(), + round, + desired_targets, + false, + ) + .unwrap(); + + let _ = SignedPallet::register(RuntimeOrigin::signed(10), paged_solution.score).unwrap(); + + for (idx, page) in paged_solution.solution_pages.into_iter().enumerate() {} + log!( + info, + "submitter: successfully submitted {} pages with {:?} score in round {}.", + Pages::get(), + paged_solution.score, + ElectionProvider::current_round(), + ); + }; + + match LastSolutionSubmittedFor::get() { + Some(submitted_at) => { + if submitted_at == ElectionProvider::current_round() { + // solution already submitted in this round, do nothing. + } else { + // haven't submit in this round, submit it. + submit() + } + }, + // never submitted, do it. + None => submit(), + }; + LastSolutionSubmittedFor::set(Some(ElectionProvider::current_round())); + + Ok(()) +} + +pub(crate) fn on_offence_now( + offenders: &[OffenceDetails>], + slash_fraction: &[Perbill], +) { + let now = Staking::active_era().unwrap().index; + let _ = Staking::on_offence( + offenders, + slash_fraction, + Staking::eras_start_session_index(now).unwrap(), + ); +} + +// Add offence to validator, slash it. +pub(crate) fn add_slash(who: &AccountId) { + on_offence_now( + &[OffenceDetails { + offender: (*who, Staking::eras_stakers(active_era(), who)), + reporters: vec![], + }], + &[Perbill::from_percent(10)], + ); +} + +// Slashes 1/2 of the active set. Returns the `AccountId`s of the slashed validators. +pub(crate) fn slash_half_the_active_set() -> Vec { + let mut slashed = Session::validators(); + slashed.truncate(slashed.len() / 2); + + for v in slashed.iter() { + add_slash(v); + } + + slashed +} + +// Slashes a percentage of the active nominators that haven't been slashed yet, with +// a minimum of 1 validator slash. +pub(crate) fn slash_percentage(percentage: Perbill) -> Vec { + let validators = Session::validators(); + let mut remaining_slashes = (percentage * validators.len() as u32).max(1); + let mut slashed = vec![]; + + for v in validators.into_iter() { + if remaining_slashes != 0 { + add_slash(&v); + slashed.push(v); + remaining_slashes -= 1; + } + } + slashed +} + +pub(crate) fn set_minimum_election_score( + _minimal_stake: ExtendedBalance, + _sum_stake: ExtendedBalance, + _sum_stake_squared: ExtendedBalance, +) -> Result<(), ()> { + todo!() +} + +pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { + pallet_staking::asset::staked::(&account_id) +} + +pub(crate) fn staking_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) + .collect::>() +} + +pub(crate) fn epm_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| { + if let RuntimeEvent::ElectionProvider(inner) = e { + Some(inner) + } else { + None + } + }, + ) + .collect::>() +} diff --git a/substrate/frame/election-provider-multi-block/src/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/benchmarking.rs new file mode 100644 index 0000000000000..d0d9a98b6bae3 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/benchmarking.rs @@ -0,0 +1,318 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Benchmarking for the Elections Multiblock pallet and sub-pallets. + +use super::*; +use crate::Snapshot; + +use frame_benchmarking::v2::*; +use frame_support::{assert_ok, traits::OnInitialize}; + +/// Seed to generate account IDs. +const SEED: u32 = 999; +/// Default page to use in the benchmarking. +const PAGE: u32 = 0; +/// Minimum number of voters in the data provider and per snapshot page. +const MIN_VOTERS: u32 = 10; + +#[benchmarks( + where T: ConfigCore + ConfigSigned + ConfigVerifier, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn create_targets_snapshot_paged( + t: Linear< + { T::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { T::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + T::BenchmarkingConfig::VOTERS, + T::BenchmarkingConfig::TARGETS.max(t), + ); + + assert!(Snapshot::::targets().is_none()); + + #[block] + { + assert_ok!(PalletCore::::create_targets_snapshot_inner(t)); + } + + assert!(Snapshot::::targets().is_some()); + + Ok(()) + } + + #[benchmark] + fn create_voters_snapshot_paged( + v: Linear< + { T::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { T::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + T::BenchmarkingConfig::VOTERS.max(v), + T::BenchmarkingConfig::TARGETS, + ); + + assert!(Snapshot::::voters(PAGE).is_none()); + + #[block] + { + assert_ok!(PalletCore::::create_voters_snapshot_inner(PAGE, v)); + } + + assert!(Snapshot::::voters(PAGE).is_some()); + + Ok(()) + } + + #[benchmark] + fn on_initialize_start_signed() -> Result<(), BenchmarkError> { + assert!(PalletCore::::current_phase() == Phase::Off); + + #[block] + { + let _ = PalletCore::::start_signed_phase(); + } + + assert!(PalletCore::::current_phase() == Phase::Signed); + + Ok(()) + } + + #[benchmark] + fn on_phase_transition() -> Result<(), BenchmarkError> { + assert!(PalletCore::::current_phase() == Phase::Off); + + #[block] + { + let _ = PalletCore::::phase_transition(Phase::Snapshot(0)); + } + + assert!(PalletCore::::current_phase() == Phase::Snapshot(0)); + + Ok(()) + } + + #[benchmark] + fn on_initialize_start_export() -> Result<(), BenchmarkError> { + #[block] + { + let _ = PalletCore::::do_export_phase(1u32.into(), 100u32.into()); + } + + Ok(()) + } + + #[benchmark] + fn on_initialize_do_nothing() -> Result<(), BenchmarkError> { + assert!(PalletCore::::current_phase() == Phase::Off); + + #[block] + { + let _ = PalletCore::::on_initialize(0u32.into()); + } + + assert!(PalletCore::::current_phase() == Phase::Off); + + Ok(()) + } + + impl_benchmark_test_suite!( + PalletCore, + crate::mock::ExtBuilder::default(), + crate::mock::Runtime, + exec_name = build_and_execute + ); +} + +/// Helper fns to use across the benchmarking of the core pallet and its sub-pallets. +pub(crate) mod helpers { + use super::*; + use crate::{signed::pallet::Submissions, unsigned::miner::Miner, SolutionOf}; + use frame_election_provider_support::ElectionDataProvider; + use frame_support::traits::tokens::Precision; + use sp_std::vec::Vec; + + pub(crate) fn setup_funded_account( + domain: &'static str, + id: u32, + balance_factor: u32, + ) -> T::AccountId { + use frame_support::traits::fungible::{Balanced, Inspect}; + + let account = frame_benchmarking::account::(domain, id, SEED); + let funds = (T::Currency::minimum_balance() + 1u32.into()) * balance_factor.into(); + // increase issuance to ensure a sane voter weight. + let _ = T::Currency::deposit(&account, funds.into(), Precision::Exact); + + account + } + + /// Generates and adds `v` voters and `t` targets in the data provider stores. The voters + /// nominate `DataProvider::MaxVotesPerVoter` targets. + pub(crate) fn setup_data_provider(v: u32, t: u32) { + ::DataProvider::clear(); + + log!(info, "setup_data_provider with v: {}, t: {}", v, t,); + + // generate and add targets. + let mut targets = (0..t) + .map(|i| { + let target = setup_funded_account::("Target", i, 200); + ::DataProvider::add_target(target.clone()); + target + }) + .collect::>(); + + // we should always have enough voters to fill. + assert!( + targets.len() > + <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter::get() + as usize + ); + + targets.truncate( + <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter::get() as usize, + ); + + // generate and add voters with `MaxVotesPerVoter` nominations from the list of targets. + (0..v.max(MIN_VOTERS)).for_each(|i| { + let voter = setup_funded_account::("Voter", i, 2_000); + <::DataProvider as ElectionDataProvider>::add_voter( + voter, + 1_000, + targets.clone().try_into().unwrap(), + ); + }); + } + + /// Generates the full paged snapshot for both targets and voters. + pub(crate) fn setup_snapshot(v: u32, t: u32) -> Result<(), &'static str> { + // set desired targets to match the size off the target page. + ::set_desired_targets(t); + + log!( + info, + "setting up the snapshot. voters/page: {:?}, targets/page: {:?} (desired_targets: {:?})", + v, + t, + ::desired_targets(), + ); + + let _ = PalletCore::::create_targets_snapshot_inner(t) + .map_err(|_| "error creating the target snapshot, most likely `T::TargetSnapshotPerBlock` config needs to be adjusted")?; + + for page in 0..T::Pages::get() { + let _ = PalletCore::::create_voters_snapshot_inner(page, v) + .map_err(|_| "error creating the voter snapshot, most likely `T::VoterSnapshotPerBlock` config needs to be adjusted")?; + } + + Ok(()) + } + + /// Mines a full solution for the current snapshot and submits `maybe_page`. Otherwise submits + /// all pages. `valid` defines whether the solution is valid or not. + pub(crate) fn mine_and_submit< + T: ConfigCore + ConfigUnsigned + ConfigSigned + ConfigVerifier, + >( + maybe_page: Option, + valid: bool, + ) -> Result { + // ensure that the number of desired targets fits within the bound of max winners per page, + // otherwise preemptively since the feasibilty check will fail. + ensure!( + ::desired_targets() + .expect("desired_targets is set") <= + ::MaxWinnersPerPage::get(), + "`MaxWinnersPerPage` must be equal or higher than desired_targets. fix the configs.", + ); + + let submitter = setup_funded_account::("Submitter", 1, 1_000); + + let (mut solution, _) = + Miner::::mine_paged_solution(T::Pages::get(), true).map_err( + |e| { + log!(info, "ERR:: {:?}", e); + "error mining solution" + }, + )?; + + // if the submission is full and the fesibility check must fail, mess up with the solution's + // claimed score to fail the verification (worst case scenario in terms of async solution + // verification). + let claimed_score = if maybe_page.is_none() && !valid { + solution.score.sum_stake += 1_000_000; + solution.score + } else { + solution.score + }; + + // set transition to phase to ensure the page mutation works. + PalletCore::::phase_transition(Phase::Signed); + + // first register submission. + PalletSigned::::do_register(&submitter, claimed_score, PalletCore::::current_round()) + .map_err(|_| "error registering solution")?; + + for page in maybe_page + .map(|p| sp_std::vec![p]) + .unwrap_or((0..T::Pages::get()).rev().collect::>()) + .into_iter() + { + let paged_solution = + solution.solution_pages.get(page as usize).ok_or("page out of bounds")?; + + // if it is a single page submission and submission should be invalid, make the paged + // paged submission invalid by tweaking the current snapshot. + if maybe_page.is_some() && !valid { + ensure_solution_invalid::(&paged_solution)?; + } + + // process and submit only onle page. + Submissions::::try_mutate_page( + &submitter, + PalletCore::::current_round(), + page, + Some(paged_solution.clone()), + ) + .map_err(|_| "error storing page")?; + } + + Ok(submitter) + } + + /// ensures `solution` will be considered invalid in the feasibility check by tweaking the + /// snapshot which was used to compute the solution and remove one of the targets from the + /// snapshot. NOTE: we expect that the `solution` was generated based on the current snapshot + /// state. + fn ensure_solution_invalid( + solution: &SolutionOf, + ) -> Result<(), &'static str> { + let new_count_targets = solution.unique_targets().len().saturating_sub(1); + + // remove a target from the snapshot to invalidate solution. + let _ = PalletCore::::create_targets_snapshot_inner(new_count_targets as u32) + .map_err(|_| "error regenerating the target snapshot")?; + + Ok(()) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/helpers.rs b/substrate/frame/election-provider-multi-block/src/helpers.rs new file mode 100644 index 0000000000000..61c6f0b907ae3 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/helpers.rs @@ -0,0 +1,331 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! Some helper functions/macros for this crate. + +use crate::{ + types::{AllTargetPagesOf, AllVoterPagesOf, MaxWinnersPerPageOf, MinerVoterOf}, + SolutionTargetIndexOf, SolutionVoterIndexOf, +}; +use frame_election_provider_support::{PageIndex, VoteWeight}; +use frame_support::{traits::Get, BoundedVec}; +use sp_runtime::SaturatedConversion; +use sp_std::{cmp::Reverse, collections::btree_map::BTreeMap, vec, vec::Vec}; + +#[macro_export] +macro_rules! log { + ($level:tt, $pattern:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: $crate::LOG_TARGET, + concat!("[#{:?}]: 🎯🎯🎯 🗳 ", $pattern), >::block_number() $(, $values)* + ) + }; +} + +macro_rules! sublog { + ($level:tt, $sub_pallet:tt, $pattern:expr $(, $values:expr)* $(,)?) => { + #[cfg(not(feature = "std"))] + log!($level, $pattern $(, $values )*); + #[cfg(feature = "std")] + log::$level!( + target: format!("{}::{}", $crate::LOG_TARGET, $sub_pallet).as_ref(), + concat!("[#{:?}]: 🎯🎯🎯 🗳 ", $pattern), >::block_number() $(, $values )* + ) + }; +} + +use crate::unsigned::miner::Config as MinerConfig; + +/// Generate a btree-map cache of the voters and their indices within the provided `snapshot`. +/// +/// This does not care about pagination. `snapshot` might be a single page or the entire blob of +/// voters. +/// +/// This can be used to efficiently build index getter closures. +pub fn generate_voter_cache>( + snapshot: &BoundedVec, AnyBound>, +) -> BTreeMap { + let mut cache: BTreeMap = BTreeMap::new(); + snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { + let _existed = cache.insert(x.clone(), i); + // if a duplicate exists, we only consider the last one. Defensive only, should never + // happen. + debug_assert!(_existed.is_none()); + }); + + cache +} + +pub fn generate_target_cache( + snapshot: &Vec, +) -> BTreeMap { + let mut cache: BTreeMap = BTreeMap::new(); + snapshot.iter().enumerate().for_each(|(i, x)| { + let _existed = cache.insert(x.clone(), i); + // if a duplicate exists, we only consider the last one. Defensive only, should never + // happen. + debug_assert!(_existed.is_none()); + }); + + cache +} + +pub fn generate_voter_staked_cache( + snapshot: &Vec<&MinerVoterOf>, +) -> BTreeMap { + let mut cache: BTreeMap = BTreeMap::new(); + snapshot.into_iter().enumerate().for_each(|(i, (x, _, _))| { + let _existed = cache.insert(x.clone(), i); + // if a duplicate exists, we only consider the last one. Defensive only, should never + // happen. + debug_assert!(_existed.is_none()); + }); + cache +} + +/// Generate an efficient closure of voters and the page in which they live in. +/// +/// The bucketing of voters into a page number is based on their position in the snapshot's page. +pub fn generate_voter_page_fn( + paged_snapshot: &AllVoterPagesOf, +) -> impl Fn(&T::AccountId) -> Option { + let mut cache: BTreeMap = BTreeMap::new(); + paged_snapshot + .iter() + .enumerate() + .map(|(page, whatever)| (page.saturated_into::(), whatever)) + .for_each(|(page, page_voters)| { + page_voters.iter().for_each(|(v, _, _)| { + let _existed = cache.insert(v.clone(), page); + // if a duplicate exists, we only consider the last one. Defensive only, should + // never happen. + debug_assert!(_existed.is_none()); + }); + }); + + move |who| cache.get(who).copied() +} + +pub fn generate_target_page_fn( + paged_snapshot: &AllTargetPagesOf, +) -> impl Fn(&T::AccountId) -> Option { + let mut cache: BTreeMap = BTreeMap::new(); + paged_snapshot + .iter() + .enumerate() + .map(|(page, whatever)| (page.saturated_into::(), whatever)) + .for_each(|(page, page_voters)| { + page_voters.iter().for_each(|t| { + let _existed = cache.insert(t.clone(), page); + // if a duplicate exists, we only consider the last one. Defensive only, should + // never happen. + debug_assert!(_existed.is_none()); + }); + }); + move |who| cache.get(who).copied() +} + +/// stake. +/// +/// The bucketing of voters into a page number is based on their relative stake in the assignments +/// set (the larger the stake, the higher the page). +pub fn generate_voter_page_stake_fn( + paged_snapshot: &AllVoterPagesOf, +) -> impl Fn(&T::AccountId) -> Option { + let mut cache: BTreeMap = BTreeMap::new(); + let mut sorted_by_weight: Vec<(VoteWeight, T::AccountId)> = vec![]; + + // sort voter stakes. + let _ = paged_snapshot.to_vec().iter().flatten().for_each(|voter| { + let pos = sorted_by_weight + .binary_search_by_key(&Reverse(&voter.1), |(weight, _)| Reverse(weight)) + .unwrap_or_else(|pos| pos); + sorted_by_weight.insert(pos, (voter.1, voter.0.clone())); + }); + + sorted_by_weight.iter().enumerate().for_each(|(idx, voter)| { + let page = idx + .saturating_div(MaxWinnersPerPageOf::::get() as usize) + .min(T::Pages::get() as usize); + let _existed = cache.insert(voter.1.clone(), page as PageIndex); + debug_assert!(_existed.is_none()); + }); + + move |who| cache.get(who).copied() +} + +/// Create a function that returns the index of a voter in the snapshot. +/// +/// The returning index type is the same as the one defined in `T::Solution::Voter`. +/// +/// ## Warning +/// +/// Note that this will represent the snapshot data from which the `cache` is generated. +pub fn voter_index_fn( + cache: &BTreeMap, +) -> impl Fn(&T::AccountId) -> Option> + '_ { + move |who| { + cache + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + } +} + +/// Create a function that returns the index of a voter in the snapshot. +/// +/// Same as [`voter_index_fn`] but the returned function owns all its necessary data; nothing is +/// borrowed. +pub fn voter_index_fn_owned( + cache: BTreeMap, +) -> impl Fn(&T::AccountId) -> Option> { + move |who| { + cache + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + } +} + +pub fn target_index_fn_owned( + cache: BTreeMap, +) -> impl Fn(&T::AccountId) -> Option> { + move |who| { + cache + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + } +} + +/// Create a function that returns the index of a target in the snapshot. +/// +/// The returned index type is the same as the one defined in `T::Solution::Target`. +/// +/// Note: to the extent possible, the returned function should be cached and reused. Producing that +/// function requires a `O(n log n)` data transform. Each invocation of that function completes +/// in `O(log n)`. +pub fn target_index_fn( + snapshot: &Vec, +) -> impl Fn(&T::AccountId) -> Option> + '_ { + let cache: BTreeMap<_, _> = + snapshot.iter().enumerate().map(|(idx, account_id)| (account_id, idx)).collect(); + move |who| { + cache + .get(who) + .and_then(|i| >>::try_into(*i).ok()) + } +} + +/// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter +/// account using a linearly indexible snapshot. +pub fn voter_at_fn( + snapshot: &Vec>, +) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { + move |i| { + as TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot.get(i).map(|(x, _, _)| x).cloned()) + } +} + +/// Create a function that can map a target index ([`SolutionTargetIndexOf`]) to the actual target +/// account using a linearly indexible snapshot. +pub fn target_at_fn( + snapshot: &Vec, +) -> impl Fn(SolutionTargetIndexOf) -> Option + '_ { + move |i| { + as TryInto>::try_into(i) + .ok() + .and_then(|i| snapshot.get(i).cloned()) + } +} + +/// Same as [`voter_index_fn`], but the returning index is converted into usize, if possible. +/// +/// ## Warning +/// +/// Note that this will represent the snapshot data from which the `cache` is generated. +pub fn voter_index_fn_usize( + cache: &BTreeMap, +) -> impl Fn(&T::AccountId) -> Option + '_ { + move |who| cache.get(who).cloned() +} + +pub fn target_index_fn_usize( + cache: &BTreeMap, +) -> impl Fn(&T::AccountId) -> Option + '_ { + move |who| cache.get(who).cloned() +} + +/// Create a function to get the stake of a voter. +pub fn stake_of_fn<'a, T: MinerConfig, AnyBound: Get>( + snapshot: &'a BoundedVec, AnyBound>, + cache: &'a BTreeMap, +) -> impl Fn(&T::AccountId) -> VoteWeight + 'a { + move |who| { + if let Some(index) = cache.get(who) { + snapshot.get(*index).map(|(_, x, _)| x).cloned().unwrap_or_default() + } else { + 0 + } + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use crate::mock::*; + + use sp_runtime::bounded_vec; + + type TargetsPerSnapshotPageOf = ::TargetSnapshotPerBlock; + + #[test] + fn paged_targets_indexing_works() { + ExtBuilder::default().build_and_execute(|| { + let all_target_pages: BoundedVec< + BoundedVec>, + ::Pages, + > = bounded_vec![ + bounded_vec![], // page 0 + bounded_vec![11, 61], // page 1 + bounded_vec![51, 101, 31, 41, 21, 81, 71, 91], // page 2 + ]; + + // flatten all targets. + let all_targets = all_target_pages.iter().cloned().flatten().collect::>(); + + // `targets_index_fn` get the snapshot page of the target. + let targets_index_fn = generate_target_page_fn::(&all_target_pages); + let all_targets_cache = generate_target_cache::(&all_targets); + let target_index = target_index_fn_usize::(&all_targets_cache); + + // check that the `targets_index_page` is correct. + for (page, targets) in all_target_pages.iter().enumerate() { + for t in targets { + assert_eq!(targets_index_fn(&t), Some(page as PageIndex)); + } + } + + // check that the `generate_target_cache` ad `target_index_fn_usize` return the correct + // btree cache/idx. + for (idx, target) in all_targets.iter().enumerate() { + assert_eq!(all_targets_cache.get(target), Some(idx).as_ref()); + assert_eq!(target_index(target), Some(idx)); + } + }) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs new file mode 100644 index 0000000000000..fd1b7cc05f0ac --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/lib.rs @@ -0,0 +1,1139 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Multi-phase, multi-block election provider pallet +//! +//! This pallet manages the NPoS election across its different phases, with the ability to accept +//! both on-chain and off-chain solutions. The off-chain solutions may be submitted as a signed or +//! unsigned transaction. Crucially, supports paginated, multi-block elections. The goal of +//! supporting paged elections is to scale the elections linearly with the number of blocks +//! allocated to the election. +//! +//! **PoV-friendly**: The work performed in a block by this pallet must be measurable and the time +//! and computation required per block must be deterministic with regards to the number of voters, +//! targets and any other configurations that are set apriori. These assumptions make this pallet +//! suitable to run on a parachain. +//! +//! ## Pallet organization and sub-pallets +//! +//! This pallet consists of a `core` pallet and multiple sub-pallets. Conceptually, the pallets have +//! a hierarquical relationship, where the `core` pallet sets and manages shared state between all +//! pallets. Its "child" pallets can not depend on the `core` pallet and iteract with it through +//! trait interfaces: +//! +//!```text +//! pallet-core +//! | +//! | +//! - pallet-verifier +//! | +//! - pallet-signed +//! | +//! - pallet-unsigned +//! ``` +//! +//! Each sub-pallet has a specific set of tasks and implement one or more interfaces to expose their +//! functionality to the core pallet: +//! - The [`verifier`] pallet provides an implementation of the [`verifier::Verifier`] trait, which +//! exposes the functionality to verify NPoS solutions in a multi-block context. In addition, it +//! implements [`verifier::AsyncVerifier`] which verifies multi-paged solution asynchronously. +//! - The [`signed`] pallet implements the signed phase, where off-chain entities commit to and +//! submit their election solutions. This pallet implements the +//! [`verifier::SolutionDataProvider`], which is used by the [`verifier`] pallet to fetch solution +//! data. +//! - The [`unsigned`] pallet implements the unsigned phase, where block authors can calculate and +//! submit through inherent paged solutions. This pallet also implements the +//! [`verifier::SolutionDataProvider`] interface. +//! +//! ### Pallet ordering +//! +//! Due to the assumptions of when the `on_initialize` hook must be called by the executor for the +//! core pallet and each sub-pallets, it is crucial the the pallets are ordered correctly in the +//! construct runtime. The ordering must be the following: +//! +//! ```text +//! 1. pallet-core +//! 2. pallet-verifier +//! 3. pallet-signed +//! 4. pallet-unsigned +//! ``` +//! +//! ## Election Phases +//! +//! This pallet manages the election phases which signal to the other sub-pallets which actions to +//! take at a given block. The election phases are the following: +//! +//! ```text +//! // ----------- ----------- -------------- ------------ -------- +//! // | | | | | | | +//! // Off Snapshot Signed SignedValidation Unsigned elect() Export +//! ``` +//! +//! Each phase duration depends on the estimate block number election, which can be fetched from +//! [`pallet::Config::DataProvider`]. +//! +//! > to-finish + +#![cfg_attr(not(feature = "std"), no_std)] +// TODO: remove +#![allow(dead_code)] + +use frame_election_provider_support::{ + bounds::ElectionBoundsBuilder, BoundedSupportsOf, ElectionDataProvider, ElectionProvider, + LockableElectionDataProvider, PageIndex, VoterOf, Weight, +}; +use frame_support::{ + defensive, ensure, + traits::{Defensive, DefensiveSaturating, Get}, + BoundedVec, +}; +use sp_runtime::traits::Zero; + +use frame_system::pallet_prelude::BlockNumberFor; + +#[macro_use] +pub mod helpers; + +pub mod signed; +pub mod types; +pub mod unsigned; +pub mod verifier; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +mod mock; + +pub use pallet::*; +pub use types::*; + +pub use crate::{unsigned::miner, verifier::Verifier, weights::WeightInfo}; + +/// Internal crate re-exports to use across benchmarking and tests. +#[cfg(any(test, feature = "runtime-benchmarks"))] +use crate::verifier::Pallet as PalletVerifier; + +const LOG_TARGET: &'static str = "runtime::multiblock-election"; + +/// Page configured for the election. +pub type PagesOf = ::Pages; + +/// Trait defining the benchmarking configs. +pub trait BenchmarkingConfig { + /// Range of voters registerd in the system. + const VOTERS: u32; + /// Range of targets registered in the system. + const TARGETS: u32; + /// Range of voters per snapshot page. + const VOTERS_PER_PAGE: [u32; 2]; + /// Range of targets per snapshot page. + const TARGETS_PER_PAGE: [u32; 2]; +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + + use super::*; + use frame_support::{ + pallet_prelude::{ValueQuery, *}, + sp_runtime::Saturating, + Twox64Concat, + }; + use frame_system::pallet_prelude::BlockNumberFor; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + + /// Duration of the signed phase; + #[pallet::constant] + type SignedPhase: Get>; + + /// Duration of the unsigned phase; + #[pallet::constant] + type UnsignedPhase: Get>; + + /// Duration of the signed validation phase. + /// + /// The duration of this phase SHOULD NOT be less than `T::Pages` and there is no point in + /// it being more than the maximum number of pages per submission. + #[pallet::constant] + type SignedValidationPhase: Get>; + + /// The number of blocks that the election should be ready before the election deadline. + #[pallet::constant] + type Lookhaead: Get>; + + /// The number of snapshot voters to fetch per block. + #[pallet::constant] + type VoterSnapshotPerBlock: Get; + + /// The number of snapshot targets to fetch per block. + #[pallet::constant] + type TargetSnapshotPerBlock: Get; + + /// Maximum number of supports (i.e. winners/validators/targets) that can be represented + /// in one page of a solution. + type MaxWinnersPerPage: Get; + + /// Maximum number of voters that can support a single target, across ALL the solution + /// pages. Thus, this can only be verified when processing the last solution page. + /// + /// This limit must be set so that the memory limits of the rest of the system are + /// respected. + type MaxBackersPerWinner: Get; + + /// The number of pages. + /// + /// A solution may contain at MOST this many pages. + #[pallet::constant] + type Pages: Get; + + /// The limit number of blocks that the `Phase::Export` will be open for. + /// + /// The export phase will terminate if it has been open for `T::ExportPhaseLimit` blocks or + /// the `EPM::call(0)` is called. + type ExportPhaseLimit: Get>; + + /// Something that will provide the election data. + type DataProvider: LockableElectionDataProvider< + AccountId = Self::AccountId, + BlockNumber = BlockNumberFor, + >; + + // The miner configuration. + type MinerConfig: miner::Config< + AccountId = AccountIdOf, + Pages = Self::Pages, + MaxVotesPerVoter = ::MaxVotesPerVoter, + TargetSnapshotPerBlock = Self::TargetSnapshotPerBlock, + VoterSnapshotPerBlock = Self::VoterSnapshotPerBlock, + MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxBackersPerWinner = Self::MaxBackersPerWinner, + >; + + /// Something that implements a fallback election. + /// + /// This provider must run the election in one block, thus it has at most 1 page. + type Fallback: ElectionProvider< + AccountId = Self::AccountId, + BlockNumber = BlockNumberFor, + DataProvider = Self::DataProvider, + MaxWinnersPerPage = ::MaxWinnersPerPage, + MaxBackersPerWinner = ::MaxBackersPerWinner, + Pages = ConstU32<1>, + >; + + /// Something that implements an election solution verifier. + type Verifier: verifier::Verifier< + AccountId = Self::AccountId, + Solution = SolutionOf, + > + verifier::AsyncVerifier; + + /// Benchmarking configurations for this and sub-pallets. + type BenchmarkingConfig: BenchmarkingConfig; + + /// The weights for this pallet. + type WeightInfo: WeightInfo; + } + + // Expose miner configs over the metadata such that they can be re-implemented. + #[pallet::extra_constants] + impl Pallet { + #[pallet::constant_name(MinerMaxVotesPerVoter)] + fn max_votes_per_voter() -> u32 { + ::MaxVotesPerVoter::get() + } + + #[pallet::constant_name(MinerMaxBackersPerWinner)] + fn max_backers_per_winner() -> u32 { + ::MaxBackersPerWinner::get() + } + + #[pallet::constant_name(MinerMaxWinnersPerPage)] + fn max_winners_per_page() -> u32 { + ::MaxWinnersPerPage::get() + } + } + + /// Election failure strategy. + #[pallet::storage] + pub(crate) type ElectionFailure = + StorageValue<_, ElectionFailureStrategy, ValueQuery>; + + /// Current phase. + #[pallet::storage] + pub(crate) type CurrentPhase = StorageValue<_, Phase>, ValueQuery>; + + /// Current round + #[pallet::storage] + pub(crate) type Round = StorageValue<_, u32, ValueQuery>; + + /// Paginated target snapshot. + #[pallet::storage] + pub(crate) type PagedTargetSnapshot = + StorageMap<_, Twox64Concat, PageIndex, BoundedVec>; + + /// Paginated voter snapshot. + #[pallet::storage] + pub(crate) type PagedVoterSnapshot = + StorageMap<_, Twox64Concat, PageIndex, VoterPageOf>; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// There was a phase transition in a given round. + PhaseTransitioned { + from: Phase>, + to: Phase>, + round: u32, + }, + } + + #[pallet::error] + pub enum Error {} + + #[pallet::call] + impl Pallet {} + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(now: BlockNumberFor) -> Weight { + // ---------- ---------- ---------- ----------- ---------- -------- + // | | | | | | | + // Off Snapshot (Signed SigValid) Unsigned Export elect() + + use sp_runtime::traits::One; + + let export_deadline = T::ExportPhaseLimit::get().saturating_add(T::Lookhaead::get()); + let unsigned_deadline = export_deadline.saturating_add(T::UnsignedPhase::get()); + let signed_validation_deadline = + unsigned_deadline.saturating_add(T::SignedValidationPhase::get()); + let signed_deadline = signed_validation_deadline.saturating_add(T::SignedPhase::get()); + let snapshot_deadline = signed_deadline + .saturating_add(T::Pages::get().into()) + .saturating_add(One::one()); + + let next_election = T::DataProvider::next_election_prediction(now) + .saturating_sub(T::Lookhaead::get()) + .max(now); + + let remaining_blocks = next_election - now; + let current_phase = Self::current_phase(); + + log!( + trace, + "now {:?} - current phase {:?} | \ + snapshot_deadline: {:?} (at #{:?}), signed_deadline: {:?} (at #{:?}), \ + signed_validation_deadline: {:?} (at #{:?}), unsigned_deadline: {:?} (at #{:?}) \ + export_deadline: {:?} (at #{:?}) - [next election at #{:?}, remaining: {:?}]", + now, + current_phase, + snapshot_deadline, + next_election.saturating_sub(snapshot_deadline), + signed_deadline, + next_election.saturating_sub(signed_deadline), + signed_validation_deadline, + next_election.saturating_sub(signed_validation_deadline), + unsigned_deadline, + next_election.saturating_sub(unsigned_deadline), + export_deadline, + next_election.saturating_sub(export_deadline), + next_election, + remaining_blocks, + ); + + match current_phase { + // start snapshot. + Phase::Off + if remaining_blocks <= snapshot_deadline && + remaining_blocks > signed_deadline => + // allocate one extra block for the target snapshot. + Self::try_progress_snapshot(T::Pages::get() + 1), + + // continue snapshot. + Phase::Snapshot(x) if x > 0 => Self::try_progress_snapshot(x.saturating_sub(1)), + + // start unsigned phase if snapshot is ready and signed phase is disabled. + Phase::Snapshot(0) if T::SignedPhase::get().is_zero() => { + Self::phase_transition(Phase::Unsigned(now)); + T::WeightInfo::on_phase_transition() + }, + + // start signed phase. The `signed` pallet will take further actions now. + Phase::Snapshot(0) + if remaining_blocks <= signed_deadline && + remaining_blocks > signed_validation_deadline => + Self::start_signed_phase(), + + // start signed validation. The `signed` pallet will take further actions now. + Phase::Signed + if remaining_blocks <= signed_validation_deadline && + remaining_blocks > unsigned_deadline => + { + Self::phase_transition(Phase::SignedValidation(now)); + T::WeightInfo::on_phase_transition() + }, + + // start unsigned phase. The `unsigned` pallet will take further actions now. + Phase::Signed | Phase::SignedValidation(_) | Phase::Snapshot(0) + if remaining_blocks <= unsigned_deadline && remaining_blocks > Zero::zero() => + { + Self::phase_transition(Phase::Unsigned(now)); + T::WeightInfo::on_phase_transition() + }, + + // EPM is "serving" the staking pallet with the election results. + Phase::Export(started_at) => Self::do_export_phase(now, started_at), + + _ => T::WeightInfo::on_initialize_do_nothing(), + } + } + + fn integrity_test() { + // the signed validator phase must not be less than the number of pages of a + // submission. + assert!( + T::SignedValidationPhase::get() <= T::Pages::get().into(), + "signed validaton phase ({:?}) should not be less than the number of pages per submission ({:?})", + T::SignedValidationPhase::get(), + T::Pages::get(), + ); + } + } + + #[pallet::pallet] + pub struct Pallet(PhantomData); +} + +/// Wrapper struct for working with snapshots. +/// +/// It manages the following storage items: +/// +/// - [`PagedVoterSnapshot`]: Paginated map of voters. +/// - [`PagedTargetSnapshot`]: Paginated map of targets. +/// +/// To ensure correctness and data consistency, all the reads and writes to storage items related +/// to the snapshot and "wrapped" by this struct must be performed through the methods exposed by +/// the implementation of [`Snapshot`]. +pub(crate) struct Snapshot(sp_std::marker::PhantomData); +impl Snapshot { + /// Returns the targets snapshot. + /// + /// TODO(gpestana): consider paginating targets (update: a lot of shenenigans on the assignments + /// converstion and target/voter index. Hard to ensure that no more than 1 snapshot page is + /// fetched when both voter and target snapshots are paged.) + fn targets() -> Option> { + PagedTargetSnapshot::::get(Pallet::::lsp()) + } + + /// Sets a page of targets in the snapshot's storage. + fn set_targets(targets: BoundedVec) { + PagedTargetSnapshot::::insert(Pallet::::lsp(), targets); + } + + /// Returns whether the target snapshot exists in storage. + fn targets_snapshot_exists() -> bool { + !PagedTargetSnapshot::::iter_keys().count().is_zero() + } + + /// Return the number of desired targets, which is defined by [`T::DataProvider`]. + fn desired_targets() -> Option { + match T::DataProvider::desired_targets() { + Ok(desired) => Some(desired), + Err(err) => { + defensive!( + "error fetching the desired targets from the election data provider {}", + err + ); + None + }, + } + } + + /// Returns the voters of a specific `page` index in the current snapshot. + fn voters(page: PageIndex) -> Option> { + PagedVoterSnapshot::::get(page) + } + + /// Sets a single page of voters in the snapshot's storage. + fn set_voters( + page: PageIndex, + voters: BoundedVec, T::VoterSnapshotPerBlock>, + ) { + PagedVoterSnapshot::::insert(page, voters); + } + + /// Clears all data related to a snapshot. + /// + /// At the end of a round, all the snapshot related data must be cleared and the election phase + /// has transitioned to `Phase::Off`. + fn kill() { + let _ = PagedVoterSnapshot::::clear(u32::MAX, None); + let _ = PagedTargetSnapshot::::clear(u32::MAX, None); + + debug_assert_eq!(>::get(), Phase::Off); + } + + #[allow(dead_code)] + #[cfg(any(test, debug_assertions))] + pub(crate) fn ensure() -> Result<(), &'static str> { + let pages = T::Pages::get(); + ensure!(pages > 0, "number pages must be higer than 0."); + + // target snapshot exists (one page only); + ensure!(Self::targets().is_some(), "target snapshot does not exist."); + + // ensure that snapshot pages exist as expected. + for page in (crate::Pallet::::lsp()..=crate::Pallet::::msp()).rev() { + ensure!( + Self::voters(page).is_some(), + "at least one page of the snapshot does not exist" + ); + } + + Ok(()) + } +} + +impl Pallet { + /// Return the current election phase. + pub fn current_phase() -> Phase> { + >::get() + } + + /// Return the current election round. + pub fn current_round() -> u32 { + >::get() + } + + /// Phase transition helper. + pub(crate) fn phase_transition(to: Phase>) { + Self::deposit_event(Event::PhaseTransitioned { + from: >::get(), + to, + round: >::get(), + }); + >::put(to); + } + + /// Return the most significant page of the snapshot. + /// + /// Based on the contract with `ElectionDataProvider`, tis is the first page to be filled. + pub fn msp() -> PageIndex { + T::Pages::get().checked_sub(1).defensive_unwrap_or_default() + } + + /// Return the least significant page of the snapshot. + /// + /// Based on the contract with `ElectionDataProvider`, tis is the last page to be filled. + pub fn lsp() -> PageIndex { + Zero::zero() + } + + /// Creates and stores the target snapshot. + /// + /// Note: currently, the pallet uses single page target page only. + fn create_targets_snapshot() -> Result> { + let stored_count = Self::create_targets_snapshot_inner(T::TargetSnapshotPerBlock::get())?; + log!(info, "created target snapshot with {} targets.", stored_count); + + Ok(stored_count) + } + + fn create_targets_snapshot_inner(targets_per_page: u32) -> Result> { + // set target count bound as the max number of targets per block. + let bounds = ElectionBoundsBuilder::default() + .targets_count(targets_per_page.into()) + .build() + .targets; + + let targets: BoundedVec<_, T::TargetSnapshotPerBlock> = + T::DataProvider::electable_targets(bounds, Zero::zero()) + .and_then(|t| { + t.try_into().map_err(|e| { + log!(error, "too many targets? err: {:?}", e); + "too many targets returned by the data provider." + }) + }) + .map_err(|e| { + log!(info, "error fetching electable targets from data provider: {:?}", e); + ElectionError::::DataProvider + })?; + + let count = targets.len() as u32; + Snapshot::::set_targets(targets); + + Ok(count) + } + + /// Creates and store a single page of the voter snapshot. + fn create_voters_snapshot(remaining_pages: u32) -> Result> { + ensure!(remaining_pages < T::Pages::get(), ElectionError::::RequestedPageExceeded); + + let paged_voters_count = + Self::create_voters_snapshot_inner(remaining_pages, T::VoterSnapshotPerBlock::get())?; + log!(info, "created voter snapshot with {} voters.", paged_voters_count); + + Ok(paged_voters_count) + } + + fn create_voters_snapshot_inner( + remaining_pages: u32, + voters_per_page: u32, + ) -> Result> { + // set voter count bound as the max number of voters per page. + let bounds = ElectionBoundsBuilder::default() + .voters_count(voters_per_page.into()) + .build() + .voters; + + let paged_voters: BoundedVec<_, T::VoterSnapshotPerBlock> = + T::DataProvider::electing_voters(bounds, remaining_pages) + .and_then(|v| { + v.try_into().map_err(|_| "too many voters returned by the data provider") + }) + .map_err(|_| ElectionError::::DataProvider)?; + + let count = paged_voters.len() as u32; + Snapshot::::set_voters(remaining_pages, paged_voters); + + Ok(count) + } + + /// Tries to progress the snapshot. + /// + /// The first (and only) target page is fetched from the [`DataProvider`] at the same block when + /// the msp of the voter snaphot. + fn try_progress_snapshot(remaining_pages: PageIndex) -> Weight { + let _ = ::set_lock(); + + debug_assert!( + CurrentPhase::::get().is_snapshot() || + !Snapshot::::targets_snapshot_exists() && + remaining_pages == T::Pages::get() + 1, + ); + + if !Snapshot::::targets_snapshot_exists() { + // first block for single target snapshot. + match Self::create_targets_snapshot() { + Ok(target_count) => { + log!(info, "target snapshot created with {} targets", target_count); + Self::phase_transition(Phase::Snapshot(remaining_pages.saturating_sub(1))); + T::WeightInfo::create_targets_snapshot_paged(T::TargetSnapshotPerBlock::get()) + }, + Err(err) => { + log!(error, "error preparing targets snapshot: {:?}", err); + // TODO: T::WeightInfo::snapshot_error(); + Weight::default() + }, + } + } else { + // progress voter snapshot. + match Self::create_voters_snapshot(remaining_pages) { + Ok(voter_count) => { + log!( + info, + "voter snapshot progressed: page {} with {} voters", + remaining_pages, + voter_count, + ); + Self::phase_transition(Phase::Snapshot(remaining_pages)); + T::WeightInfo::create_voters_snapshot_paged(T::VoterSnapshotPerBlock::get()) + }, + Err(err) => { + log!(error, "error preparing voter snapshot: {:?}", err); + // TODO: T::WeightInfo::snapshot_error(); + Weight::default() + }, + } + } + } + + pub(crate) fn start_signed_phase() -> Weight { + // done with the snapshot, release the data provider lock. + ::unlock(); + Self::phase_transition(Phase::Signed); + + T::WeightInfo::on_initialize_start_signed() + } + + pub(crate) fn do_export_phase(now: BlockNumberFor, started_at: BlockNumberFor) -> Weight { + if now > started_at + T::ExportPhaseLimit::get() { + log!( + error, + "phase `Export` has been open for too long ({:?} blocks). election round failed.", + T::ExportPhaseLimit::get(), + ); + + match ElectionFailure::::get() { + ElectionFailureStrategy::Restart => Self::reset_round(), + ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), + } + } + + T::WeightInfo::on_initialize_start_export() + } + + /// Performs all tasks required after a successful election: + /// + /// 1. Increment round. + /// 2. Change phase to [`Phase::Off`]. + /// 3. Clear all snapshot data. + fn rotate_round() { + >::mutate(|r| r.defensive_saturating_accrue(1)); + Self::phase_transition(Phase::Off); + + Snapshot::::kill(); + ::kill(); + } + + /// Performs all tasks required after an unsuccessful election: + /// + /// 1. Change phase to [`Phase::Off`]. + /// 2. Clear all snapshot data. + fn reset_round() { + Self::phase_transition(Phase::Off); + Snapshot::::kill(); + + ::kill(); + } +} + +impl ElectionProvider for Pallet { + type AccountId = T::AccountId; + type BlockNumber = BlockNumberFor; + type Error = ElectionError; + type MaxWinnersPerPage = ::MaxWinnersPerPage; + type MaxBackersPerWinner = ::MaxBackersPerWinner; + type Pages = T::Pages; + type DataProvider = T::DataProvider; + + /// Important note: we do exect the caller of `elect` to reach page 0. + fn elect(remaining: PageIndex) -> Result, Self::Error> { + T::Verifier::get_queued_solution(remaining) + .ok_or(ElectionError::::SupportPageNotAvailable(remaining)) + .or_else(|err| { + log!( + error, + "elect(): (page {:?}) election provider failed due to {:?}, trying fallback.", + remaining, + err + ); + T::Fallback::elect(remaining).map_err(|fe| ElectionError::::Fallback(fe)) + }) + .map(|supports| { + if remaining.is_zero() { + log!(info, "elect(): provided the last supports page, rotating round."); + Self::rotate_round(); + } else { + // Phase::Export is on while the election is calling all pages of `elect`. + if !Self::current_phase().is_export() { + let now = >::block_number(); + Self::phase_transition(Phase::Export(now)); + } + } + supports.into() + }) + .map_err(|err| { + log!(error, "elect(): fetching election page {} and fallback failed.", remaining); + + match ElectionFailure::::get() { + // force emergency phase for testing. + ElectionFailureStrategy::Restart => Self::reset_round(), + ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), + } + err + }) + } +} + +#[cfg(test)] +mod phase_transition { + use super::*; + use crate::mock::*; + + use frame_support::assert_ok; + + #[test] + fn single_page() { + // ---------- ---------- -------------- ----------- + // | | | | | + // Snapshot Signed SignedValidation Unsigned elect() + let (mut ext, _) = ExtBuilder::default() + .pages(1) + .signed_phase(3) + .validate_signed_phase(1) + .lookahead(0) + .build_offchainify(1); + + ext.execute_with(|| { + assert_eq!(System::block_number(), 0); + assert_eq!(Pages::get(), 1); + assert_eq!(>::get(), 0); + assert_eq!(>::get(), Phase::Off); + + let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number() + ); + assert_eq!(next_election, 30); + + // representing the blocknumber when the phase transition happens. + let export_deadline = next_election - (ExportPhaseLimit::get() + Lookhaead::get()); + let expected_unsigned = export_deadline - UnsignedPhase::get(); + let expected_validate = expected_unsigned - SignedValidationPhase::get(); + let expected_signed = expected_validate - SignedPhase::get(); + let expected_snapshot = expected_signed - Pages::get() as u64; + + // tests transition phase boundaries. + roll_to(expected_snapshot); + assert_eq!(>::get(), Phase::Snapshot(Pages::get() - 1)); + + roll_to(expected_signed); + assert_eq!(>::get(), Phase::Signed); + + roll_to(expected_validate); + let start_validate = System::block_number(); + assert_eq!(>::get(), Phase::SignedValidation(start_validate)); + + roll_to(expected_unsigned); + let start_unsigned = System::block_number(); + assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); + + roll_to(next_election + 1); + assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); + + // unsigned phase until elect() is called. + roll_to(next_election + 3); + assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); + + assert_ok!(MultiPhase::elect(0)); + + // election done, go to off phase. + assert_eq!(>::get(), Phase::Off); + }) + } + + #[test] + fn multi_page() { + let (mut ext, _) = ExtBuilder::default() + .pages(2) + .signed_phase(3) + .validate_signed_phase(1) + .lookahead(0) + .build_offchainify(1); + + ext.execute_with(|| { + assert_eq!(System::block_number(), 0); + assert_eq!(Pages::get(), 2); + assert_eq!(>::get(), 0); + assert_eq!(>::get(), Phase::Off); + + let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number() + ); + assert_eq!(next_election, 30); + + // representing the blocknumber when the phase transition happens. + let export_deadline = next_election - (ExportPhaseLimit::get() + Lookhaead::get()); + let expected_unsigned = export_deadline - UnsignedPhase::get(); + let expected_validate = expected_unsigned - SignedValidationPhase::get(); + let expected_signed = expected_validate - SignedPhase::get(); + let expected_snapshot = expected_signed - Pages::get() as u64; + + // two blocks for snapshot. + roll_to(expected_snapshot); + assert_eq!(>::get(), Phase::Snapshot(Pages::get() - 1)); + + roll_to(expected_snapshot + 1); + assert_eq!(>::get(), Phase::Snapshot(0)); + + roll_to(expected_signed); + assert_eq!(>::get(), Phase::Signed); + + roll_to(expected_signed + 1); + assert_eq!(>::get(), Phase::Signed); + + // two blocks for validate signed. + roll_to(expected_validate); + let start_validate = System::block_number(); + assert_eq!(>::get(), Phase::SignedValidation(start_validate)); + + // now in unsigned until elect() is called. + roll_to(expected_validate + 2); + let start_unsigned = System::block_number(); + assert_eq!(>::get(), Phase::Unsigned(start_unsigned - 1)); + + }) + } + + #[test] + fn emergency_phase_works() { + let (mut ext, _) = ExtBuilder::default().build_offchainify(1); + ext.execute_with(|| { + let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number() + ); + + // if election fails, enters in emergency phase. + ElectionFailure::::set(ElectionFailureStrategy::Emergency); + + compute_snapshot_checked(); + roll_to(next_election); + + // election will fail due to inexistent solution. + assert!(MultiPhase::elect(Pallet::::msp()).is_err()); + // thus entering in emergency phase. + assert_eq!(>::get(), Phase::Emergency); + }) + } + + #[test] + fn restart_after_elect_fails_works() { + let (mut ext, _) = ExtBuilder::default().build_offchainify(1); + ext.execute_with(|| { + let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number() + ); + + // if election fails, restart the election round. + ElectionFailure::::set(ElectionFailureStrategy::Restart); + + compute_snapshot_checked(); + roll_to(next_election); + + // election will fail due to inexistent solution. + assert!(MultiPhase::elect(Pallet::::msp()).is_err()); + // thus restarting from Off phase. + assert_eq!(>::get(), Phase::Off); + }) + } +} + +#[cfg(test)] +mod snapshot { + use super::*; + use crate::mock::*; + + use frame_support::{assert_noop, assert_ok}; + + #[test] + fn setters_getters_work() { + ExtBuilder::default().build_and_execute(|| { + let v = BoundedVec::<_, _>::try_from(vec![]).unwrap(); + + assert!(Snapshot::::targets().is_none()); + assert!(Snapshot::::voters(0).is_none()); + assert!(Snapshot::::voters(1).is_none()); + + Snapshot::::set_targets(v.clone()); + assert!(Snapshot::::targets().is_some()); + + Snapshot::::kill(); + assert!(Snapshot::::targets().is_none()); + assert!(Snapshot::::voters(0).is_none()); + assert!(Snapshot::::voters(1).is_none()); + }) + } + + #[test] + fn targets_voters_snapshot_boundary_checks_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Pages::get(), 3); + assert_eq!(MultiPhase::msp(), 2); + assert_eq!(MultiPhase::lsp(), 0); + + assert_ok!(MultiPhase::create_targets_snapshot()); + + assert_ok!(MultiPhase::create_voters_snapshot(2)); + assert_ok!(MultiPhase::create_voters_snapshot(1)); + assert_ok!(MultiPhase::create_voters_snapshot(0)); + + assert_noop!( + MultiPhase::create_voters_snapshot(3), + ElectionError::::RequestedPageExceeded + ); + assert_noop!( + MultiPhase::create_voters_snapshot(10), + ElectionError::::RequestedPageExceeded + ); + }) + } + + #[test] + fn create_targets_snapshot_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(MultiPhase::msp(), 2); + + let no_bounds = ElectionBoundsBuilder::default().build().targets; + let all_targets = + ::electable_targets(no_bounds, 0); + assert_eq!(all_targets.unwrap(), Targets::get()); + assert_eq!(Targets::get().len(), 8); + + // sets max targets per page to 2. + TargetSnapshotPerBlock::set(2); + + let result_and_count = MultiPhase::create_targets_snapshot(); + assert_eq!(result_and_count.unwrap(), 2); + assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20]); + + // sets max targets per page to 4. + TargetSnapshotPerBlock::set(4); + + let result_and_count = MultiPhase::create_targets_snapshot(); + assert_eq!(result_and_count.unwrap(), 4); + assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20, 30, 40]); + + Snapshot::::kill(); + + TargetSnapshotPerBlock::set(6); + + let result_and_count = MultiPhase::create_targets_snapshot(); + assert_eq!(result_and_count.unwrap(), 6); + assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20, 30, 40, 50, 60]); + + // reset storage. + Snapshot::::kill(); + }) + } + + #[test] + fn voters_snapshot_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(MultiPhase::msp(), 2); + + let no_bounds = ElectionBoundsBuilder::default().build().voters; + let all_voters = ::electing_voters(no_bounds, 0); + assert_eq!(all_voters.unwrap(), Voters::get()); + assert_eq!(Voters::get().len(), 16); + + // sets max voters per page to 7. + VoterSnapshotPerBlock::set(7); + + let voters_page = |page: PageIndex| { + Snapshot::::voters(page) + .unwrap() + .iter() + .map(|v| v.0) + .collect::>() + }; + + // page `msp`. + let result_and_count = MultiPhase::create_voters_snapshot(MultiPhase::msp()); + assert_eq!(result_and_count.unwrap(), 7); + assert_eq!(voters_page(MultiPhase::msp()), vec![1, 2, 3, 4, 5, 6, 7]); + + let result_and_count = MultiPhase::create_voters_snapshot(1); + assert_eq!(result_and_count.unwrap(), 7); + assert_eq!(voters_page(1), vec![8, 10, 20, 30, 40, 50, 60]); + + // page `lsp`. + let result_and_count = MultiPhase::create_voters_snapshot(MultiPhase::lsp()); + assert_eq!(result_and_count.unwrap(), 2); + assert_eq!(voters_page(MultiPhase::lsp()), vec![70, 80]); + }) + } + + #[test] + fn try_progress_snapshot_works() {} +} + +#[cfg(test)] +mod election_provider { + use super::*; + use crate::{mock::*, unsigned::miner::Miner}; + use frame_support::testing_prelude::*; + + #[test] + fn snapshot_to_supports_conversions_work() { + type VotersPerPage = ::VoterSnapshotPerBlock; + type TargetsPerPage = ::TargetSnapshotPerBlock; + type Pages = ::Pages; + + ExtBuilder::default() + .pages(2) + .snasphot_voters_page(4) + .snasphot_targets_page(4) + .desired_targets(2) + .build_and_execute(|| { + assert_eq!(MultiPhase::msp(), 1); + + let all_targets: BoundedVec = + bounded_vec![10, 20, 30, 40]; + + let all_voter_pages: BoundedVec< + BoundedVec, VotersPerPage>, + Pages, + > = bounded_vec![ + bounded_vec![ + (1, 100, bounded_vec![10, 20]), + (2, 20, bounded_vec![30]), + (3, 30, bounded_vec![10]), + (10, 10, bounded_vec![10]) + ], + bounded_vec![ + (20, 20, bounded_vec![20]), + (30, 30, bounded_vec![30]), + (40, 40, bounded_vec![40]) + ], + ]; + + Snapshot::::set_targets(all_targets.clone()); + Snapshot::::set_voters(0, all_voter_pages[0].clone()); + Snapshot::::set_voters(1, all_voter_pages[1].clone()); + + let desired_targets = Snapshot::::desired_targets().unwrap(); + let (results, _) = Miner::::mine_paged_solution_with_snapshot( + &all_voter_pages, + &all_targets, + Pages::get(), + current_round(), + desired_targets, + false, + ) + .unwrap(); + + let supports_page_zero = + PalletVerifier::::feasibility_check(results.solution_pages[0].clone(), 0) + .unwrap(); + let supports_page_one = + PalletVerifier::::feasibility_check(results.solution_pages[1].clone(), 1) + .unwrap(); + + use frame_election_provider_support::{BoundedSupports, TryIntoBoundedSupports}; + use sp_npos_elections::{Support, Supports}; + + let s0: Supports = vec![ + (10, Support { total: 90, voters: vec![(3, 30), (10, 10), (1, 50)] }), + (20, Support { total: 50, voters: vec![(1, 50)] }), + ]; + let bs0: BoundedSupports<_, _, _> = s0.try_into_bounded_supports().unwrap(); + + let s1: Supports = + vec![(20, Support { total: 20, voters: vec![(20, 20)] })]; + let bs1: BoundedSupports<_, _, _> = s1.try_into_bounded_supports().unwrap(); + + assert_eq!(supports_page_zero, bs0); + assert_eq!(supports_page_one, bs1); + }) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs new file mode 100644 index 0000000000000..e094bac3f6919 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -0,0 +1,594 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(unused)] + +mod staking; + +use frame_election_provider_support::{bounds::ElectionBounds, onchain, SequentialPhragmen}; +use sp_npos_elections::ElectionScore; +pub use staking::*; + +use crate::{ + self as epm, + signed::{self as signed_pallet}, + unsigned::{ + self as unsigned_pallet, + miner::{self, Miner, MinerError, OffchainWorkerMiner}, + }, + verifier::{self as verifier_pallet}, + Config, *, +}; +use frame_support::{derive_impl, pallet_prelude::*, parameter_types}; +use parking_lot::RwLock; +use sp_runtime::{ + offchain::{ + testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, + OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, + }, + BuildStorage, Perbill, +}; +use std::sync::Arc; + +frame_support::construct_runtime!( + pub struct Runtime { + System: frame_system, + Balances: pallet_balances, + MultiPhase: epm, + VerifierPallet: verifier_pallet, + SignedPallet: signed_pallet, + UnsignedPallet: unsigned_pallet, + } +); + +pub type AccountId = u64; +pub type Balance = u128; +pub type BlockNumber = u64; +pub type VoterIndex = u32; +pub type TargetIndex = u16; +pub type T = Runtime; +pub type Block = frame_system::mocking::MockBlock; +pub(crate) type Solver = SequentialPhragmen; + +frame_election_provider_support::generate_solution_type!( + #[compact] + pub struct TestNposSolution::< + VoterIndex = VoterIndex, + TargetIndex = TargetIndex, + Accuracy = sp_runtime::PerU16, + MaxVoters = frame_support::traits::ConstU32::<2_000> + >(16) +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountData = pallet_balances::AccountData; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); + type FreezeIdentifier = (); + type MaxFreezes = (); + type DoneSlashHandler = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = (); +} + +parameter_types! { + pub static SignedPhase: BlockNumber = 3; + pub static UnsignedPhase: BlockNumber = 5; + pub static SignedValidationPhase: BlockNumber = Pages::get().into(); + pub static Lookhaead: BlockNumber = 0; + pub static VoterSnapshotPerBlock: VoterIndex = 5; + pub static TargetSnapshotPerBlock: TargetIndex = 8; + pub static Pages: PageIndex = 3; + pub static ExportPhaseLimit: BlockNumber = (Pages::get() * 2u32).into(); +} + +pub struct EPMBenchmarkingConfigs; +impl BenchmarkingConfig for EPMBenchmarkingConfigs { + const VOTERS: u32 = 100; + const TARGETS: u32 = 50; + const VOTERS_PER_PAGE: [u32; 2] = [1, 5]; + const TARGETS_PER_PAGE: [u32; 2] = [1, 8]; +} + +impl Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SignedPhase = SignedPhase; + type UnsignedPhase = UnsignedPhase; + type SignedValidationPhase = SignedValidationPhase; + type Lookhaead = Lookhaead; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type TargetSnapshotPerBlock = TargetSnapshotPerBlock; + type MaxBackersPerWinner = MaxBackersPerWinner; + type MaxWinnersPerPage = MaxWinnersPerPage; + type Pages = Pages; + type ExportPhaseLimit = ExportPhaseLimit; + type DataProvider = MockStaking; + type MinerConfig = Self; + type Fallback = MockFallback; + type Verifier = VerifierPallet; + type BenchmarkingConfig = EPMBenchmarkingConfigs; + type WeightInfo = (); +} + +parameter_types! { + pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); + pub static MaxWinnersPerPage: u32 = 100; + pub static MaxBackersPerWinner: u32 = 1000; +} + +impl crate::verifier::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForceOrigin = frame_system::EnsureRoot; + type SolutionImprovementThreshold = SolutionImprovementThreshold; + type SolutionDataProvider = SignedPallet; + type WeightInfo = (); +} + +parameter_types! { + pub static DepositBase: Balance = 10; + pub static DepositPerPage: Balance = 1; + pub static Reward: Balance = 10; + pub static MaxSubmissions: u32 = 5; +} + +impl crate::signed::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type EstimateCallFee = ConstU32<8>; + type OnSlash = (); // burn + type DepositBase = ConstDepositBase; + type DepositPerPage = DepositPerPage; + type Reward = Reward; + type MaxSubmissions = MaxSubmissions; + type RuntimeHoldReason = RuntimeHoldReason; + type WeightInfo = (); +} + +parameter_types! { + pub OffchainRepeatInterval: BlockNumber = 10; + pub MinerTxPriority: u64 = 0; + pub MinerSolutionMaxLength: u32 = 10; + pub MinerSolutionMaxWeight: Weight = Default::default(); +} + +impl crate::unsigned::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OffchainRepeatInterval = OffchainRepeatInterval; + type MinerTxPriority = MinerTxPriority; + type MaxLength = MinerSolutionMaxLength; + type MaxWeight = MinerSolutionMaxWeight; + type WeightInfo = (); +} + +impl miner::Config for Runtime { + type AccountId = AccountId; + type Solution = TestNposSolution; + type Solver = Solver; + type Pages = Pages; + type MaxVotesPerVoter = MaxVotesPerVoter; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + type VoterSnapshotPerBlock = VoterSnapshotPerBlock; + type TargetSnapshotPerBlock = TargetSnapshotPerBlock; + type MaxWeight = MinerSolutionMaxWeight; + type MaxLength = MinerSolutionMaxLength; +} + +pub type Extrinsic = sp_runtime::testing::TestXt; + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type OverarchingCall = RuntimeCall; + type Extrinsic = Extrinsic; +} + +pub struct ConstDepositBase; +impl sp_runtime::traits::Convert for ConstDepositBase { + fn convert(_a: usize) -> Balance { + DepositBase::get() + } +} + +parameter_types! { + pub static OnChainElectionBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); + pub static MaxVotesPerVoter: u32 = ::LIMIT as u32; + pub static FallbackEnabled: bool = true; +} + +impl onchain::Config for Runtime { + type System = Runtime; + type Solver = Solver; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + type Bounds = OnChainElectionBounds; + type DataProvider = MockStaking; + type WeightInfo = (); +} + +pub struct MockFallback; +impl ElectionProvider for MockFallback { + type AccountId = AccountId; + type BlockNumber = BlockNumberFor; + type Error = &'static str; + type DataProvider = MockStaking; + type Pages = ConstU32<1>; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + + fn elect(remaining: PageIndex) -> Result, Self::Error> { + if FallbackEnabled::get() { + onchain::OnChainExecution::::elect(remaining) + .map_err(|_| "fallback election failed") + } else { + Err("fallback election failed (forced in mock)") + } + } +} + +#[derive(Default)] +pub struct ExtBuilder { + with_verifier: bool, +} + +// TODO(gpestana): separate ext builder into separate builders for each pallet. +impl ExtBuilder { + pub(crate) fn pages(self, pages: u32) -> Self { + Pages::set(pages); + self + } + + pub(crate) fn snasphot_voters_page(self, voters: VoterIndex) -> Self { + VoterSnapshotPerBlock::set(voters); + self + } + + pub(crate) fn snasphot_targets_page(self, targets: TargetIndex) -> Self { + TargetSnapshotPerBlock::set(targets); + self + } + + pub(crate) fn signed_phase(self, blocks: BlockNumber) -> Self { + SignedPhase::set(blocks); + self + } + + pub(crate) fn validate_signed_phase(self, blocks: BlockNumber) -> Self { + SignedValidationPhase::set(blocks); + self + } + + pub(crate) fn unsigned_phase(self, blocks: BlockNumber) -> Self { + UnsignedPhase::set(blocks); + self + } + + pub(crate) fn lookahead(self, blocks: BlockNumber) -> Self { + Lookhaead::set(blocks); + self + } + + pub(crate) fn max_winners_per_page(self, max: u32) -> Self { + MaxWinnersPerPage::set(max); + self + } + + pub(crate) fn max_backers_per_winner(self, max: u32) -> Self { + MaxBackersPerWinner::set(max); + self + } + + pub(crate) fn desired_targets(self, desired: u32) -> Self { + DesiredTargets::set(desired); + self + } + + pub(crate) fn signed_max_submissions(self, max: u32) -> Self { + MaxSubmissions::set(max); + self + } + + pub(crate) fn verifier() -> Self { + ExtBuilder { with_verifier: true } + } + + pub(crate) fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + + let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let _ = pallet_balances::GenesisConfig:: { + balances: vec![ + (10, 100_000), + (20, 100_000), + (30, 100_000), + (40, 100_000), + (50, 100_000), + (60, 100_000), + (70, 100_000), + (80, 100_000), + (90, 100_000), + (91, 100), + (92, 100), + (93, 100), + (94, 100), + (95, 100), + (96, 100), + (97, 100), + (99, 100), + (999, 100), + (9999, 100), + ], + } + .assimilate_storage(&mut storage); + + if self.with_verifier { + // nothing special for now + } + + sp_io::TestExternalities::from(storage) + } + + pub fn build_offchainify( + self, + iters: u32, + ) -> (sp_io::TestExternalities, Arc>) { + let mut ext = self.build(); + let (offchain, offchain_state) = TestOffchainExt::new(); + let (pool, pool_state) = TestTransactionPoolExt::new(); + + let mut seed = [0_u8; 32]; + seed[0..4].copy_from_slice(&iters.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)); + + (ext, pool_state) + } + + pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = self.build(); + ext.execute_with(test); + + #[cfg(feature = "try-runtime")] + ext.execute_with(|| { + //MultiPhase::do_try_state().unwrap(); + // etc.. + + let _ = VerifierPallet::do_try_state() + .map_err(|err| println!(" 🕵️‍♂️ Verifier `try_state` failure: {:?}", err)); + }); + } +} + +pub(crate) fn compute_snapshot_checked() { + let msp = crate::Pallet::::msp(); + + for page in (0..=Pages::get()).rev() { + CurrentPhase::::set(Phase::Snapshot(page)); + crate::Pallet::::try_progress_snapshot(page); + + assert!(Snapshot::::targets_snapshot_exists()); + + if page <= msp { + assert!(Snapshot::::voters(page).is_some()); + } + } +} + +pub(crate) fn mine_and_verify_all() -> Result< + Vec< + frame_election_provider_support::BoundedSupports< + AccountId, + MaxWinnersPerPage, + MaxBackersPerWinner, + >, + >, + &'static str, +> { + let msp = crate::Pallet::::msp(); + let mut paged_supports = vec![]; + + for page in (0..=msp).rev() { + let (_, score, solution) = + OffchainWorkerMiner::::mine(page).map_err(|e| "error mining")?; + + let supports = + ::verify_synchronous(solution, score, page) + .map_err(|_| "error verifying paged solution")?; + + paged_supports.push(supports); + } + + Ok(paged_supports) +} + +pub(crate) fn roll_to(n: BlockNumber) { + for bn in (System::block_number()) + 1..=n { + System::set_block_number(bn); + + MultiPhase::on_initialize(bn); + VerifierPallet::on_initialize(bn); + SignedPallet::on_initialize(bn); + UnsignedPallet::on_initialize(bn); + UnsignedPallet::offchain_worker(bn); + + // TODO: add try-checks for all pallets here too, as we progress the blocks. + log!( + info, + "Block: {}, Phase: {:?}, Round: {:?}, Election at {:?}", + bn, + >::get(), + >::get(), + election_prediction() + ); + } +} + +// Fast forward until a given election phase. +pub fn roll_to_phase(phase: Phase) { + while MultiPhase::current_phase() != phase { + roll_to(System::block_number() + 1); + } +} + +pub fn roll_one_with_ocw(maybe_pool: Option>>) { + use sp_runtime::traits::Dispatchable; + let bn = System::block_number() + 1; + // if there's anything in the submission pool, submit it. + if let Some(ref pool) = maybe_pool { + pool.read() + .transactions + .clone() + .into_iter() + .map(|uxt| ::decode(&mut &*uxt).unwrap()) + .for_each(|xt| { + xt.call.dispatch(frame_system::RawOrigin::None.into()).unwrap(); + }); + pool.try_write().unwrap().transactions.clear(); + } + + roll_to(bn); +} + +pub fn roll_to_phase_with_ocw( + phase: Phase, + maybe_pool: Option>>, +) { + while MultiPhase::current_phase() != phase { + roll_one_with_ocw(maybe_pool.clone()); + } +} + +pub fn roll_to_with_ocw(n: BlockNumber, maybe_pool: Option>>) { + let now = System::block_number(); + for _i in now + 1..=n { + roll_one_with_ocw(maybe_pool.clone()); + } +} + +pub fn election_prediction() -> BlockNumber { + <::DataProvider as ElectionDataProvider>::next_election_prediction( + System::block_number(), + ) +} + +pub fn current_phase() -> Phase { + MultiPhase::current_phase() +} + +pub fn current_round() -> u32 { + Pallet::::current_round() +} + +pub fn call_elect() -> Result<(), crate::ElectionError> { + for p in (0..=Pallet::::msp()).rev() { + ::elect(p)?; + } + Ok(()) +} + +pub fn assert_snapshots() -> Result<(), &'static str> { + Snapshot::::ensure() +} + +pub fn clear_snapshot() { + let _ = crate::PagedVoterSnapshot::::clear(u32::MAX, None); + let _ = crate::PagedTargetSnapshot::::clear(u32::MAX, None); +} + +pub fn balances(who: AccountId) -> (Balance, Balance) { + (Balances::free_balance(who), Balances::reserved_balance(who)) +} + +pub fn mine_full(pages: PageIndex) -> Result, MinerError> { + let (targets, voters) = + OffchainWorkerMiner::::fetch_snapshots().map_err(|_| MinerError::DataProvider)?; + + let reduce = false; + let round = crate::Pallet::::current_round(); + let desired_targets = ::desired_targets() + .map_err(|_| MinerError::DataProvider)?; + + Miner::::mine_paged_solution_with_snapshot( + &targets, + &voters, + Pages::get(), + round, + desired_targets, + reduce, + ) + .map(|(s, _)| s) +} + +pub fn mine( + page: PageIndex, +) -> Result<(ElectionScore, SolutionOf<::MinerConfig>), ()> { + let (_, partial_score, partial_solution) = + OffchainWorkerMiner::::mine(page).map_err(|_| ())?; + + Ok((partial_score, partial_solution)) +} + +// Pallet events filters. + +pub(crate) fn unsigned_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let RuntimeEvent::UnsignedPallet(inner) = e { Some(inner) } else { None }, + ) + .collect() +} + +pub(crate) fn signed_events() -> Vec> { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::SignedPallet(inner) = e { Some(inner) } else { None }) + .collect() +} + +// TODO fix or use macro. +pub(crate) fn filter_events( + types: Vec, +) -> Vec { + System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if types.contains(&e) { Some(e) } else { None }) + .collect() +} diff --git a/substrate/frame/election-provider-multi-block/src/mock/staking.rs b/substrate/frame/election-provider-multi-block/src/mock/staking.rs new file mode 100644 index 0000000000000..52fc297700420 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/mock/staking.rs @@ -0,0 +1,235 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use sp_runtime::bounded_vec; + +use frame_election_provider_support::{ + bounds::CountBound, data_provider, DataProviderBounds, ElectionDataProvider, + LockableElectionDataProvider, PageIndex, VoterOf as VoterOfProvider, +}; + +use super::{AccountId, BlockNumber, MaxVotesPerVoter, T}; + +// alias for a voter of EPM-MB. +type VoterOf = frame_election_provider_support::VoterOf<::DataProvider>; + +frame_support::parameter_types! { + pub static Targets: Vec = vec![10, 20, 30, 40, 50, 60, 70, 80]; + pub static Voters: Vec> = vec![ + (1, 10, bounded_vec![10, 20]), + (2, 10, bounded_vec![30, 40]), + (3, 10, bounded_vec![40]), + (4, 10, bounded_vec![10, 20, 40]), + (5, 10, bounded_vec![10, 30, 40]), + (6, 10, bounded_vec![20, 30, 40]), + (7, 10, bounded_vec![20, 30]), + (8, 10, bounded_vec![10]), + (10, 10, bounded_vec![10]), + (20, 20, bounded_vec![20]), + (30, 30, bounded_vec![30]), + (40, 40, bounded_vec![40]), + (50, 50, bounded_vec![50]), + (60, 60, bounded_vec![60]), + (70, 70, bounded_vec![70]), + (80, 80, bounded_vec![80]), + ]; + pub static EpochLength: u64 = 30; + pub static DesiredTargets: u32 = 5; + + pub static LastIteratedTargetIndex: Option = None; + pub static LastIteratedVoterIndex: Option = None; + + pub static ElectionDataLock: Option<()> = None; // not locker. +} + +pub struct MockStaking; +impl ElectionDataProvider for MockStaking { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type MaxVotesPerVoter = MaxVotesPerVoter; + + fn electable_targets( + bounds: DataProviderBounds, + remaining: PageIndex, + ) -> data_provider::Result> { + let mut targets = Targets::get(); + + // drop previously processed targets. + if let Some(last_index) = LastIteratedTargetIndex::get() { + targets = targets.iter().skip(last_index).cloned().collect::>(); + } + + // take as many targets as requested. + if let Some(max_len) = bounds.count { + targets.truncate(max_len.0 as usize); + } + + assert!(!bounds.exhausted(None, CountBound(targets.len() as u32).into(),)); + + // update the last iterated target index accordingly. + if remaining > 0 { + if let Some(last) = targets.last().cloned() { + LastIteratedTargetIndex::set(Some( + Targets::get().iter().position(|v| v == &last).map(|i| i + 1).unwrap(), + )); + } else { + // no more targets to process, do nothing. + } + } else { + LastIteratedTargetIndex::set(None); + } + + Ok(targets) + } + + /// Note: electing voters bounds are only constrained by the count of voters. + fn electing_voters( + bounds: DataProviderBounds, + remaining: PageIndex, + ) -> data_provider::Result>> { + let mut voters = Voters::get(); + + // skip the already iterated voters in previous pages. + if let Some(index) = LastIteratedVoterIndex::get() { + voters = voters.iter().skip(index).cloned().collect::>(); + } + + // take as many voters as permitted by the bounds. + if let Some(max_len) = bounds.count { + voters.truncate(max_len.0 as usize); + } + + assert!(!bounds.exhausted(None, CountBound(voters.len() as u32).into())); + + // update the last iterater voter index accordingly. + if remaining > 0 { + if let Some(last) = voters.last().cloned() { + LastIteratedVoterIndex::set(Some( + Voters::get().iter().position(|v| v == &last).map(|i| i + 1).unwrap(), + )); + } else { + // no more voters to process, do nothing. + } + } else { + LastIteratedVoterIndex::set(None); + } + + Ok(voters) + } + + fn desired_targets() -> data_provider::Result { + Ok(DesiredTargets::get()) + } + + fn next_election_prediction(now: Self::BlockNumber) -> Self::BlockNumber { + now + EpochLength::get() - now % EpochLength::get() + } +} + +impl LockableElectionDataProvider for MockStaking { + fn set_lock() -> data_provider::Result<()> { + ElectionDataLock::get() + .ok_or("lock is already set") + .map(|_| ElectionDataLock::set(Some(()))) + } + + fn unlock() { + ElectionDataLock::set(None); + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::mock::{ExtBuilder, Pages}; + + #[test] + fn multi_page_targets() { + ExtBuilder::default().build_and_execute(|| { + // no bounds. + let targets = + ::electable_targets(Default::default(), 0); + assert_eq!(targets.unwrap().len(), 8); + assert_eq!(LastIteratedTargetIndex::get(), None); + + // 2 targets per page. + let bounds: DataProviderBounds = + DataProviderBounds { count: Some(2.into()), size: None }; + + let mut all_targets = vec![]; + for page in (0..(Pages::get())).rev() { + let mut targets = + ::electable_targets(bounds, page).unwrap(); + assert_eq!(targets.len(), bounds.count.unwrap().0 as usize); + + all_targets.append(&mut targets); + } + + assert_eq!(all_targets, vec![10, 20, 30, 40, 50, 60]); + assert_eq!(LastIteratedTargetIndex::get(), None); + }) + } + + #[test] + fn multi_page_voters() { + ExtBuilder::default().build_and_execute(|| { + // no bounds. + let voters = + ::electing_voters(Default::default(), 0); + assert_eq!(voters.unwrap().len(), 16); + assert_eq!(LastIteratedVoterIndex::get(), None); + + // 2 voters per page. + let bounds: DataProviderBounds = + DataProviderBounds { count: Some(2.into()), size: None }; + + let mut all_voters = vec![]; + for page in (0..(Pages::get())).rev() { + let mut voters = + ::electing_voters(bounds, page).unwrap(); + + assert_eq!(voters.len(), bounds.count.unwrap().0 as usize); + + all_voters.append(&mut voters); + } + + let mut expected_voters = Voters::get(); + expected_voters.truncate(6); + + assert_eq!(all_voters, expected_voters); + assert_eq!(LastIteratedVoterIndex::get(), None); + + // bound based on the *encoded size* of the voters, per page. + let bounds: DataProviderBounds = + DataProviderBounds { count: None, size: Some(100.into()) }; + + let mut all_voters = vec![]; + for page in (0..(Pages::get())).rev() { + let mut voters = + ::electing_voters(bounds, page).unwrap(); + + all_voters.append(&mut voters); + } + + let mut expected_voters = Voters::get(); + expected_voters.truncate(all_voters.len()); + + assert_eq!(all_voters, expected_voters); + assert_eq!(LastIteratedVoterIndex::get(), None); + }) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs new file mode 100644 index 0000000000000..9629acce2ed38 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs @@ -0,0 +1,66 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Benchmarking for the Elections Multiblock Unsigned sub-pallet. + +use super::*; +use crate::{benchmarking::helpers, BenchmarkingConfig, ConfigCore, ConfigSigned, ConfigUnsigned}; +use frame_benchmarking::v2::*; + +#[benchmarks( + where T: ConfigCore + ConfigSigned + ConfigUnsigned, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn verify_page( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS, + ::BenchmarkingConfig::TARGETS, + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + #[block] + { + // TODO + let _ = 1 + 2; + } + + Ok(()) + } + + impl_benchmark_test_suite!( + PalletSigned, + crate::mock::ExtBuilder::default(), + crate::mock::Runtime, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs new file mode 100644 index 0000000000000..3ec1c824597d0 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -0,0 +1,676 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Signed sub-pallet +//! +//! The main goal of the signed sub-pallet is to keep and manage a list of sorted score commitments +//! and correponding paged solutions during the [`crate::Phase::Signed`]. +//! +//! Accounts may submit up to [`Config::MaxSubmissions`] score commitments per election round and +//! this pallet ensures that the scores are stored under the map `SortedScores` are sorted and keyed +//! by the correct round number. +//! +//! Each submitter must hold a deposit per submission that is calculated based on the number of +//! pages required for a full submission and the number of submissions in the queue. The deposit is +//! returned in case the claimed score is correct after the solution verification. Note that if a +//! commitment and corresponding solution are not verified during the verification phase, the +//! submitter is not slashed and the deposits returned. +//! +//! When the time to evaluate the signed submission comes, the solutions are checked from best to +//! worse, which may result in one of three scenarios: +//! +//! 1. If the committed score and page submissions are correct, the submitter is rewarded. +//! 2. Any queued score that was not evaluated, the hold deposit is returned. +//! 3. Any invalid solution results in a 100% slash of the hold submission deposit. +//! +//! Once the [`crate::Phase::SignedValidation`] phase starts, the async verifier is notified to +//! start verifying the best queued solution. +//! +//! TODO: +//! - Be more efficient with cleaning up the submission storage by e.g. expose an extrinsic that +//! allows anyone to clean up the submissions storage with a small reward from the submission +//! deposit (clean up storage submissions and all corresponding metadata). + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +mod tests; + +use crate::{ + signed::pallet::Submissions, + types::AccountIdOf, + verifier::{AsyncVerifier, SolutionDataProvider, VerificationResult}, + PageIndex, PagesOf, SolutionOf, +}; + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + traits::{ + fungible::{ + hold::Balanced as FnBalanced, Credit, Inspect as FnInspect, MutateHold as FnMutateHold, + }, + tokens::Precision, + Defensive, + }, + RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use sp_npos_elections::ElectionScore; +use sp_runtime::BoundedVec; +use sp_std::vec::Vec; + +// public re-exports. +pub use pallet::{ + Call, Config, Error, Event, HoldReason, Pallet, __substrate_call_check, + __substrate_event_check, tt_default_parts, tt_default_parts_v2, tt_error_token, +}; + +/// Alias for the pallet's balance type. +type BalanceOf = <::Currency as FnInspect>>::Balance; +/// Alias for the pallet's hold credit type. +pub type CreditOf = Credit, ::Currency>; + +/// Metadata of a registered submission. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Default, RuntimeDebugNoBound)] +#[cfg_attr(test, derive(frame_support::PartialEqNoBound, frame_support::EqNoBound))] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] +pub struct SubmissionMetadata { + /// The score that this submission is proposing. + claimed_score: ElectionScore, + /// A bit-wise bounded vec representing the submitted pages thus far. + pages: BoundedVec>, + /// The amount held for this submission. + deposit: BalanceOf, +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use core::marker::PhantomData; + + use crate::verifier::{AsyncVerifier, Verifier}; + + use super::*; + use frame_support::{ + pallet_prelude::{ValueQuery, *}, + traits::{Defensive, EstimateCallFee, OnUnbalanced}, + Twox64Concat, + }; + use frame_system::{ + ensure_signed, + pallet_prelude::{BlockNumberFor, OriginFor}, + WeightInfo, + }; + use sp_npos_elections::ElectionScore; + use sp_runtime::traits::Convert; + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: crate::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The currency type. + type Currency: FnMutateHold + + FnBalanced; + + /// Something that can predict the fee of a call. Used to sensibly distribute rewards. + type EstimateCallFee: EstimateCallFee, BalanceOf>; + + /// Handler for the unbalanced reduction that happens when submitters are slashed. + type OnSlash: OnUnbalanced>; + + /// Something that calculates the signed base deposit based on the size of the current + /// queued solution proposals. + /// TODO: rename to `Deposit` or other? + type DepositBase: Convert>; + + /// Per-page deposit for a signed solution. + #[pallet::constant] + type DepositPerPage: Get>; + + /// Reward for an accepted solution. + #[pallet::constant] + type Reward: Get>; + + /// The maximum number of signed submissions per round. + #[pallet::constant] + type MaxSubmissions: Get; + + /// The pallet's hold reason. + type RuntimeHoldReason: From; + + type WeightInfo: WeightInfo; + } + + /// A sorted list of the current submissions scores corresponding to solution commitments + /// submitted in the signed phase, keyed by round. + /// + /// This pallet *MUST* ensure the bounded vec of scores is always sorted after mutation. + #[pallet::storage] + type SortedScores = StorageMap< + _, + Twox64Concat, + u32, + BoundedVec<(T::AccountId, ElectionScore), T::MaxSubmissions>, + ValueQuery, + >; + + /// A triple-map from (round, account, page) to a submitted solution. + #[pallet::storage] + type SubmissionStorage = StorageNMap< + _, + ( + NMapKey, + NMapKey, + NMapKey, + ), + SolutionOf, + OptionQuery, + >; + + /// A double-map from (`round`, `account_id`) to a submission metadata of a registered + /// solution commitment. + #[pallet::storage] + type SubmissionMetadataStorage = + StorageDoubleMap<_, Twox64Concat, u32, Twox64Concat, T::AccountId, SubmissionMetadata>; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + /// A reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Deposit for registering an election solution. + ElectionSolutionSubmission, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A score commitment has been successfully registered. + Registered { round: u32, who: AccountIdOf, claimed_score: ElectionScore }, + /// A submission page was stored successfully. + PageStored { round: u32, who: AccountIdOf, page: PageIndex }, + /// Retracted a submission successfully. + Bailed { round: u32, who: AccountIdOf }, + /// A submission has been cleared by request. + SubmissionCleared { round: u32, submitter: AccountIdOf, reward: Option> }, + } + + #[pallet::error] + pub enum Error { + /// The election system is not expecting signed submissions. + NotAcceptingSubmissions, + /// Duplicate registering for a given round, + DuplicateRegister, + /// The submissions queue is full. Reject submission. + SubmissionsQueueFull, + /// Submission with a page index higher than the supported. + BadPageIndex, + /// A page submission was attempted for a submission that was not previously registered. + SubmissionNotRegistered, + /// A submission score is not high enough. + SubmissionScoreTooLow, + /// Bad timing for force clearing a stored submission. + CannotClear, + } + + /// Wrapper for signed submissions. + /// + /// It handle 3 storage items: + /// + /// 1. [`SortedScores`]: A flat, striclty sorted, vector with all the submission's scores. The + /// vector contains a tuple of `submitter_id` and `claimed_score`. + /// 2. [`SubmissionStorage`]: Paginated map with all submissions, keyed by round, submitter and + /// page index. + /// 3. [`SubmissionMetadataStorage`]: Double map with submissions metadata, keyed by submitter + /// ID and round. + /// + /// Invariants: + /// - TODO + pub(crate) struct Submissions(core::marker::PhantomData); + impl Submissions { + /// Generic mutation helper with checks. + /// + /// All the mutation functions must be done through this function. + fn mutate_checked R>(_round: u32, mutate: F) -> R { + let result = mutate(); + + #[cfg(debug_assertions)] + assert!(Self::sanity_check_round(crate::Pallet::::current_round()).is_ok()); + + result + } + + /// Try to register a submission commitment. + /// + /// The submission is not accepted if one of these invariants fails: + /// - The claimed score is not higher than the minimum expected score. + /// - The queue is full and the election score is strictly worse than all the current + /// queued solutions. + /// + /// A queued solution may be discarded if the queue is full and the new submission has a + /// better score. + /// + /// It must ensure that the metadata queue is sorted by election score. + fn try_register( + who: &T::AccountId, + round: u32, + metadata: SubmissionMetadata, + ) -> DispatchResult { + Self::mutate_checked(round, || Self::try_register_inner(who, round, metadata)) + } + + fn try_register_inner( + who: &T::AccountId, + round: u32, + metadata: SubmissionMetadata, + ) -> DispatchResult { + let mut scores = SortedScores::::get(round); + scores.iter().try_for_each(|(account, _)| -> DispatchResult { + ensure!(account != who, Error::::DuplicateRegister); + Ok(()) + })?; + + // most likely checked before, but double-checking. + debug_assert!(!SubmissionMetadataStorage::::contains_key(round, who)); + + // the submission score must be higher than the minimum trusted score. Note that since + // there is no queued solution yet, the check is performed against the minimum score + // only. TODO: consider rename `ensure_score_improves`. + ensure!( + ::ensure_score_improves(metadata.claimed_score), + Error::::SubmissionScoreTooLow, + ); + + let pos = + match scores.binary_search_by_key(&metadata.claimed_score, |(_, score)| *score) { + // in the unlikely event that election scores already exists in the storage, we + // store the submissions next to one other. + Ok(pos) | Err(pos) => pos, + }; + + let submission = (who.clone(), metadata.claimed_score); + + match scores.force_insert_keep_right(pos, submission) { + // entry inserted without discarding. + Ok(None) => Ok(()), + // entry inserted but queue was full, clear the discarded submission. + Ok(Some((discarded, _s))) => { + let _ = + SubmissionStorage::::clear_prefix((round, &discarded), u32::MAX, None); + // unreserve deposit + let _ = T::Currency::release_all( + &HoldReason::ElectionSolutionSubmission.into(), + &who, + Precision::Exact, + ) + .defensive()?; + + Ok(()) + }, + Err(_) => Err(Error::::SubmissionsQueueFull), + }?; + + SortedScores::::insert(round, scores); + SubmissionMetadataStorage::::insert(round, who, metadata); + + Ok(()) + } + + /// Store a paged solution for `who` in a given `round`. + /// + /// If `maybe_solution` is None, it will delete the given page from the submission store. + /// Successive calls to this with the same page index will replace the existing page + /// submission. + pub(crate) fn try_mutate_page( + who: &T::AccountId, + round: u32, + page: PageIndex, + maybe_solution: Option>, + ) -> DispatchResult { + Self::mutate_checked(round, || { + Self::try_mutate_page_inner(who, round, page, maybe_solution) + }) + } + + fn try_mutate_page_inner( + who: &T::AccountId, + round: u32, + page: PageIndex, + maybe_solution: Option>, + ) -> DispatchResult { + ensure!( + crate::Pallet::::current_phase().is_signed(), + Error::::NotAcceptingSubmissions + ); + ensure!(page < T::Pages::get(), Error::::BadPageIndex); + + ensure!( + SubmissionMetadataStorage::::contains_key(round, who), + Error::::SubmissionNotRegistered + ); + + // TODO: update the held deposit to account for the paged submission deposit. + + SubmissionStorage::::mutate_exists((round, who, page), |maybe_old_solution| { + *maybe_old_solution = maybe_solution + }); + + Ok(()) + } + + /// Clears all the stored data from the leader. + /// + /// Returns the submission metadata of the cleared submission, if any. + pub(crate) fn take_leader_data( + round: u32, + ) -> Option<(T::AccountId, SubmissionMetadata)> { + Self::mutate_checked(round, || { + SortedScores::::mutate(round, |scores| scores.pop()).and_then( + |(submitter, _score)| { + let _ = SubmissionStorage::::clear_prefix( + (round, &submitter), + u32::MAX, + None, + ); // TODO: handle error. + + SubmissionMetadataStorage::::take(round, &submitter) + .map(|metadata| (submitter, metadata)) + }, + ) + }) + } + + /// Returns the leader submitter for the current round and corresponding claimed score. + pub(crate) fn leader(round: u32) -> Option<(T::AccountId, ElectionScore)> { + SortedScores::::get(round).last().cloned() + } + + /// Returns a submission page for a given round, submitter and page index. + pub(crate) fn get_page( + who: &T::AccountId, + round: u32, + page: PageIndex, + ) -> Option> { + SubmissionStorage::::get((round, who, page)) + } + } + + #[allow(dead_code)] + impl Submissions { + /// Returns the metadata of a submitter for a given account. + pub(crate) fn metadata_for( + round: u32, + who: &T::AccountId, + ) -> Option> { + SubmissionMetadataStorage::::get(round, who) + } + + /// Returns the scores for a given round. + pub(crate) fn scores_for( + round: u32, + ) -> BoundedVec<(T::AccountId, ElectionScore), T::MaxSubmissions> { + SortedScores::::get(round) + } + + /// Returns the submission of a submitter for a given round and page. + pub(crate) fn submission_for( + who: T::AccountId, + round: u32, + page: PageIndex, + ) -> Option> { + SubmissionStorage::::get((round, who, page)) + } + } + + #[cfg(debug_assertions)] + impl Submissions { + fn sanity_check_round(_round: u32) -> Result<(), &'static str> { + // TODO + Ok(()) + } + } + + impl Pallet { + pub(crate) fn do_register( + who: &T::AccountId, + claimed_score: ElectionScore, + round: u32, + ) -> DispatchResult { + let deposit = T::DepositBase::convert( + SubmissionMetadataStorage::::iter_key_prefix(round).count(), + ); + + T::Currency::hold(&HoldReason::ElectionSolutionSubmission.into(), &who, deposit)?; + + let pages: BoundedVec<_, T::Pages> = (0..T::Pages::get()) + .map(|_| false) + .collect::>() + .try_into() + .expect("bounded vec constructed from bound; qed."); + + let metadata = SubmissionMetadata { pages, claimed_score, deposit }; + + let _ = Submissions::::try_register(&who, round, metadata)?; + Ok(()) + } + } + + #[pallet::call] + impl Pallet { + /// Submit a score commitment for a solution in the current round. + /// + /// The scores must be kept sorted in the `SortedScores` storage map. + #[pallet::call_index(1)] + pub fn register(origin: OriginFor, claimed_score: ElectionScore) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!( + crate::Pallet::::current_phase().is_signed(), + Error::::NotAcceptingSubmissions + ); + + let round = crate::Pallet::::current_round(); + ensure!( + !SubmissionMetadataStorage::::contains_key(round, who.clone()), + Error::::DuplicateRegister + ); + + Self::do_register(&who, claimed_score, round)?; + + Self::deposit_event(Event::::Registered { round, who, claimed_score }); + Ok(()) + } + + /// Submit a page for a solution. + /// + /// To submit a solution page successfull, the submitter must have registered the + /// commitment before. + /// + /// TODO: for security reasons, we have to ensure that ALL submitters "space" to + /// submit their pages and be verified. + #[pallet::call_index(2)] + pub fn submit_page( + origin: OriginFor, + page: PageIndex, + maybe_solution: Option>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!( + crate::Pallet::::current_phase().is_signed(), + Error::::NotAcceptingSubmissions + ); + + let round = crate::Pallet::::current_round(); + Submissions::::try_mutate_page(&who, round, page, maybe_solution)?; + + Self::deposit_event(Event::::PageStored { + round: crate::Pallet::::current_round(), + who, + page, + }); + + Ok(()) + } + + /// Unregister a submission. + /// + /// This will fully remove the solution and corresponding metadata from storage and refund + /// the submission deposit. + /// + /// NOTE: should we refund the deposit? there's an attack vector where an attacker can + /// register with a set of very high elections core and then retract all submission just + /// before the signed phase ends. This may end up depriving other honest miners from + /// registering their solution. + #[pallet::call_index(3)] + pub fn bail(origin: OriginFor) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!( + crate::Pallet::::current_phase().is_signed(), + Error::::NotAcceptingSubmissions + ); + + // TODO + // 1. clear all storage items related to `who` + // 2. return deposit + + Self::deposit_event(Event::::Bailed { + round: crate::Pallet::::current_round(), + who, + }); + + Ok(()) + } + + /// Force clean submissions storage. + /// + /// Allows any account to receive a reward for requesting the submission storage and + /// corresponding metadata to be cleaned. This extrinsic will fail if the signed or signed + /// validated phases are active to prevent disruption in the election progress. + /// + /// A successfull call will result in a reward that is taken from the cleared submission + /// deposit and the return of the call fees. + #[pallet::call_index(4)] + pub fn force_clear_submission( + origin: OriginFor, + submitter: T::AccountId, + ) -> DispatchResult { + let _who = ensure_signed(origin); + + // prevent cleaning up submissions storage during the signed and signed validation + // phase. + ensure!( + !crate::Pallet::::current_phase().is_signed() && + !crate::Pallet::::current_phase().is_signed_validation_open_at(None), + Error::::CannotClear, + ); + + // TODO: + // 1. clear the submission, if it exists + // 2. clear the submission metadata + // 3. reward caller as a portions of the submittion's deposit + let reward = Default::default(); + // 4. return fees. + + Self::deposit_event(Event::::SubmissionCleared { + round: crate::Pallet::::current_round(), + submitter, + reward, + }); + + Ok(()) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + /// The `on_initialize` signals the [`AsyncVerifier`] whenever it should start or stop the + /// asynchronous verification of the stored submissions. + /// + /// - Start async verification at the beginning of the [`crate::Phase::SignedValidation`]. + /// - Stopns async verification at the beginning of the [`crate::Phase::Unsigned`]. + fn on_initialize(now: BlockNumberFor) -> Weight { + // TODO: match + if crate::Pallet::::current_phase().is_signed_validation_open_at(Some(now)) { + let _ = ::start().defensive(); + }; + + if crate::Pallet::::current_phase().is_unsigned_open_at(now) { + sublog!(info, "signed", "signed validation phase ended, signaling the verifier."); + ::stop(); + } + + if crate::Pallet::::current_phase() == crate::Phase::Off { + sublog!(info, "signed", "clear up storage for pallets."); + + // TODO: optimize. + let _ = SubmissionMetadataStorage::::clear(u32::MAX, None); + let _ = SubmissionStorage::::clear(u32::MAX, None); + let _ = SortedScores::::clear(u32::MAX, None); + } + + Weight::default() + } + } +} + +impl SolutionDataProvider for Pallet { + type Solution = SolutionOf; + + fn get_paged_solution(page: PageIndex) -> Option { + let round = crate::Pallet::::current_round(); + + Submissions::::leader(round).map(|(who, _score)| { + sublog!(info, "signed", "returning page {} of leader's {:?} solution", page, who); + Submissions::::get_page(&who, round, page).unwrap_or_default() + }) + } + + fn get_score() -> Option { + let round = crate::Pallet::::current_round(); + Submissions::::leader(round).map(|(_who, score)| score) + } + + fn report_result(result: VerificationResult) { + let round = crate::Pallet::::current_round(); + match result { + VerificationResult::Queued => {}, + VerificationResult::Rejected => { + if let Some((_offender, _metadata)) = Submissions::::take_leader_data(round) { + // TODO: slash offender + } else { + // no signed submission in storage, signal async verifier to stop and move on. + let _ = ::stop(); + }; + + if crate::Pallet::::current_phase().is_signed_validation_open_at(None) && + Submissions::::leader(round).is_some() + { + let _ = ::start().defensive(); + } + }, + VerificationResult::DataUnavailable => { + // signed pallet did not have the required data. + }, + } + } +} diff --git a/substrate/frame/election-provider-multi-block/src/signed/tests.rs b/substrate/frame/election-provider-multi-block/src/signed/tests.rs new file mode 100644 index 0000000000000..864a94eb1a8c4 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/signed/tests.rs @@ -0,0 +1,309 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::{mock::*, verifier::SolutionDataProvider, Phase, Verifier}; +use frame_support::{assert_noop, assert_ok, testing_prelude::*}; +use sp_npos_elections::ElectionScore; + +mod calls { + use super::*; + use sp_core::bounded_vec; + + #[test] + fn register_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to_phase(Phase::Signed); + assert_ok!(assert_snapshots()); + + assert_eq!(balances(99), (100, 0)); + let score = ElectionScore { minimal_stake: 100, ..Default::default() }; + + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), score)); + assert_eq!(balances(99), (90, 10)); + + assert_eq!( + Submissions::::metadata_for(current_round(), &99).unwrap(), + SubmissionMetadata { + claimed_score: score, + deposit: 10, + pages: bounded_vec![false, false, false], + } + ); + + assert_eq!( + signed_events(), + vec![Event::Registered { round: 0, who: 99, claimed_score: score }], + ); + + // duplicate submission for the same round fails. + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(99), score), + Error::::DuplicateRegister, + ); + + // if claimed score if below the minimum score, submission will fail. + ::set_minimum_score(ElectionScore { + minimal_stake: 20, + ..Default::default() + }); + + let low_score = ElectionScore { minimal_stake: 10, ..Default::default() }; + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(97), low_score), + Error::::SubmissionScoreTooLow, + ); + }) + } + + #[test] + fn register_sorted_works() { + ExtBuilder::default().signed_max_submissions(3).build_and_execute(|| { + // try register 5 submissions: + // - 3 are stored. + // - one submission is registered after queue is full while the score improves current + // submission in the queue; other submission is discarded. + // - one submission is registered after queue is full while the score does not improve + // the current submission in the queue; submission is discarded. + + roll_to_phase(Phase::Signed); + + let score = ElectionScore { minimal_stake: 40, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(40), score)); + + let score = ElectionScore { minimal_stake: 30, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(30), score)); + + let score = ElectionScore { minimal_stake: 20, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(20), score)); + + // submission queue is full, next submissions will only be accepted if the submitted + // score improves the current lower score. + + // registration discarded. + let score = ElectionScore { minimal_stake: 10, ..Default::default() }; + assert_noop!( + SignedPallet::register(RuntimeOrigin::signed(10), score), + Error::::SubmissionsQueueFull + ); + + // higher score is successfully registered. + let higher_score = ElectionScore { minimal_stake: 50, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(50), higher_score)); + + assert_eq!(Submissions::::leader(current_round()).unwrap(), (50, higher_score),); + + assert_eq!( + signed_events(), + vec![ + Event::Registered { + round: 0, + who: 40, + claimed_score: ElectionScore { + minimal_stake: 40, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::Registered { + round: 0, + who: 30, + claimed_score: ElectionScore { + minimal_stake: 30, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::Registered { + round: 0, + who: 20, + claimed_score: ElectionScore { + minimal_stake: 20, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::Registered { + round: 0, + who: 50, + claimed_score: ElectionScore { + minimal_stake: 50, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + ], + ); + }) + } + + #[test] + fn submit_page_works() { + ExtBuilder::default().build_and_execute(|| { + // bad timing. + assert_noop!( + SignedPallet::submit_page(RuntimeOrigin::signed(40), 0, None), + Error::::NotAcceptingSubmissions + ); + + roll_to_phase(Phase::Signed); + + // submission not registered before. + assert_noop!( + SignedPallet::submit_page(RuntimeOrigin::signed(10), 0, None), + Error::::SubmissionNotRegistered + ); + + let score = ElectionScore { minimal_stake: 10, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(10), score)); + + // now submission works since there is a registered commitment. + assert_ok!(SignedPallet::submit_page( + RuntimeOrigin::signed(10), + 0, + Some(Default::default()) + )); + + assert_eq!( + Submissions::::submission_for(10, current_round(), 0), + Some(Default::default()), + ); + + // tries to submit a page out of bounds. + assert_noop!( + SignedPallet::submit_page(RuntimeOrigin::signed(10), 10, Some(Default::default())), + Error::::BadPageIndex, + ); + + assert_eq!( + signed_events(), + vec![ + Event::Registered { + round: 0, + who: 10, + claimed_score: ElectionScore { + minimal_stake: 10, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::PageStored { round: 0, who: 10, page: 0 } + ], + ); + }) + } +} + +mod solution_data_provider { + use super::*; + + #[test] + fn higher_score_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to_phase(Phase::Signed); + + assert_eq!(::get_score(), None); + + let higher_score = ElectionScore { minimal_stake: 40, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(40), higher_score)); + + let score = ElectionScore { minimal_stake: 30, ..Default::default() }; + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(30), score)); + + assert_eq!(::get_score(), Some(higher_score)); + }) + } + + #[test] + fn get_page_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to_phase(Phase::Signed); + assert_eq!(::get_score(), None); + }) + } +} + +mod e2e { + use super::*; + + type MaxSubmissions = ::MaxSubmissions; + + mod simple_e2e_works { + use super::*; + + #[test] + fn submit_solution_happy_path_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to_phase(Phase::Signed); + + let current_round = MultiPhase::current_round(); + assert!(Submissions::::metadata_for(current_round, &10).is_none()); + + let claimed_score = ElectionScore { minimal_stake: 100, ..Default::default() }; + + // register submission + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(10), claimed_score,)); + + // metadata and claimed scores have been stored as expected. + assert_eq!( + Submissions::::metadata_for(current_round, &10), + Some(SubmissionMetadata { + claimed_score, + deposit: 10, + pages: bounded_vec![false, false, false], + }) + ); + let expected_scores: BoundedVec<(AccountId, ElectionScore), MaxSubmissions> = + bounded_vec![(10, claimed_score)]; + assert_eq!(Submissions::::scores_for(current_round), expected_scores); + + // submit all pages of a noop solution; + let solution = TestNposSolution::default(); + for page in (0..=MultiPhase::msp()).into_iter().rev() { + assert_ok!(SignedPallet::submit_page( + RuntimeOrigin::signed(10), + page, + Some(solution.clone()) + )); + + assert_eq!( + Submissions::::submission_for(10, current_round, page), + Some(solution.clone()) + ); + } + + assert_eq!( + signed_events(), + vec![ + Event::Registered { + round: 0, + who: 10, + claimed_score: ElectionScore { + minimal_stake: 100, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::PageStored { round: 0, who: 10, page: 2 }, + Event::PageStored { round: 0, who: 10, page: 1 }, + Event::PageStored { round: 0, who: 10, page: 0 }, + ] + ); + }) + } + } +} diff --git a/substrate/frame/election-provider-multi-block/src/types.rs b/substrate/frame/election-provider-multi-block/src/types.rs new file mode 100644 index 0000000000000..e903db68e2d77 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/types.rs @@ -0,0 +1,255 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Types for the multi-block election provider pallet and sub-pallets. + +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +use crate::{unsigned::miner::Config as MinerConfig, Verifier}; +use frame_election_provider_support::{ElectionProvider, NposSolution, PageIndex}; +use frame_support::{ + BoundedVec, CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, + RuntimeDebugNoBound, +}; +use sp_npos_elections::ElectionScore; +use sp_runtime::SaturatedConversion; +use sp_std::{boxed::Box, vec::Vec}; + +/// The main account ID type. +pub type AccountIdOf = ::AccountId; + +/// Supports that are returned from a given [`Verifier`]. +pub type SupportsOf = frame_election_provider_support::BoundedSupports< + ::AccountId, + ::MaxWinnersPerPage, + ::MaxBackersPerWinner, +>; + +/// Supports that are returned from a given [`miner::Config`]. +pub type MinerSupportsOf = frame_election_provider_support::BoundedSupports< + ::AccountId, + ::MaxWinnersPerPage, + ::MaxBackersPerWinner, +>; + +/// The voter index. Derived from the solution of the Miner config. +pub type SolutionVoterIndexOf = <::Solution as NposSolution>::VoterIndex; +/// The target index. Derived from the solution of the Miner config. +pub type SolutionTargetIndexOf = <::Solution as NposSolution>::TargetIndex; + +/// The solution type used by this crate. +pub type SolutionOf = ::Solution; + +/// Alias for an error of a fallback election provider. +type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; + +/// Alias for a voter, parameterized by this crate's config. +pub(crate) type VoterOf = + frame_election_provider_support::VoterOf<::DataProvider>; + +/// Same as [`VoterOf`], but parameterized by the `miner::Config`. +pub(crate) type MinerVoterOf = frame_election_provider_support::Voter< + ::AccountId, + ::MaxVotesPerVoter, +>; + +/// Alias for a page of voters, parameterized by this crate's config. +pub(crate) type VoterPageOf = + BoundedVec, ::VoterSnapshotPerBlock>; +/// Alias for a page of targets, parameterized by this crate's config. +pub(crate) type TargetPageOf = + BoundedVec, ::TargetSnapshotPerBlock>; + +/// Same as [`VoterPageOf`], but parameterized by [`miner::Config`]. +pub(crate) type VoterPageMinerOf = + BoundedVec, ::VoterSnapshotPerBlock>; +/// Same as [`TargetPageOf`], but parameterized by []`miner::Config`]. +pub(crate) type TargetPageMinerOf = + BoundedVec<::AccountId, ::TargetSnapshotPerBlock>; + +pub(crate) type MaxWinnersPerPageOf = ::MaxWinnersPerPage; + +/// Alias for all pages of voters, parameterized by the miner's Config. +pub(crate) type AllVoterPagesOf = BoundedVec, ::Pages>; +pub(crate) type AllTargetPagesOf = BoundedVec, ::Pages>; + +/// Edges from voters to nominated targets that are part of the winner set. +pub type AssignmentOf = + sp_npos_elections::Assignment<::AccountId, SolutionAccuracyOf>; + +// Accuracy of the election. +pub type SolutionAccuracyOf = <::Solution as NposSolution>::Accuracy; + +/// Encodes the length of a page of either a solution or a snapshot. +/// +/// This is stored automatically on-chain, and it contains the **size of the entire snapshot page**. +/// This is also used in dispatchables as weight witness data and should **only contain the size of +/// the presented solution page**, not the entire snapshot or page snaphsot. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, Default, TypeInfo)] +pub struct PageSize { + /// The length of voters. + #[codec(compact)] + pub voters: u32, + /// The length of targets. + #[codec(compact)] + pub targets: u32, +} + +/// Strategies for when the election fails. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)] +pub enum ElectionFailureStrategy { + /// Enters in emergency phase when election fails. + Emergency, + /// Restarts the election phase without starting a new era. + Restart, +} + +impl Default for ElectionFailureStrategy { + fn default() -> Self { + ElectionFailureStrategy::Restart + } +} + +/// Current phase of an election. +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)] +pub enum Phase { + /// Election has halted -- nothing will happen. + Halted, + /// The election is off. + Off, + /// Signed phase is open. + Signed, + /// The signed validations phase + SignedValidation(Bn), + Unsigned(Bn), + /// Preparing the paged target and voter snapshots. + Snapshot(PageIndex), + /// Exporting the paged election result (i.e. most likely staking is requesting election + /// pages). It includes the block at which the export phase started. + Export(Bn), + /// Emergency phase, something went wrong and the election is halted. + Emergency, +} + +impl Default for Phase { + fn default() -> Self { + Phase::Off + } +} + +impl Phase { + pub(crate) fn is_signed(&self) -> bool { + matches!(self, Phase::Signed) + } + + pub(crate) fn is_snapshot(&self) -> bool { + matches!(self, Phase::Snapshot(_)) + } + + /// Returns whether the validation phase is ongoing. + pub(crate) fn is_signed_validation_open_at(&self, at: Option) -> bool { + match at { + Some(at) => matches!(self, Phase::SignedValidation(real) if *real == at), + None => matches!(self, Phase::SignedValidation(_)), + } + } + + pub(crate) fn is_unsigned_open_at(&self, at: Bn) -> bool { + matches!(self, Phase::Unsigned(real) if *real == at) + } + + pub(crate) fn is_unsigned(&self) -> bool { + matches!(self, Phase::Unsigned(_)) + } + + pub(crate) fn is_export(&self) -> bool { + matches!(self, Phase::Export(_)) + } +} + +#[derive(DebugNoBound, PartialEq)] +pub enum ElectionError { + /// Error returned by the election data provider. + DataProvider, + /// The data provider returned data that exceeded the boundaries defined in the contract with + /// the election provider. + DataProviderBoundariesExceeded, + /// The support `page_index` was not available at request. + SupportPageNotAvailable(PageIndex), + /// The requested page exceeds the number of election pages defined of the current election + /// config. + RequestedPageExceeded, + /// The fallback election error'ed. + Fallback(FallbackErrorOf), +} + +/// A paged raw solution which contains a set of paginated solutions to be submitted. +/// +/// A raw solution has not been checked for correctness. +#[derive( + TypeInfo, + Encode, + Decode, + RuntimeDebugNoBound, + CloneNoBound, + EqNoBound, + PartialEqNoBound, + MaxEncodedLen, + DefaultNoBound, +)] +#[codec(mel_bound(T: MinerConfig))] +#[scale_info(skip_type_params(T))] +pub struct PagedRawSolution { + pub solution_pages: BoundedVec, T::Pages>, + pub score: ElectionScore, + pub round: u32, +} + +/// A helper trait to deal with the page index of partial solutions. +/// +/// This should only be called on the `Vec` or similar types. If the solution is *full*, +/// it returns a normal iterator that is just mapping the index (usize) to `PageIndex`. +/// +/// if the solution is partial, it shifts the indices sufficiently so that the most significant page +/// of the solution matches with the most significant page of the snapshot onchain. +pub trait Pagify { + fn pagify(&self, bound: PageIndex) -> Box + '_>; + fn into_pagify(self, bound: PageIndex) -> Box>; +} + +impl Pagify for Vec { + fn pagify(&self, desired_pages: PageIndex) -> Box + '_> { + Box::new( + self.into_iter() + .enumerate() + .map(|(p, s)| (p.saturated_into::(), s)) + .map(move |(p, s)| { + let desired_pages_usize = desired_pages as usize; + // TODO: this could be an error. + debug_assert!(self.len() <= desired_pages_usize); + let padding = desired_pages_usize.saturating_sub(self.len()); + let new_page = p.saturating_add(padding.saturated_into::()); + (new_page, s) + }), + ) + } + + fn into_pagify(self, _: PageIndex) -> Box> { + todo!() + } +} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs new file mode 100644 index 0000000000000..ba2d769a11bc0 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs @@ -0,0 +1,88 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Benchmarking for the Elections Multiblock Unsigned sub-pallet. + +use super::*; +use crate::{ + benchmarking::helpers, signed::Config as ConfigSigned, unsigned::Config, BenchmarkingConfig, + Config as ConfigCore, ConfigVerifier, Pallet as PalletCore, Phase, +}; +use frame_system::RawOrigin; + +use frame_benchmarking::v2::*; + +#[benchmarks( + where T: Config + ConfigCore + ConfigSigned + ConfigVerifier, +)] +mod benchmarks { + use super::*; + + #[benchmark] + fn submit_page_unsigned( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + // configs necessary to proceed with the unsigned submission. + PalletCore::::phase_transition(Phase::Unsigned(0u32.into())); + + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + // the last page (0) will also perfom a full feasibility check for all the pages in the + // queue. For this benchmark, we want to ensure that we do not call `submit_page_unsigned` + // on the last page, to avoid this extra step. + assert!(T::Pages::get() >= 2); + + let (claimed_full_score, partial_score, paged_solution) = + OffchainWorkerMiner::::mine(PalletCore::::msp()).map_err(|err| { + log!(error, "mine error: {:?}", err); + BenchmarkError::Stop("miner error") + })?; + + #[extrinsic_call] + _( + RawOrigin::None, + PalletCore::::msp(), + paged_solution, + partial_score, + claimed_full_score, + ); + + Ok(()) + } + + impl_benchmark_test_suite!( + PalletUnsigned, + crate::mock::ExtBuilder::default(), + crate::mock::Runtime, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs new file mode 100644 index 0000000000000..a83cbdafb09c8 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs @@ -0,0 +1,811 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # NPoS miner + +use crate::{ + helpers, + types::{PageSize, Pagify}, + unsigned::{pallet::Config as UnsignedConfig, Call}, + verifier::FeasibilityError, + AssignmentOf, MinerSupportsOf, MinerVoterOf, Pallet as EPM, Snapshot, +}; + +use frame_election_provider_support::{ + ElectionDataProvider, IndexAssignmentOf, NposSolution, NposSolver, PageIndex, + TryIntoBoundedSupports, Weight, +}; +use frame_support::{ensure, traits::Get, BoundedVec}; +use scale_info::TypeInfo; +use sp_npos_elections::{ElectionResult, ElectionScore, ExtendedBalance, Support}; +use sp_runtime::{offchain::storage::StorageValueRef, SaturatedConversion}; +use sp_std::{prelude::ToOwned, vec, vec::Vec}; + +pub type TargetSnaphsotOf = + BoundedVec<::AccountId, ::TargetSnapshotPerBlock>; +pub type VoterSnapshotPagedOf = BoundedVec< + BoundedVec, ::VoterSnapshotPerBlock>, + ::Pages, +>; + +#[derive(Debug, Eq, PartialEq, Clone)] +pub enum MinerError { + /// An internal error in the NPoS elections crate. + NposElections(sp_npos_elections::Error), + /// Snapshot data was unavailable. + SnapshotUnAvailable(SnapshotType), + /// An error from the election solver. + Solver, + /// The solution generated from the miner is not feasible. + Feasibility(FeasibilityError), + InvalidPage, + SubmissionFailed, + NotEnoughTargets, + DataProvider, +} + +impl From for MinerError { + fn from(e: sp_npos_elections::Error) -> Self { + MinerError::NposElections(e) + } +} + +impl From for MinerError { + fn from(e: FeasibilityError) -> Self { + MinerError::Feasibility(e) + } +} + +impl From for MinerError { + fn from(typ: SnapshotType) -> Self { + MinerError::SnapshotUnAvailable(typ) + } +} + +/// The type of the snapshot. +/// +/// Used to express errors. +#[derive(Debug, Eq, PartialEq, Clone)] +pub enum SnapshotType { + /// Voters at the given page missing. + Voters(PageIndex), + /// Targets are missing. + Targets, + // Desired targets are missing. + DesiredTargets, +} + +/// Reports the trimming result of a mined solution +#[derive(Debug, Clone, PartialEq)] +pub struct TrimmingStatus { + weight: usize, + length: usize, +} + +impl Default for TrimmingStatus { + fn default() -> Self { + Self { weight: 0, length: 0 } + } +} + +use crate::PagedRawSolution; +use codec::{EncodeLike, MaxEncodedLen}; + +pub trait Config { + type AccountId: Ord + Clone + codec::Codec + core::fmt::Debug; + + type Solution: codec::Codec + + sp_std::fmt::Debug + + Default + + PartialEq + + Eq + + Clone + + Sized + + Ord + + NposSolution + + TypeInfo + + EncodeLike + + MaxEncodedLen; + + type Solver: NposSolver< + AccountId = Self::AccountId, + Accuracy = ::Accuracy, + >; + + type Pages: Get; + + type MaxVotesPerVoter: Get; + type MaxWinnersPerPage: Get; + type MaxBackersPerWinner: Get; + + type VoterSnapshotPerBlock: Get; + type TargetSnapshotPerBlock: Get; + + type MaxWeight: Get; + type MaxLength: Get; +} + +pub struct Miner(sp_std::marker::PhantomData); + +impl Miner { + pub fn mine_paged_solution_with_snapshot( + all_voter_pages: &BoundedVec< + BoundedVec, T::VoterSnapshotPerBlock>, + T::Pages, + >, + all_targets: &BoundedVec, + pages: PageIndex, + round: u32, + desired_targets: u32, + do_reduce: bool, + ) -> Result<(PagedRawSolution, TrimmingStatus), MinerError> { + // useless to proceed if the solution will not be feasible. + ensure!(all_targets.len() >= desired_targets as usize, MinerError::NotEnoughTargets); + + // flatten pages of voters and target snapshots. + let all_voters: Vec> = + all_voter_pages.iter().cloned().flatten().collect::>(); + + // these closures generate an efficient index mapping of each tvoter -> the snaphot + // that they are part of. this needs to be the same indexing fn in the verifier side to + // sync when reconstructing the assingments page from a solution. + //let binding_targets = all_targets.clone(); + let voters_page_fn = helpers::generate_voter_page_fn::(&all_voter_pages); + let targets_index_fn = helpers::target_index_fn::(&all_targets); + + // run the election with all voters and targets. + let ElectionResult { winners: _, assignments } = ::solve( + desired_targets as usize, + all_targets.clone().to_vec(), + all_voters.clone(), + ) + .map_err(|_| MinerError::Solver)?; + + if do_reduce { + // TODO(gpestana): reduce and trim. + } + // split assignments into `T::Pages pages. + let mut paged_assignments: BoundedVec>, T::Pages> = + BoundedVec::with_bounded_capacity(pages as usize); + + paged_assignments.bounded_resize(pages as usize, vec![]); + + // adds assignment to the correct page, based on the voter's snapshot page. + for assignment in assignments { + let page = voters_page_fn(&assignment.who).ok_or(MinerError::InvalidPage)?; + let assignment_page = + paged_assignments.get_mut(page as usize).ok_or(MinerError::InvalidPage)?; + assignment_page.push(assignment); + } + + // convert each page of assignments to a paged `T::Solution`. + let solution_pages: BoundedVec<::Solution, T::Pages> = paged_assignments + .clone() + .into_iter() + .enumerate() + .map(|(page_index, assignment_page)| { + let page: PageIndex = page_index.saturated_into(); + let voter_snapshot_page = all_voter_pages + .get(page as usize) + .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Voters(page)))?; + + let voters_index_fn = { + let cache = helpers::generate_voter_cache::(&voter_snapshot_page); + helpers::voter_index_fn_owned::(cache) + }; + + <::Solution>::from_assignment( + &assignment_page, + &voters_index_fn, + &targets_index_fn, + ) + .map_err(|e| MinerError::NposElections(e)) + }) + .collect::, _>>()? + .try_into() + .expect("paged_assignments is bound by `T::Pages. qed."); + + // TODO(gpestana): trim again? + let trimming_status = Default::default(); + + let mut paged_solution = + PagedRawSolution { solution_pages, score: Default::default(), round }; + + // everytthing's ready - calculate final solution score. + paged_solution.score = + Self::compute_score(all_voter_pages, all_targets, &paged_solution, desired_targets)?; + + Ok((paged_solution, trimming_status)) + } + + /// Take the given raw paged solution and compute its score. This will replicate what the chain + /// would do as closely as possible, and expects all the corresponding snapshot data to be + /// available. + fn compute_score( + voters: &VoterSnapshotPagedOf, + targets: &TargetSnaphsotOf, + paged_solution: &PagedRawSolution, + desired_targets: u32, + ) -> Result { + use sp_npos_elections::EvaluateSupport; + use sp_std::collections::btree_map::BTreeMap; + + let all_supports = + Self::feasibility_check(voters, targets, paged_solution, desired_targets)?; + let mut total_backings: BTreeMap = BTreeMap::new(); + all_supports.into_iter().map(|x| x.0).flatten().for_each(|(who, support)| { + let backing = total_backings.entry(who).or_default(); + *backing = backing.saturating_add(support.total); + }); + + let all_supports = total_backings + .into_iter() + .map(|(who, total)| (who, Support { total, ..Default::default() })) + .collect::>(); + + Ok((&all_supports).evaluate()) + } + + // Checks the feasibility of a paged solution and calculates the score associated with the + // page. + pub fn compute_partial_score( + voters: &VoterSnapshotPagedOf, + targets: &TargetSnaphsotOf, + solution: &::Solution, + desired_targets: u32, + page: PageIndex, + ) -> Result { + let supports = Self::feasibility_check_partial( + voters, + targets, + solution.clone(), + desired_targets, + page, + )?; + let score = sp_npos_elections::evaluate_support( + supports.clone().into_iter().map(|(_, backings)| backings), + ); + + Ok(score) + } + + /// Perform the feasibility check on all pages of a solution, one by one, and returns the + /// supports of the full solution. + pub fn feasibility_check( + voters: &VoterSnapshotPagedOf, + targets: &TargetSnaphsotOf, + paged_solution: &PagedRawSolution, + desired_targets: u32, + ) -> Result>, MinerError> { + // check every solution page for feasibility. + paged_solution + .solution_pages + .pagify(T::Pages::get()) + .map(|(page_index, page_solution)| { + Self::feasibility_check_partial( + voters, + targets, + page_solution.clone(), + desired_targets, + page_index as PageIndex, + ) + }) + .collect::, _>>() + .map_err(|err| MinerError::from(err)) + } + + /// Performs the feasibility check of a single page, returns the supports of the partial + /// feasibility check. + pub fn feasibility_check_partial( + voters: &VoterSnapshotPagedOf, + targets: &TargetSnaphsotOf, + partial_solution: ::Solution, + desired_targets: u32, + page: PageIndex, + ) -> Result, FeasibilityError> { + // TODO: double check page index if tests ERR. + let voters_page: BoundedVec, ::VoterSnapshotPerBlock> = voters + .get(page as usize) + .ok_or(FeasibilityError::Incomplete) + .map(|v| v.to_owned())?; + + let voter_cache = helpers::generate_voter_cache::(&voters_page); + let voter_at = helpers::voter_at_fn::(&voters_page); + let target_at = helpers::target_at_fn::(targets); + let voter_index = helpers::voter_index_fn_usize::(&voter_cache); + + // Then convert solution -> assignment. This will fail if any of the indices are + // gibberish. + let assignments = partial_solution + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + + // Ensure that assignments are all correct. + let _ = assignments + .iter() + .map(|ref assignment| { + // Check that assignment.who is actually a voter (defensive-only). NOTE: while + // using the index map from `voter_index` is better than a blind linear search, + // this *still* has room for optimization. Note that we had the index when we + // did `solution -> assignment` and we lost it. Ideal is to keep the index + // around. + + // Defensive-only: must exist in the snapshot. + let snapshot_index = + voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; + // Defensive-only: index comes from the snapshot, must exist. + let (_voter, _stake, targets) = + voters_page.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; + debug_assert!(*_voter == assignment.who); + + // Check that all of the targets are valid based on the snapshot. + if assignment.distribution.iter().any(|(t, _)| !targets.contains(t)) { + return Err(FeasibilityError::InvalidVote) + } + Ok(()) + }) + .collect::>()?; + + // ----- Start building support. First, we need one more closure. + let stake_of = helpers::stake_of_fn::(&voters_page, &voter_cache); + + // This might fail if the normalization fails. Very unlikely. See `integrity_test`. + let staked_assignments = + sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + + let supports = sp_npos_elections::to_supports(&staked_assignments); + + // Check the maximum number of backers per winner. If this is a single-page solution, this + // is enough to check `MaxBackersPerWinner`. Else, this is just a heuristic, and needs to be + // checked again at the end (via `QueuedSolutionBackings`). + ensure!( + supports + .iter() + .all(|(_, s)| (s.voters.len() as u32) <= T::MaxBackersPerWinner::get()), + FeasibilityError::TooManyBackings + ); + + // supports per page must not be higher than the desired targets, otherwise final solution + // will also be higher than desired_targets. + ensure!((supports.len() as u32) <= desired_targets, FeasibilityError::WrongWinnerCount); + + // almost-defensive-only: `MaxBackersPerWinner` is already checked. A sane value of + // `MaxWinnersPerPage` should be more than any possible value of `desired_targets()`, which + // is ALSO checked, so this conversion can almost never fail. + let bounded_supports = supports + .try_into_bounded_supports() + .map_err(|_| FeasibilityError::WrongWinnerCount)?; + + Ok(bounded_supports) + } + + /// Greedily reduce the size of the solution to fit into the block w.r.t length. + /// + /// The length of the solution is largely a function of the number of voters. The number of + /// winners cannot be changed Thus, to reduce the solution size, we need to strip voters. + /// + /// Note that this solution is already computed, and winners are elected based on the merit of + /// the total stake in the system. Nevertheless, some of the voters may be removed here. + /// + /// Sometimes, removing a voter can cause a validator to also be implicitly removed, if + /// that voter was the only backer of that winner. In such cases, this solution is invalid, + /// which will be caught prior to submission. + /// + /// The score must be computed **after** this step. If this step reduces the score too much, + /// then the solution must be discarded. + pub fn trim_assignments_length( + max_allowed_length: u32, + assignments: &mut Vec>, + encoded_size_of: impl Fn( + &[IndexAssignmentOf], + ) -> Result, + ) -> Result { + // Perform a binary search for the max subset of which can fit into the allowed + // length. Having discovered that, we can truncate efficiently. + let max_allowed_length: usize = max_allowed_length.saturated_into(); + let mut high = assignments.len(); + let mut low = 0; + + // not much we can do if assignments are already empty. + if high == low { + return Ok(0) + } + + while high - low > 1 { + let test = (high + low) / 2; + if encoded_size_of(&assignments[..test])? <= max_allowed_length { + low = test; + } else { + high = test; + } + } + let maximum_allowed_voters = if low < assignments.len() && + encoded_size_of(&assignments[..low + 1])? <= max_allowed_length + { + low + 1 + } else { + low + }; + + // ensure our post-conditions are correct + //debug_assert!( + // encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length + //); + debug_assert!(if maximum_allowed_voters < assignments.len() { + encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() > + max_allowed_length + } else { + true + }); + + // NOTE: before this point, every access was immutable. + // after this point, we never error. + // check before edit. + + let remove = assignments.len().saturating_sub(maximum_allowed_voters); + assignments.truncate(maximum_allowed_voters); + + Ok(remove) + } + + /// Greedily reduce the size of the 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. + /// `assignments.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 from the `assignments`. + /// + /// Note that the solution is already computed, and the winners are elected based on the merit + /// of the 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 or remove a winner, then the solution must be discarded **after** this step. + pub fn trim_assignments_weight( + desired_targets: u32, + size: PageSize, + max_weight: Weight, + assignments: &mut Vec>, + ) -> usize { + let maximum_allowed_voters = + Self::maximum_voter_for_weight(desired_targets, size, max_weight); + let removing: usize = + assignments.len().saturating_sub(maximum_allowed_voters.saturated_into()); + assignments.truncate(maximum_allowed_voters as usize); + + removing + } + + /// Find the maximum `len` that a solution can have in order to fit into the block weight. + /// + /// This only returns a value between zero and `size.nominators`. + pub fn maximum_voter_for_weight( + _desired_winners: u32, + size: PageSize, + max_weight: Weight, + ) -> u32 { + if size.voters < 1 { + return size.voters + } + + let max_voters = size.voters.max(1); + let mut voters = max_voters; + + // helper closures. + let weight_with = |_active_voters: u32| -> Weight { + Weight::zero() // TODO + }; + + let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { + if current_weight.all_lt(max_weight) { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } else if current_weight.any_gt(max_weight) { + voters.checked_sub(step).ok_or(()) + } else { + // If any of the constituent weights is equal to the max weight, we're at max + 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 /= 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 < max_voters && weight_with(voters + 1).all_lt(max_weight) { + voters += 1; + } + while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { + voters -= 1; + } + + let final_decision = voters.min(size.voters); + debug_assert!( + weight_with(final_decision).all_lte(max_weight), + "weight_with({}) <= {}", + final_decision, + max_weight, + ); + final_decision + } +} + +/// Errors associated with the off-chain worker miner. +#[derive( + frame_support::DebugNoBound, frame_support::EqNoBound, frame_support::PartialEqNoBound, +)] +pub enum OffchainMinerError { + Miner(MinerError), + PoolSubmissionFailed, + NotUnsignedPhase, + StorageError, + PageOutOfBounds, + Snapshots, +} + +impl From for OffchainMinerError { + fn from(e: MinerError) -> Self { + OffchainMinerError::Miner(e) + } +} + +/// A miner used in the context of the offchain worker for unsigned submissions. +pub(crate) struct OffchainWorkerMiner(sp_std::marker::PhantomData); + +impl OffchainWorkerMiner { + /// The off-chain storage lock to work with unsigned submissions. + pub(crate) const OFFCHAIN_LOCK: &'static [u8] = b"parity/multi-block-unsigned-election/lock"; + + /// The off-chain storage ID prefix for each of the solution's pages. Each page will be + /// prefixed by this ID, followed by the page index. The full page ID for a given index can be + /// generated by [`Self::page_cache_id`]. + pub(crate) const OFFCHAIN_CACHED_SOLUTION: &'static [u8] = + b"parity/multi-block-unsigned-election/solution"; + + /// The off-chain storage ID for the solution's full score. + pub(crate) const OFFCHAIN_CACHED_SCORE: &'static [u8] = + b"parity/multi-block-unsigned-election/score"; + + /// Mine a solution. + /// + /// Mines a new solution with [`crate::Pallet::Pages`] pages and computes the partial score + /// of the page with `page` index. + pub fn mine( + page: PageIndex, + ) -> Result< + (ElectionScore, ElectionScore, ::Solution), + OffchainMinerError, + > { + let reduce = true; + + let (all_voter_pages, all_targets) = Self::fetch_snapshots()?; + let round = crate::Pallet::::current_round(); + let desired_targets = + <::DataProvider as ElectionDataProvider>::desired_targets() + .map_err(|_| MinerError::DataProvider)?; + + let (solution, _trimming_status) = + Miner::::mine_paged_solution_with_snapshot( + &all_voter_pages, + &all_targets, + T::Pages::get(), + round, + desired_targets, + reduce, + )?; + + let partial_solution = solution + .solution_pages + .get(page as usize) + .ok_or(OffchainMinerError::PageOutOfBounds)?; + + let partial_score = Miner::::compute_partial_score( + &all_voter_pages, + &all_targets, + &partial_solution, + desired_targets, + page, + )?; + + Ok((solution.score, partial_score, partial_solution.clone())) + } + + pub(crate) fn fetch_snapshots() -> Result< + (VoterSnapshotPagedOf, TargetSnaphsotOf), + OffchainMinerError, + > { + // prepare range to fetch all pages of the target and voter snapshot. + let paged_range = 0..EPM::::msp() + 1; + + // fetch all pages of the voter snapshot and collect them in a bounded vec. + let all_voter_pages: BoundedVec<_, T::Pages> = paged_range + .map(|page| { + Snapshot::::voters(page) + .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Voters(page))) + }) + .collect::, _>>()? + .try_into() + .expect("range was constructed from the bounded vec bounds; qed."); + + // fetch all pages of the target snapshot and collect them in a bounded vec. + let all_targets = Snapshot::::targets() + .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Targets))?; + + Ok((all_voter_pages, all_targets)) + } + + /// Fetches from the local storage or mines a new solution. + /// + /// Calculates and returns the partial score of paged solution of the given `page` index. + pub fn fetch_or_mine( + page: PageIndex, + ) -> Result< + (ElectionScore, ElectionScore, ::Solution), + OffchainMinerError, + > { + let cache_id = Self::paged_cache_id(page)?; + let score_storage = StorageValueRef::persistent(&Self::OFFCHAIN_CACHED_SCORE); + let maybe_storage = StorageValueRef::persistent(&cache_id); + + let (full_score, paged_solution, partial_score) = + if let Ok(Some((solution_page, partial_score))) = + maybe_storage.get::<(::Solution, ElectionScore)>() + { + sublog!(debug, "unsigned::ocw-miner", "offchain restoring a solution from cache."); + + let full_score = score_storage + .get() + .map_err(|_| OffchainMinerError::StorageError)? + .ok_or(OffchainMinerError::StorageError)?; + + (full_score, solution_page, partial_score) + } else { + // no solution cached, compute it first. + sublog!(debug, "unsigned::ocw-miner", "offchain miner computing a new solution."); + + // fetch snapshots. + let (all_voter_pages, all_targets) = Self::fetch_snapshots()?; + let round = crate::Pallet::::current_round(); + let desired_targets = + <::DataProvider as ElectionDataProvider>::desired_targets() + .map_err(|_| MinerError::DataProvider)?; + + let reduce = false; // TODO + + let (solution, _trimming_status) = + Miner::::mine_paged_solution_with_snapshot( + &all_voter_pages, + &all_targets, + T::Pages::get(), + round, + desired_targets, + reduce, + )?; + + // caches the solution score. + score_storage + .mutate::<_, (), _>(|_| Ok(solution.score.clone())) + .map_err(|_| OffchainMinerError::StorageError)?; + + let mut solution_page = Default::default(); + let mut partial_score_r: ElectionScore = Default::default(); + + // caches each of the individual pages and their partial score under its own key. + for (idx, paged_solution) in solution.solution_pages.into_iter().enumerate() { + let partial_score = Miner::::compute_partial_score( + &all_voter_pages, + &all_targets, + &paged_solution, + desired_targets, + idx as u32, + )?; + + let cache_id = Self::paged_cache_id(idx as PageIndex)?; + let storage = StorageValueRef::persistent(&cache_id); + storage + .mutate::<_, (), _>(|_| Ok((paged_solution.clone(), partial_score))) + .map_err(|_| OffchainMinerError::StorageError)?; + + // save to return the requested paged solution and partial score. + if idx as PageIndex == page { + solution_page = paged_solution; + partial_score_r = partial_score; + } + } + (solution.score, solution_page, partial_score_r) + }; + + Ok((full_score, partial_score, paged_solution)) + } + + /// Clears all local storage items related to the unsigned off-chain miner. + pub(crate) fn clear_cache() { + let mut score_storage = StorageValueRef::persistent(&Self::OFFCHAIN_CACHED_SCORE); + score_storage.clear(); + + for idx in (0..::Pages::get()).into_iter() { + let cache_id = Self::paged_cache_id(idx as PageIndex) + .expect("page index was calculated based on the msp."); + let mut page_storage = StorageValueRef::persistent(&cache_id); + + page_storage.clear(); + } + + sublog!(debug, "unsigned", "offchain miner cache cleared."); + } + + /// Generate the page cache ID based on the `page` index and the + /// [`Self::OFFCHAIN_CACHED_SOLUTION`] prefix. + fn paged_cache_id(page: PageIndex) -> Result, OffchainMinerError> { + let mut id = Self::OFFCHAIN_CACHED_SOLUTION.to_vec(); + id.push(page.try_into().map_err(|_| OffchainMinerError::PageOutOfBounds)?); + Ok(id) + } + + /// Submits a paged solution through the [`Call::submit_page_unsigned`] callable as an + /// inherent. + pub(crate) fn submit_paged_call( + page: PageIndex, + solution: ::Solution, + partial_score: ElectionScore, + claimed_full_score: ElectionScore, + ) -> Result<(), OffchainMinerError> { + sublog!( + debug, + "unsigned::ocw-miner", + "miner submitting a solution as an unsigned transaction, page: {:?}", + page, + ); + + let call = Call::submit_page_unsigned { page, solution, partial_score, claimed_full_score }; + frame_system::offchain::SubmitTransaction::>::submit_unsigned_transaction( + call.into(), + ) + .map(|_| { + sublog!( + debug, + "unsigned::ocw-miner", + "miner submitted a solution as an unsigned transaction, page {:?}", + page + ); + }) + .map_err(|_| OffchainMinerError::PoolSubmissionFailed) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs new file mode 100644 index 0000000000000..a675907e13e49 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs @@ -0,0 +1,360 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Unsigned sub-pallet +//! +//! The main goal of this sub-pallet is to manage the unsigned phase submissions by an off-chain +//! worker. It implements the `offchain_worker` hook which will compute and store +//! in the off-chain cache a paged solution and try to submit it if: +//! +//! - Current phase is [`crate::Phase::Unsigned`]; +//! - The score of the computed solution is better than the minimum score defined by the verifier +//! pallet and the current election score stored by the [`crate::signed::Pallet`]. +//! +//! During the unsigned phase, multiple block builders will collaborate to submit the full +//! solution, one page per block. +//! +//! ## Sync/Async off-chain worker +//! +//! The unsigned phase relies on a mix of sync and async checks to ensure that the paged unsigned +//! submissions (and final solution) are correct, namely: +//! +//! - Synchronous checks: each block builder will compute the *full* election solution. However, +//! only one page +//! is verified through the [Verifier::verify_synchronous] and submitted through the +//! [`Call::submit_page_unsigned`] callable as an inherent. +//! - Asynchronous checks: once all pages are submitted, the [`Call::submit_page_unsigned`] will +//! call [`verifier::AsyncVerifier::force_finalize_verification`] to ensure that the full solution +//! submitted by all the block builders is good. +//! +//! In sum, each submitted page is verified using the synchronous verification implemented by the +//! verifier pallet (i.e. [`verifier::Verifier::verify_synchronous`]). The pages are submitted by +//! order from [`crate::Pallet::msp`] down to [`crate::Pallet::lsp`]. After successfully submitting +//! the last page, the [`verifier::AsyncVerifier::force_finalize_verification`], which will perform +//! the last feasibility checks over the full stored solution. +//! +//! At each block of the unsigned phase, the block builder running the node with the off-chain +//! worker enabled will compute a solution based on the round's snapshot. The solution is pagified +//! and stored in the local cache. +//! +//! The off-chain miner will *always* compute a new solution regardless of whether there +//! is a queued solution for the current era. The solution will be added to the storage through the +//! inherent [`Call::submit_page_unsigned`] only if the computed (total) solution score is strictly +//! better than the current queued solution. + +pub mod miner; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +mod tests; + +use crate::{ + unsigned::{ + miner::{OffchainMinerError, OffchainWorkerMiner}, + weights::WeightInfo, + }, + verifier, Phase, SolutionOf, Verifier, +}; +use frame_election_provider_support::PageIndex; +use frame_support::{ + ensure, + pallet_prelude::{TransactionValidity, ValidTransaction}, + traits::Get, +}; +use frame_system::{offchain::SendTransactionTypes, pallet_prelude::BlockNumberFor}; +use sp_npos_elections::ElectionScore; +use sp_runtime::SaturatedConversion; + +// public re-exports. +pub use pallet::{ + Call, Config, Event, Pallet, __substrate_call_check, __substrate_event_check, + __substrate_validate_unsigned_check, tt_default_parts, tt_default_parts_v2, tt_error_token, +}; + +#[frame_support::pallet(dev_mode)] +pub(crate) mod pallet { + + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::{ + ensure_none, + pallet_prelude::{BlockNumberFor, OriginFor}, + }; + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: crate::Config + SendTransactionTypes> { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The off-chain worker interval between retrying to submit a solution. + type OffchainRepeatInterval: Get>; + + /// The priority of the unsigned tx submitted. + type MinerTxPriority: Get; + + /// Maximum length of the solution that the miner is allowed to generate. + /// + /// Solutions are trimmed to respect this. + type MaxLength: Get; + + /// Maximum weight of the solution that the miner is allowed to generate. + /// + /// Solutions are trimmed to respect this. + /// + /// The weight is computed using `solution_weight`. + type MaxWeight: Get; + + /// The weights for this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Unsigned solution submitted successfully. + UnsignedSolutionSubmitted { at: BlockNumberFor, page: PageIndex }, + } + + #[pallet::validate_unsigned] + impl ValidateUnsigned for Pallet { + type Call = Call; + + fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { + if let Call::submit_page_unsigned { page, partial_score, .. } = call { + ValidTransaction::with_tag_prefix("ElectionOffchainWorker") + // priority increases propotional to the `solution.minimal_stake`. + .priority( + T::MinerTxPriority::get() + .saturating_add(partial_score.minimal_stake.saturated_into()), + ) + // deduplicates unsigned solutions since each validator should calculate at most + // one paged solution per block. + .and_provides(page) + // transaction stays in the pool as long as the unsigned phase. + .longevity(T::UnsignedPhase::get().saturated_into::()) + .propagate(false) + .build() + } else { + sublog!(info, "unsigned", "validate_unsigned ERROR"); + InvalidTransaction::Call.into() + } + } + } + + #[pallet::call] + impl Pallet { + /// Submit a paged unsigned solution. + /// + /// The dispatch origin fo this call must be __none__. + /// + /// This submission is checked on the fly. Moreover, this unsigned solution is only + /// validated when submitted to the pool from the **local** node. Effectively, this means + /// that only active validators can submit this transaction when authoring a block (similar + /// to an inherent). + /// + /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will + /// panic if the solution submitted by the validator is invalid in any way, effectively + /// putting their authoring reward at risk. + /// + /// No deposit or reward is associated with this submission. + #[pallet::call_index(1)] + #[pallet::weight(::WeightInfo::submit_page_unsigned( + ::MaxBackersPerWinner::get(), + ::MaxWinnersPerPage::get(), + ))] + pub fn submit_page_unsigned( + origin: OriginFor, + page: PageIndex, + solution: SolutionOf, + partial_score: ElectionScore, + claimed_full_score: ElectionScore, + ) -> DispatchResult { + ensure_none(origin)?; + let error_message = "Invalid unsigned submission must produce invalid block and \ + deprive validator from their authoring reward."; + + sublog!( + info, + "unsigned", + "submitting page {:?} with partial score {:?}", + page, + partial_score + ); + + // Check if score is an improvement, the current phase, page index and other paged + // solution metadata checks. + Self::pre_dispatch_checks(page, &claimed_full_score).expect(error_message); + + // The verifier will store the paged solution, if valid. + let _ = ::verify_synchronous( + solution, + partial_score, + page, + ) + .expect(error_message); + + // if all pages have been submitted, request an async verification finalization which + // will work on the queued paged solutions. + if ::next_missing_solution_page().is_none() { + ::force_finalize_verification( + claimed_full_score, + ) + .expect(error_message); + sublog!(info, "unsigned", "validate_unsigned last page verify OK"); + } else { + sublog!(info, "unsigned", "submit_page_unsigned: page {:?} submitted", page); + } + + Self::deposit_event(Event::UnsignedSolutionSubmitted { + at: >::block_number(), + page, + }); + + Ok(()) + } + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_n: BlockNumberFor) -> Weight { + if crate::Pallet::::current_phase() == Phase::Off { + T::DbWeight::get().reads_writes(1, 1) + } else { + Default::default() + } + } + + /// The off-chain worker implementation + /// + /// The off-chain worker for this pallet will run IFF: + /// + /// - It can obtain the off-chain worker lock; + /// - The current block is part of the unsigned phase; + fn offchain_worker(now: BlockNumberFor) { + use sp_runtime::offchain::storage_lock::{BlockAndTime, StorageLock}; + + let mut lock = + StorageLock::>>::with_block_deadline( + miner::OffchainWorkerMiner::::OFFCHAIN_LOCK, + T::UnsignedPhase::get().saturated_into(), + ); + + if crate::Pallet::::current_phase().is_unsigned() { + match lock.try_lock() { + Ok(_guard) => { + sublog!(info, "unsigned", "obtained offchain lock at {:?}", now); + let _ = Self::do_sync_offchain_worker(now).map_err(|e| { + sublog!(debug, "unsigned", "offchain worker error."); + e + }); + }, + Err(deadline) => { + sublog!( + debug, + "unsigned", + "offchain worker lock not released, deadline is {:?}", + deadline + ); + }, + }; + } + } + + fn integrity_test() { + // TODO + } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + todo!() + } + } +} + +impl Pallet { + /// Perform the off-chain worker workload. + /// + /// If the current block is part of the unsigned phase and there are missing solution pages: + /// + /// 1. Compute or restore a mined solution; + /// 2. Pagify the solution; + /// 3. Calculate the partial score for the page to submit; + /// 4. Verify if the *total* solution is strictly better than the current queued solution or + /// better than the minimum score, of no queued solution exists. + /// 5. Submits the paged solution as an inherent through the [`Call::submit_page_unsigned`] + /// callable. + pub fn do_sync_offchain_worker(_now: BlockNumberFor) -> Result<(), OffchainMinerError> { + let missing_solution_page = ::next_missing_solution_page(); + + match (crate::Pallet::::current_phase(), missing_solution_page) { + (Phase::Unsigned(_), Some(page)) => { + let (full_score, partial_score, partial_solution) = + OffchainWorkerMiner::::fetch_or_mine(page).map_err(|err| { + sublog!(error, "unsigned", "OCW mine error: {:?}", err); + err + })?; + + // submit page only if full score improves the current queued score. + if ::ensure_score_improves(full_score) { + OffchainWorkerMiner::::submit_paged_call( + page, + partial_solution, + partial_score, + full_score, + )?; + } else { + sublog!( + debug, + "unsigned", + "unsigned solution with score {:?} does not improve current queued solution; skip it.", + full_score + ); + } + }, + (Phase::Export(_), _) | (Phase::Unsigned(_), None) => { + // Unsigned phase is over or unsigned solution is no more required, clear the + // cache. + OffchainWorkerMiner::::clear_cache(); + }, + _ => (), // nothing to do here. + } + + Ok(()) + } + + /// Ihnerent pre-dispatch checks. + pub(crate) fn pre_dispatch_checks( + page: PageIndex, + claimed_full_score: &ElectionScore, + ) -> Result<(), ()> { + // timing and metadata checks. + ensure!(crate::Pallet::::current_phase().is_unsigned(), ()); + ensure!(page <= crate::Pallet::::msp(), ()); + + // full solution score check. + ensure!(::ensure_score_improves(*claimed_full_score), ()); + + Ok(()) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs b/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs new file mode 100644 index 0000000000000..b37cc6bf43459 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs @@ -0,0 +1,216 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate::{ + mock::*, unsigned::miner::Config, PagedTargetSnapshot, PagedVoterSnapshot, Phase, Snapshot, + Verifier, +}; + +use frame_election_provider_support::ElectionProvider; +use frame_support::assert_ok; + +mod calls { + use super::*; + + #[test] + fn unsigned_submission_works() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); + ext.execute_with(|| { + // election predicted at 30. + assert_eq!(election_prediction(), 30); + + // no solution available until the unsigned phase. + assert!(::queued_score().is_none()); + assert!(::get_queued_solution(2).is_none()); + + // progress through unsigned phase just before the election. + roll_to_with_ocw(29, Some(pool.clone())); + + // successful submission events for all 3 pages, as expected. + assert_eq!( + unsigned_events(), + [ + Event::UnsignedSolutionSubmitted { at: 19, page: 2 }, + Event::UnsignedSolutionSubmitted { at: 20, page: 1 }, + Event::UnsignedSolutionSubmitted { at: 21, page: 0 } + ] + ); + // now, solution exists. + assert!(::queued_score().is_some()); + assert!(::get_queued_solution(2).is_some()); + assert!(::get_queued_solution(1).is_some()); + assert!(::get_queued_solution(0).is_some()); + + // roll to election prediction bn. + roll_to_with_ocw(election_prediction(), Some(pool.clone())); + + // still in unsigned phase (after unsigned submissions have been submitted and before + // the election happened). + assert!(current_phase().is_unsigned()); + + // elect() works as expected. + assert!(call_elect().is_ok()); + + assert_eq!(current_phase(), Phase::Off); + }) + } + + #[test] + fn unsigned_submission_no_snapshot() { + let (mut ext, pool) = ExtBuilder::default().build_offchainify(1); + ext.execute_with(|| { + // election predicted at 30. + assert_eq!(election_prediction(), 30); + + roll_to_phase_with_ocw(Phase::Signed, Some(pool.clone())); + + // no solution available until the unsigned phase. + assert!(::queued_score().is_none()); + assert!(::get_queued_solution(2).is_none()); + + // but snapshot exists. + assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); + assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_some()); + // so let's clear it. + clear_snapshot(); + assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_none()); + assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_none()); + + // progress through unsigned phase just before the election. + roll_to_with_ocw(29, Some(pool.clone())); + + // snapshot was not available, so unsigned submissions and thus no solution queued. + assert_eq!(unsigned_events().len(), 0); + // no solution available until the unsigned phase. + assert!(::queued_score().is_none()); + assert!(::get_queued_solution(2).is_none()); + + // call elect (which fails) to restart the phase. + assert!(call_elect().is_err()); + assert_eq!(current_phase(), Phase::Off); + + roll_to_phase_with_ocw(Phase::Signed, Some(pool.clone())); + + // snapshot exists now. + assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); + assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_some()); + + roll_to_with_ocw(election_prediction() - 1, Some(pool.clone())); + + // successful submission events for all 3 pages, as expected. + assert_eq!( + unsigned_events(), + [ + Event::UnsignedSolutionSubmitted { at: 49, page: 2 }, + Event::UnsignedSolutionSubmitted { at: 50, page: 1 }, + Event::UnsignedSolutionSubmitted { at: 51, page: 0 } + ] + ); + // now, solution exists. + assert!(::queued_score().is_some()); + assert!(::get_queued_solution(2).is_some()); + assert!(::get_queued_solution(1).is_some()); + assert!(::get_queued_solution(0).is_some()); + + // elect() works as expected. + assert_ok!(::elect(2)); + assert_ok!(::elect(1)); + assert_ok!(::elect(0)); + + assert_eq!(current_phase(), Phase::Off); + }) + } +} + +mod miner { + use super::*; + + type OffchainSolver = ::Solver; + + #[test] + fn snapshot_idx_based_works() { + ExtBuilder::default().build_and_execute(|| { + roll_to_phase(Phase::Signed); + + let mut all_voter_pages = vec![]; + let mut all_target_pages = vec![]; + + for page in (0..Pages::get()).rev() { + all_voter_pages.push(Snapshot::::voters(page).unwrap()); + all_target_pages.push(Snapshot::::targets().unwrap()); + } + }) + } + + #[test] + fn desired_targets_bounds_works() { + ExtBuilder::default() + .max_winners_per_page(3) + .desired_targets(3) + .build_and_execute(|| { + // max winner per page == desired_targets, OK. + compute_snapshot_checked(); + assert_ok!(mine_and_verify_all()); + + // max winner per page > desired_targets, OK. + MaxWinnersPerPage::set(4); + compute_snapshot_checked(); + assert_ok!(mine_and_verify_all()); + + // max winner per page < desired_targets, fails. + MaxWinnersPerPage::set(2); + compute_snapshot_checked(); + assert!(mine_and_verify_all().is_err()); + }) + } + + #[test] + fn fetch_or_mine() { + let (mut ext, _) = ExtBuilder::default().build_offchainify(1); + + ext.execute_with(|| { + let msp = crate::Pallet::::msp(); + assert_eq!(msp, 2); + + // no snapshot available, calling mine_paged_solution should fail. + assert!(::queued_score().is_none()); + assert!(::get_queued_solution(msp).is_none()); + + assert!(OffchainWorkerMiner::::fetch_or_mine(0).is_err()); + compute_snapshot_checked(); + + let (full_score_2, partial_score_2, _) = + OffchainWorkerMiner::::fetch_or_mine(msp).unwrap(); + let (full_score_1, partial_score_1, _) = + OffchainWorkerMiner::::fetch_or_mine(msp - 1).unwrap(); + let (full_score_0, partial_score_0, _) = + OffchainWorkerMiner::::fetch_or_mine(0).unwrap(); + + assert!(full_score_2 == full_score_1 && full_score_2 == full_score_0); + assert!( + full_score_2.sum_stake == full_score_1.sum_stake && + full_score_2.sum_stake == full_score_0.sum_stake + ); + + assert_eq!( + partial_score_0.sum_stake + partial_score_1.sum_stake + partial_score_2.sum_stake, + full_score_0.sum_stake + ); + }) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs b/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs new file mode 100644 index 0000000000000..fc15d96bbae4e --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs @@ -0,0 +1,85 @@ + +//! Autogenerated weights for `pallet_epm_unsigned` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-02, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gpestanas-MBP.lan`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// /Users/gpestana/cargo_target/debug/staking-node +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet-epm-unsigned +// --extrinsic +// * +// --steps +// 2 +// --repeat +// 1 +// --output +// unsigned_weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +pub trait WeightInfo { + fn submit_page_unsigned(v: u32, t: u32) -> Weight; +} + +/// Weight functions for `pallet_epm_unsigned`. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::MinimumScore` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::MinimumScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn submit_page_unsigned(v: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `11869 + t * (10 ±0) + v * (71 ±0)` + // Estimated: `15334 + t * (10 ±0) + v * (71 ±0)` + // Minimum execution time: 1_382_000_000 picoseconds. + Weight::from_parts(3_157_322_580, 0) + .saturating_add(Weight::from_parts(0, 15334)) + // Standard Error: 80_316 + .saturating_add(Weight::from_parts(4_146_169, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 71).saturating_mul(v.into())) + } +} + + +impl WeightInfo for () { + fn submit_page_unsigned(_v: u32, _t: u32) -> Weight { + Default::default() + } +} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs new file mode 100644 index 0000000000000..8ac6d05250916 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs @@ -0,0 +1,315 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Benchmarking for the Elections Multiblock Verifier sub-pallet. + +use super::*; +use crate::{ + benchmarking::helpers, + signed::pallet::Submissions, + unsigned::miner::OffchainWorkerMiner, + verifier::{AsyncVerifier, Status, Verifier}, + BenchmarkingConfig, ConfigCore, ConfigSigned, ConfigUnsigned, ConfigVerifier, PalletCore, + PalletVerifier, +}; +use frame_support::assert_ok; +use frame_system::RawOrigin; + +use frame_benchmarking::v2::*; + +#[benchmarks( + where T: ConfigCore + ConfigSigned + ConfigUnsigned + ConfigVerifier, +)] +mod benchmarks { + use super::*; + use frame_support::traits::Hooks; + + #[benchmark] + fn on_initialize_ongoing( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + let valid_solution = true; + let submitter = helpers::mine_and_submit::(Some(PalletCore::::msp()), valid_solution) + .map_err(|err| { + log!(error, "error mining and storing paged solutions, {:?}", err); + BenchmarkError::Stop("mine and store error") + })?; + + // page is ready for async verification. + assert!(Submissions::::get_page( + &submitter, + PalletCore::::current_round(), + PalletCore::::msp() + ) + .is_some()); + + // no backings for pages yet in storage. + assert!(PalletVerifier::::pages_backed() == 0); + + // set verifier status to pick first submitted page to verify. + as AsyncVerifier>::set_status( + Status::Ongoing(crate::Pallet::::msp()), + ); + + #[block] + { + PalletVerifier::::on_initialize(0u32.into()); + } + + // backings from submitted and verified page is in storage now + assert!(PalletVerifier::::pages_backed() == 1); + + Ok(()) + } + + #[benchmark] + fn on_initialize_ongoing_failed( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + let valid_solution = false; + let submitter = helpers::mine_and_submit::(Some(PalletCore::::msp()), valid_solution) + .map_err(|err| { + log!(error, "error mining and storing paged solutions, {:?}", err); + BenchmarkError::Stop("mine and store error") + })?; + + // page is ready for async verification. + assert!(Submissions::::get_page( + &submitter, + PalletCore::::current_round(), + PalletCore::::msp() + ) + .is_some()); + + // no backings for pages in storage. + assert!(PalletVerifier::::pages_backed() == 0); + + // set verifier status to pick first submitted page to verify. + as AsyncVerifier>::set_status( + Status::Ongoing(crate::Pallet::::msp()), + ); + + #[block] + { + PalletVerifier::::on_initialize(0u32.into()); + } + + // no backings for pages in storage due to failure. + assert!(PalletVerifier::::pages_backed() == 0); + + Ok(()) + } + + #[benchmark] + fn on_initialize_ongoing_finalize( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + // submit all pages with a valid solution. + let valid_solution = true; + let submitter = helpers::mine_and_submit::(None, valid_solution).map_err(|err| { + log!(error, "error mining and storing paged solutions, {:?}", err); + BenchmarkError::Stop("mine and store error") + })?; + + // all pages are ready for async verification. + for page in 0..T::Pages::get() { + assert!(Submissions::::get_page(&submitter, PalletCore::::current_round(), page) + .is_some()); + } + + // no backings for pages in storage. + assert!(PalletVerifier::::pages_backed() == 0); + // no queued score yet. + assert!( as Verifier>::queued_score().is_none()); + + // process all paged solutions but lsp. + for page in (1..T::Pages::get()).rev() { + as AsyncVerifier>::set_status(Status::Ongoing(page)); + Pallet::::on_initialize(0u32.into()); + } + + assert!(PalletVerifier::::pages_backed() as u32 == T::Pages::get().saturating_sub(1)); + + // set verifier status to pick last submitted page to verify. + as AsyncVerifier>::set_status(Status::Ongoing(PalletCore::::lsp())); + + #[block] + { + PalletVerifier::::on_initialize(0u32.into()); + } + + // OK, so score is queued. + assert!( as Verifier>::queued_score().is_some()); + + Ok(()) + } + + #[benchmark] + fn on_initialize_ongoing_finalize_failed( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + #[block] + { + let _ = 1 + 2; + } + + Ok(()) + } + + #[benchmark] + fn finalize_async_verification( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + #[block] + { + let _ = 1 + 2; + } + + Ok(()) + } + + #[benchmark] + fn verify_sync_paged( + v: Linear< + { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, + { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, + >, + t: Linear< + { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, + { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, + >, + ) -> Result<(), BenchmarkError> { + helpers::setup_data_provider::( + ::BenchmarkingConfig::VOTERS.max(v), + ::BenchmarkingConfig::TARGETS.max(t), + ); + + if let Err(err) = helpers::setup_snapshot::(v, t) { + log!(error, "error setting up snapshot: {:?}.", err); + return Err(BenchmarkError::Stop("snapshot error")); + } + + let (_claimed_full_score, partial_score, paged_solution) = + OffchainWorkerMiner::::mine(PalletCore::::msp()).map_err(|err| { + log!(error, "mine error: {:?}", err); + BenchmarkError::Stop("miner error") + })?; + + #[block] + { + assert_ok!(PalletVerifier::::do_verify_sync( + paged_solution, + partial_score, + PalletCore::::msp() + )); + } + + Ok(()) + } + + impl_benchmark_test_suite!( + PalletVerifier, + crate::mock::ExtBuilder::default(), + crate::mock::Runtime, + exec_name = build_and_execute + ); +} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs new file mode 100644 index 0000000000000..dc108ec3cdc06 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -0,0 +1,764 @@ +// ohis file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO(gpestana): clean up imports. +use frame_election_provider_support::{NposSolution, PageIndex, TryIntoBoundedSupports}; +use frame_support::{ + ensure, + pallet_prelude::Weight, + traits::{Defensive, TryCollect}, + BoundedVec, +}; +use sp_runtime::{traits::Zero, Perbill}; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; + +use super::*; +use pallet::*; + +use crate::{helpers, unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; + +#[frame_support::pallet(dev_mode)] +pub(crate) mod pallet { + use super::*; + use frame_support::pallet_prelude::{ValueQuery, *}; + use frame_system::pallet_prelude::*; + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: crate::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Origin that can control this pallet. This must be a *trusted origin* since the + /// actions taken by this origin are not checked (e.g. `set_emergency_solution`). + type ForceOrigin: EnsureOrigin; + + /// Minimum improvement to a solution that defines a new solution as "better". + type SolutionImprovementThreshold: Get; + + /// Something that can provide the solution data to the verifier. + type SolutionDataProvider: crate::verifier::SolutionDataProvider< + Solution = SolutionOf, + >; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A verificaction failed at the given page. + VerificationFailed(PageIndex, FeasibilityError), + /// The final verifications of the `finalize_verification` failed. If this error happened, + /// all the single pages passed the feasibility checks. + FinalVerificationFailed(FeasibilityError), + /// The given page has been correctly verified, with the number of backers that are part of + /// the page. + Verified(PageIndex, u32), + /// A new solution with the given score has replaced the previous best solution, if any. + Queued(ElectionScore, Option), + /// The solution data was not available for a specific page. + SolutionDataUnavailable(PageIndex), + } + + /// A wrapper type of the storage items related to the queued solution. + /// + /// It manages the following storage types: + /// + /// - [`QueuedSolutionX`]: variant X of the queued solution. + /// - [`QueuedSolutionY`]: variant Y of the queued solution. + /// - [`QueuedValidVariant`]: pointer to which variant is the currently valid. + /// - [`QueuedSolutionScore`]: the soltution score of the current valid variant. + /// - [`QueuedSolutionBackings`]. + /// + /// Note that, as an async verification is progressing, the paged solution is kept in the + /// invalid variant storage. A solution is considered valid only when all the single page and + /// full solution checks have been perform based on the stored [`QueuedSolutionBackings`]. for + /// the corresponding in-verification solution. After the solution verification is successful, + /// the election score can be calculated and stored. + /// + /// ### Invariants + /// + /// - [`QueuedSolutionScore`] must be always the correct queued score of a variant corresponding + /// to the [`QueuedValidVariant`]. + /// - [`QueuedSolution`] must always be [`Config::SolutionImprovementThreshold`] better than + /// [`MininumScore`]. + /// - The [`QueuedSolutionBackings`] are always the backings corresponding to the *invalid* + /// variant. + pub struct QueuedSolution(sp_std::marker::PhantomData); + + impl QueuedSolution { + fn mutate_checked(mutate: impl FnOnce() -> R) -> R { + let r = mutate(); + #[cfg(debug_assertions)] + assert!(Self::sanity_check().is_ok()); + r + } + + /// Clear all relevant data of an invalid solution. + /// + /// This should be called when a solution being verified is deemed infeasible. + pub(crate) fn clear_invalid_and_backings() { + let _ = match Self::invalid() { + SolutionPointer::X => QueuedSolutionX::::clear(u32::MAX, None), + SolutionPointer::Y => QueuedSolutionY::::clear(u32::MAX, None), + }; + let _ = QueuedSolutionBackings::::clear(u32::MAX, None); + } + + /// Clear all relevant storage items. + pub(crate) fn kill() { + Self::mutate_checked(|| { + let _ = QueuedSolutionX::::clear(u32::MAX, None); + let _ = QueuedSolutionY::::clear(u32::MAX, None); + QueuedValidVariant::::kill(); + let _ = QueuedSolutionBackings::::clear(u32::MAX, None); + QueuedSolutionScore::::kill(); + }) + } + + /// Finalize a correct solution. + /// + /// It should be called at the end of the verification process of a valid solution to update + /// the queued solution score and flip the invalid variant. + pub(crate) fn finalize_solution(score: ElectionScore) { + sublog!( + info, + "verifier", + "finalizing verification of a correct solution, replacing old score {:?} with {:?}", + QueuedSolutionScore::::get(), + score + ); + + Self::mutate_checked(|| { + QueuedValidVariant::::mutate(|v| *v = v.other()); + QueuedSolutionScore::::put(score); + // TODO: should clear the invalid backings too? + }) + } + + /// Write a single page of a valid solution into the `invalid` variant of the storage. + /// + /// It should be called only once the page has been verified to be 100% correct. + pub(crate) fn set_page(page: PageIndex, supports: MinerSupportsOf) { + Self::mutate_checked(|| { + let backings: BoundedVec<_, _> = supports + .iter() + .map(|(x, s)| (x.clone(), PartialBackings {total: s.total, backers: s.voters.len() as u32})) + .try_collect() + .expect("`SupportsOf` is bounded by as Verifier>::MaxWinnersPerPage which is ensured by an integrity test; qed."); + + QueuedSolutionBackings::::insert(page, backings); + + // update the last stored page. + RemainingUnsignedPages::::mutate(|remaining| { + remaining.retain(|p| *p != page); + sublog!(debug, "verifier", "updated remaining pages, current: {:?}", remaining); + }); + + // store the new page into the invalid variant storage type. + match Self::invalid() { + SolutionPointer::X => QueuedSolutionX::::insert(page, supports), + SolutionPointer::Y => QueuedSolutionY::::insert(page, supports), + } + }) + } + + /// Computes the score and the winner count of a stored variant solution. + pub(crate) fn compute_current_score() -> Result<(ElectionScore, u32), FeasibilityError> { + // ensures that all the pages are complete; + if QueuedSolutionBackings::::iter_keys().count() != T::Pages::get() as usize { + return Err(FeasibilityError::Incomplete) + } + + let mut supports: BTreeMap = Default::default(); + for (who, PartialBackings { backers, total }) in + QueuedSolutionBackings::::iter().map(|(_, backings)| backings).flatten() + { + let entry = supports.entry(who).or_default(); + entry.total = entry.total.saturating_add(total); + entry.backers = entry.backers.saturating_add(backers); + + if entry.backers > T::MaxBackersPerWinner::get() { + return Err(FeasibilityError::TooManyBackings) + } + } + + let winners_count = supports.len() as u32; + let score = sp_npos_elections::evaluate_support( + supports.into_iter().map(|(_, backings)| backings), + ); + + Ok((score, winners_count)) + } + + /// Returns the current queued score, if any. + pub(crate) fn queued_score() -> Option { + QueuedSolutionScore::::get() + } + + /// Returns the current *valid* paged queued solution, if any. + pub(crate) fn get_queued_solution( + page: PageIndex, + ) -> Option> { + match Self::valid() { + SolutionPointer::X => QueuedSolutionX::::get(page), + SolutionPointer::Y => QueuedSolutionY::::get(page), + } + } + + /// Returns the pointer for the valid solution storage. + pub(crate) fn valid() -> SolutionPointer { + QueuedValidVariant::::get() + } + + /// Returns the pointer for the invalid solution storage. + pub(crate) fn invalid() -> SolutionPointer { + Self::valid().other() + } + + #[allow(dead_code)] + pub(crate) fn sanity_check() -> Result<(), &'static str> { + // TODO(gpestana) + Ok(()) + } + } + + /// Supports of the solution of the variant X. + /// + /// A potential valid or invalid solution may be stored in this variant during the round. + #[pallet::storage] + pub type QueuedSolutionX = + StorageMap<_, Twox64Concat, PageIndex, MinerSupportsOf>; + + /// Supports of the solution of the variant Y. + /// + /// A potential valid or invalid solution may be stored in this variant during the round. + #[pallet::storage] + pub type QueuedSolutionY = + StorageMap<_, Twox64Concat, PageIndex, MinerSupportsOf>; + + /// The `(amount, count)` of backings, keyed by page. + /// + /// This is stored to facilitate the `MaxBackersPerWinner` check at the end of an async + /// verification. Once the solution is valid (i.e. verified), the solution backings are not + /// useful anymore and can be cleared. + #[pallet::storage] + pub(crate) type QueuedSolutionBackings = StorageMap< + _, + Twox64Concat, + PageIndex, + BoundedVec<(T::AccountId, PartialBackings), T::MaxWinnersPerPage>, + >; + + /// The score of the current valid solution. + #[pallet::storage] + type QueuedSolutionScore = StorageValue<_, ElectionScore>; + + /// Pointer for the storage variant (X or Y) that stores the current valid variant. + #[pallet::storage] + type QueuedValidVariant = StorageValue<_, SolutionPointer, ValueQuery>; + + /// The minimum score that each solution must have to be considered feasible. + #[pallet::storage] + pub(crate) type MinimumScore = StorageValue<_, ElectionScore>; + + /// Current status of the verification process. + #[pallet::storage] + pub(crate) type VerificationStatus = StorageValue<_, Status, ValueQuery>; + + // For unsigned page solutions only. + #[pallet::storage] + pub(crate) type RemainingUnsignedPages = StorageValue<_, Vec, ValueQuery>; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(n: BlockNumberFor) -> Weight { + Self::do_on_initialize(n) + } + + fn integrity_test() { + // TODO(gpestana): add more integrity tests related to queued solution et al. + assert_eq!(T::MaxWinnersPerPage::get(), ::MaxWinnersPerPage::get()); + assert_eq!( + T::MaxBackersPerWinner::get(), + ::MaxBackersPerWinner::get() + ); + } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } +} + +impl Verifier for Pallet { + type AccountId = T::AccountId; + type Solution = SolutionOf; + type MaxWinnersPerPage = T::MaxWinnersPerPage; + type MaxBackersPerWinner = T::MaxBackersPerWinner; + + fn set_minimum_score(score: ElectionScore) { + MinimumScore::::put(score); + } + + fn queued_score() -> Option { + QueuedSolution::::queued_score() + } + + fn ensure_score_improves(claimed_score: ElectionScore) -> bool { + Self::ensure_score_quality(claimed_score).is_ok() + } + + fn get_queued_solution(page_index: PageIndex) -> Option> { + QueuedSolution::::get_queued_solution(page_index) + } + + fn next_missing_solution_page() -> Option { + let next_missing = RemainingUnsignedPages::::get().last().copied(); + sublog!(debug, "verifier", "next missing page: {:?}", next_missing); + + next_missing + } + + fn kill() { + QueuedSolution::::kill(); + >::put(Status::Nothing); + } + + fn verify_synchronous( + partial_solution: Self::Solution, + partial_score: ElectionScore, + page: PageIndex, + ) -> Result, FeasibilityError> { + let maybe_current_score = Self::queued_score(); + match Self::do_verify_sync(partial_solution, partial_score, page) { + Ok(supports) => { + sublog!( + info, + "verifier", + "queued sync solution with score {:?} (page {:?})", + partial_score, + page + ); + Self::deposit_event(Event::::Verified(page, supports.len() as u32)); + Self::deposit_event(Event::::Queued(partial_score, maybe_current_score)); + Ok(supports) + }, + Err(err) => { + sublog!( + info, + "verifier", + "sync verification failed with {:?} (page: {:?})", + err, + page + ); + Self::deposit_event(Event::::VerificationFailed(page, err.clone())); + Err(err) + }, + } + } + + fn feasibility_check( + solution: Self::Solution, + page: PageIndex, + ) -> Result, FeasibilityError> { + let targets = + crate::Snapshot::::targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + + // prepare range to fetch all pages of the target and voter snapshot. + let paged_range = 0..crate::Pallet::::msp() + 1; + + // fetch all pages of the voter snapshot and collect them in a bounded vec. + let all_voter_pages: BoundedVec<_, T::Pages> = paged_range + .map(|page| { + crate::Snapshot::::voters(page).ok_or(FeasibilityError::SnapshotUnavailable) + }) + .collect::, _>>()? + .try_into() + .expect("range was constructed from the bounded vec bounds; qed."); + + let desired_targets = + crate::Snapshot::::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + + miner::Miner::::feasibility_check_partial( + &all_voter_pages, + &targets, + solution, + desired_targets, + page, + ) + } +} + +impl AsyncVerifier for Pallet { + type SolutionDataProvider = T::SolutionDataProvider; + + fn force_finalize_verification(claimed_score: ElectionScore) -> Result<(), FeasibilityError> { + Self::finalize_async_verification(claimed_score) + } + + fn status() -> Status { + VerificationStatus::::get() + } + + fn start() -> Result<(), &'static str> { + if let Status::Nothing = Self::status() { + let claimed_score = Self::SolutionDataProvider::get_score().unwrap_or_default(); + + if Self::ensure_score_quality(claimed_score).is_err() { + Self::deposit_event(Event::::VerificationFailed( + crate::Pallet::::msp(), + FeasibilityError::ScoreTooLow, + )); + // report to the solution data provider that the page verification failed. + T::SolutionDataProvider::report_result(VerificationResult::Rejected); + // despite the verification failed, this was a successful `start` operation. + Ok(()) + } else { + VerificationStatus::::put(Status::Ongoing(crate::Pallet::::msp())); + Ok(()) + } + } else { + sublog!(warn, "verifier", "tries to start election while ongoing, ignored."); + Err("verification ongoing") + } + } + + fn stop() { + sublog!(warn, "verifier", "stop signal received. clearing everything."); + // TODO(gpestana): debug asserts + QueuedSolution::::clear_invalid_and_backings(); + + // if a verification is ongoing, signal the solution rejection to the solution data + // provider and reset the current status. + VerificationStatus::::mutate(|status| { + if matches!(status, Status::Ongoing(_)) { + T::SolutionDataProvider::report_result(VerificationResult::Rejected); + }; + *status = Status::Nothing; + }); + } + + // Sets current verifications status. + #[cfg(any(test, feature = "runtime-benchmarks"))] + fn set_status(status: Status) { + VerificationStatus::::put(status); + } +} + +impl Pallet { + fn do_on_initialize(_now: crate::BlockNumberFor) -> Weight { + let max_backers_winner = T::MaxBackersPerWinner::get(); + let max_winners_page = T::MaxWinnersPerPage::get(); + + match crate::Pallet::::current_phase() { + // reset remaining unsigned pages after snapshot is created. + crate::Phase::Snapshot(page) if page == crate::Pallet::::lsp() => { + RemainingUnsignedPages::::put( + (crate::Pallet::::lsp()..crate::Pallet::::msp() + 1).collect::>(), + ); + + sublog!( + debug, + "verifier", + "reset remaining unsgined pages to {:?}", + RemainingUnsignedPages::::get() + ); + }, + _ => (), + } + + if let Status::Ongoing(current_page) = >::get() { + let maybe_page_solution = + ::get_paged_solution(current_page); + + if maybe_page_solution.is_none() { + sublog!( + error, + "verifier", + "T::SolutionDataProvider failed to deliver page {} at {:?}.", + current_page, + crate::Pallet::::current_phase(), + ); + // reset election data and notify the `T::SolutionDataProvider`. + QueuedSolution::::clear_invalid_and_backings(); + VerificationStatus::::put(Status::Nothing); + T::SolutionDataProvider::report_result(VerificationResult::DataUnavailable); + + Self::deposit_event(Event::::SolutionDataUnavailable(current_page)); + + return ::WeightInfo::on_initialize_ongoing_failed( + max_backers_winner, + max_winners_page, + ); + } + + let page_solution = maybe_page_solution.expect("page solution checked to exist; qed."); + let maybe_supports = Self::feasibility_check(page_solution, current_page); + + // TODO: can refator out some of these code blocks to clean up the code. + let weight_consumed = match maybe_supports { + Ok(supports) => { + Self::deposit_event(Event::::Verified(current_page, supports.len() as u32)); + QueuedSolution::::set_page(current_page, supports); + + if current_page > crate::Pallet::::lsp() { + // election didn't finish, tick forward. + VerificationStatus::::put(Status::Ongoing( + current_page.saturating_sub(1), + )); + ::WeightInfo::on_initialize_ongoing( + max_backers_winner, + max_winners_page, + ) + } else { + // last page, finalize everything. At this point, the solution data + // provider should have a score ready for us. Otherwise, a default score + // will reset the whole election which is the desired behaviour. + let claimed_score = + T::SolutionDataProvider::get_score().defensive_unwrap_or_default(); + + // reset the election status. + VerificationStatus::::put(Status::Nothing); + + match Self::finalize_async_verification(claimed_score) { + Ok(_) => { + T::SolutionDataProvider::report_result(VerificationResult::Queued); + ::WeightInfo::on_initialize_ongoing_finalize( + max_backers_winner, + max_winners_page, + ) + }, + Err(_) => { + T::SolutionDataProvider::report_result( + VerificationResult::Rejected, + ); + // kill the solution in case of error. + QueuedSolution::::clear_invalid_and_backings(); + ::WeightInfo::on_initialize_ongoing_finalize_failed( + max_backers_winner, + max_winners_page, + ) + }, + } + } + }, + Err(err) => { + // the paged solution is invalid. + Self::deposit_event(Event::::VerificationFailed(current_page, err)); + VerificationStatus::::put(Status::Nothing); + QueuedSolution::::clear_invalid_and_backings(); + T::SolutionDataProvider::report_result(VerificationResult::Rejected); + + // TODO: may need to be a differnt another branch. + ::WeightInfo::on_initialize_ongoing_finalize_failed( + max_backers_winner, + max_winners_page, + ) + }, + }; + + weight_consumed + } else { + // nothing to do yet. + // TOOD(return weight reads=1) + Default::default() + } + } + + pub(crate) fn do_verify_sync( + partial_solution: SolutionOf, + partial_score: ElectionScore, + page: PageIndex, + ) -> Result, FeasibilityError> { + let _ = Self::ensure_score_quality(partial_score)?; + let supports = Self::feasibility_check(partial_solution.clone(), page)?; + + // TODO: implement fn evaluate on `BondedSupports`; remove extra clone. + let real_score = sp_npos_elections::evaluate_support( + supports.clone().into_iter().map(|(_, backings)| backings), + ); + ensure!(real_score == partial_score, FeasibilityError::InvalidScore); + + // queue valid solution of single page. + QueuedSolution::::set_page(page, supports.clone()); + + Ok(supports) + } + + pub(crate) fn finalize_async_verification( + claimed_score: ElectionScore, + ) -> Result<(), FeasibilityError> { + let outcome = QueuedSolution::::compute_current_score() + .and_then(|(final_score, winner_count)| { + let desired_targets = crate::Snapshot::::desired_targets().unwrap_or_default(); + + match (final_score == claimed_score, winner_count <= desired_targets) { + (true, true) => { + QueuedSolution::::finalize_solution(final_score); + Self::deposit_event(Event::::Queued( + final_score, + QueuedSolution::::queued_score(), + )); + + Ok(()) + }, + (false, true) => Err(FeasibilityError::InvalidScore), + (true, false) => Err(FeasibilityError::WrongWinnerCount), + (false, false) => Err(FeasibilityError::InvalidScore), + } + }) + .map_err(|err| { + sublog!(warn, "verifier", "finalizing the solution was invalid due to {:?}", err); + Self::deposit_event(Event::::VerificationFailed(Zero::zero(), err.clone())); + err + }); + + sublog!(debug, "verifier", "finalize verification outcome: {:?}", outcome); + outcome + } + + pub fn ensure_score_quality(score: ElectionScore) -> Result<(), FeasibilityError> { + let is_improvement = ::queued_score().map_or(true, |best_score| { + score.strict_threshold_better(best_score, T::SolutionImprovementThreshold::get()) + }); + ensure!(is_improvement, FeasibilityError::ScoreTooLow); + + let is_greater_than_min_trusted = MinimumScore::::get() + .map_or(true, |min_score| score.strict_threshold_better(min_score, Perbill::zero())); + ensure!(is_greater_than_min_trusted, FeasibilityError::ScoreTooLow); + + Ok(()) + } + + pub(crate) fn feasibility_check_old( + partial_solution: SolutionOf, + page: PageIndex, + ) -> Result, FeasibilityError> { + // Read the corresponding snapshots. + let snapshot_targets = + crate::Snapshot::::targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + let snapshot_voters = + crate::Snapshot::::voters(page).ok_or(FeasibilityError::SnapshotUnavailable)?; + + let voter_cache = helpers::generate_voter_cache::(&snapshot_voters); + let voter_at = helpers::voter_at_fn::(&snapshot_voters); + let target_at = helpers::target_at_fn::(&snapshot_targets); + let voter_index = helpers::voter_index_fn_usize::(&voter_cache); + + // Then convert solution -> assignment. This will fail if any of the indices are + // gibberish. + let assignments = partial_solution + .into_assignment(voter_at, target_at) + .map_err::(Into::into)?; + + // Ensure that assignments are all correct. + let _ = assignments + .iter() + .map(|ref assignment| { + // Check that assignment.who is actually a voter (defensive-only). NOTE: while + // using the index map from `voter_index` is better than a blind linear search, + // this *still* has room for optimization. Note that we had the index when we + // did `solution -> assignment` and we lost it. Ideal is to keep the index + // around. + + // Defensive-only: must exist in the snapshot. + let snapshot_index = + voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; + // Defensive-only: index comes from the snapshot, must exist. + let (_voter, _stake, targets) = + snapshot_voters.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; + debug_assert!(*_voter == assignment.who); + + // Check that all of the targets are valid based on the snapshot. + if assignment.distribution.iter().any(|(t, _)| !targets.contains(t)) { + return Err(FeasibilityError::InvalidVote) + } + Ok(()) + }) + .collect::>()?; + + // ----- Start building support. First, we need one more closure. + let stake_of = helpers::stake_of_fn::(&snapshot_voters, &voter_cache); + + // This might fail if the normalization fails. Very unlikely. See `integrity_test`. + let staked_assignments = + sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, stake_of) + .map_err::(Into::into)?; + + let supports = sp_npos_elections::to_supports(&staked_assignments); + + // Check the maximum number of backers per winner. If this is a single-page solution, this + // is enough to check `MaxBackersPerWinner`. Else, this is just a heuristic, and needs to be + // checked again at the end (via `QueuedSolutionBackings`). + ensure!( + supports + .iter() + .all(|(_, s)| (s.voters.len() as u32) <= T::MaxBackersPerWinner::get()), + FeasibilityError::TooManyBackings + ); + + // Ensure some heuristics. These conditions must hold in the **entire** support, this is + // just a single page. But, they must hold in a single page as well. + let desired_targets = + crate::Snapshot::::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; + + // supports per page must not be higher than the desired targets, otherwise final solution + // will also be higher than desired_targets. + ensure!((supports.len() as u32) <= desired_targets, FeasibilityError::WrongWinnerCount); + + // almost-defensive-only: `MaxBackersPerWinner` is already checked. A sane value of + // `MaxWinnersPerPage` should be more than any possible value of `desired_targets()`, which + // is ALSO checked, so this conversion can almost never fail. + let bounded_supports = supports.try_into_bounded_supports().map_err(|e| { + log!(info, "ERR: {:?}", e); + FeasibilityError::WrongWinnerCount + })?; + + Ok(bounded_supports) + } + + /// Returns the number backings/pages verified and stored. + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub(crate) fn pages_backed() -> usize { + QueuedSolutionBackings::::iter_keys().count() + } +} + +#[cfg(feature = "try-runtime")] +impl Pallet { + pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::check_variants() + } + + /// Invariants: + /// + /// 1. The valid and invalid solution pointers are always different. + fn check_variants() -> Result<(), sp_runtime::TryRuntimeError> { + ensure!( + QueuedSolution::::valid() != QueuedSolution::::invalid(), + "valid and invalid solution pointers are the same" + ); + Ok(()) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs new file mode 100644 index 0000000000000..8b7e095ac6371 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs @@ -0,0 +1,287 @@ +// This file is part of Substrate. + +// Copyright (C) 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. + +//! # Verifier sub-pallet +//! +//! This pallet implements the NPoS solution verification logic. It supports both synchronous and +//! asynchronous verification of paged solutions. Moreover, it manages and ultimately stores +//! the best correct solution in a round, which can be requested by the election provider at the +//! time of the election. +//! +//! The paged solution data to be verified async is retrieved through the +//! [`Config::SolutionDataProvider`] implementor which most likely is the signed pallet. +//! +//! ## Feasibility check +//! +//! The goal of the feasibility of a solution is to ensure that a provided +//! [`crate::Config::Solution`] is correct based on the voter and target snapshots of a given round +//! kept by the parent pallet. The correctness of a solution is defined as: +//! +//! - The edges of a solution (voter -> targets) match the expected by the current snapshot. This +//! check can be performed at the page level. +//! - The total number of winners in the solution is sufficient. This check can only be performed +//! when the full paged solution is available;; +//! - The election score is higher than the expected minimum score. This check can only be performed +//! when the full paged solution is available;; +//! - All of the bounds of the election are respected, namely: +//! * [`Verifier::MaxBackersPerWinner`] - which set the total max of voters are backing a target, +//! per election. This check can only be performed when the full paged solution is available; +//! * [`Verifier::MaxWinnersPerPage`] - which ensure that a paged solution has a bound on the +//! number of targets. This check can be performed at the page level. +//! +//! Some checks can be performed at the page level (e.g. correct edges check) while others can only +//! be performed when the full solution is available. +//! +//! ## Sync and Async verification modes +//! +//! 1. Single-page, synchronous verification. This mode is used when a single page needs to be +//! verified on the fly, e.g. unsigned submission. +//! 2. Multi-page, asynchronous verification. This mode is used in the context of the multi-paged +//! signed solutions. +//! +//! The [`crate::verifier::Verifier`] and [`crate::verifier::AsyncVerifier`] traits define the +//! interface of each of the verification modes and this pallet implements both traits. +//! +//! ## Queued solution +//! +//! Once a solution has been succefully verified, it is stored in a queue. This pallet implements +//! the [`SolutionDataProvider`] trait which allows the parent pallet to request a correct +//! solution for the current round. + +mod impls; +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +mod tests; + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::traits::Get; +use sp_npos_elections::{ElectionScore, ExtendedBalance}; +use sp_runtime::RuntimeDebug; + +// public re-exports. +pub use impls::pallet::{ + Call, Config, Event, Pallet, __substrate_call_check, __substrate_event_check, tt_default_parts, + tt_default_parts_v2, tt_error_token, +}; + +use crate::{PageIndex, SupportsOf}; + +/// Errors related to the solution feasibility checks. +#[derive(Debug, Eq, PartialEq, codec::Encode, codec::Decode, scale_info::TypeInfo, Clone)] +pub enum FeasibilityError { + /// Election score is too low to be accepted. + ScoreTooLow, + /// Ongoing verification was not completed. + Incomplete, + /// Solution exceeds the number of backers per winner for at least one winner. + TooManyBackings, + /// Solution exceeds the number of winners. + WrongWinnerCount, + /// Snapshot is not available. + SnapshotUnavailable, + /// A voter is invalid. + InvalidVoter, + /// A vote is invalid. + InvalidVote, + /// Solution with an invalid score. + InvalidScore, + /// Internal election error. + #[codec(skip)] + NposElection(sp_npos_elections::Error), +} + +impl From for FeasibilityError { + fn from(err: sp_npos_elections::Error) -> Self { + FeasibilityError::NposElection(err) + } +} + +/// The status of this pallet. +/// +/// This pallet is either processing an async verification or doing nothing. A single page +/// verification can only be done while the pallet has status [`Status::Nothing`]. +#[derive(Encode, Decode, scale_info::TypeInfo, Clone, Copy, MaxEncodedLen, RuntimeDebug)] +pub enum Status { + /// A paged solution is ongoing and the next page to be verified is indicated in the inner + /// value. + Ongoing(PageIndex), + /// Nothing is happening. + Nothing, +} + +impl Default for Status { + fn default() -> Self { + Status::Nothing + } +} + +/// Pointer to the current valid solution of `QueuedSolution`. +#[derive(Encode, Decode, scale_info::TypeInfo, Clone, Copy, MaxEncodedLen, Debug, PartialEq)] +pub enum SolutionPointer { + X, + Y, +} + +impl Default for SolutionPointer { + fn default() -> Self { + SolutionPointer::X + } +} + +impl SolutionPointer { + pub fn other(&self) -> SolutionPointer { + match *self { + SolutionPointer::X => SolutionPointer::Y, + SolutionPointer::Y => SolutionPointer::X, + } + } +} + +/// A type that represents a *partial* backing of a winner. It does not contain the +/// supports normally associated with a list of backings. +#[derive(Debug, Default, Encode, Decode, MaxEncodedLen, scale_info::TypeInfo)] +pub struct PartialBackings { + /// Total backing of a particular winner. + total: ExtendedBalance, + /// Number of backers. + backers: u32, +} + +impl sp_npos_elections::Backings for PartialBackings { + fn total(&self) -> ExtendedBalance { + self.total + } +} + +/// The interface of something that can verify solutions for election in a multi-block context. +pub trait Verifier { + /// The account ID type. + type AccountId; + + /// The solution type; + type Solution; + + /// Maximum number of winners that a page supports. + /// + /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. + type MaxWinnersPerPage: Get; + + /// Maximum number of backers that each winner can have. + type MaxBackersPerWinner: Get; + + /// Sets the minimum score that an election must have from now on. + fn set_minimum_score(score: ElectionScore); + + /// Fetches the current queued election score, if any. + /// + /// Returns `None` if not score is queued. + fn queued_score() -> Option; + + /// Check if a claimed score improves the current queued score. + fn ensure_score_improves(claimed_score: ElectionScore) -> bool; + + /// Returns the next missing solution page. + fn next_missing_solution_page() -> Option; + + /// Clears all the storage items related to the verifier pallet. + fn kill(); + + /// Get a single page of the best verified solutions, if any. + fn get_queued_solution(page_index: PageIndex) -> Option>; + + /// Perform the feasibility check on a given single-page solution. + /// + /// This will perform: + /// 1. feasibility-check + /// 2. claimed score is correct and it is an improvements + /// 3. check if bounds are correct + /// 4. store the solution if all checks pass + fn verify_synchronous( + partial_solution: Self::Solution, + claimed_score: ElectionScore, + page: PageIndex, + ) -> Result, FeasibilityError>; + + /// Just perform a single-page feasibility-check, based on the standards of this pallet. + /// + /// No score check is part of this. + fn feasibility_check( + partial_solution: Self::Solution, + page: PageIndex, + ) -> Result, FeasibilityError>; +} + +/// Something that can verify a solution asynchronously. +pub trait AsyncVerifier: Verifier { + /// The data provider that can provide the candidate solution to verify. The result of the + /// verification is returned back to this entity. + type SolutionDataProvider: SolutionDataProvider; + + /// Forces finalizing the async verification. + fn force_finalize_verification(claimed_score: ElectionScore) -> Result<(), FeasibilityError>; + + /// Returns the status of the current verification. + fn status() -> Status; + + /// Start a verification process. + fn start() -> Result<(), &'static str>; // new error type? + + /// Stop the verification. + /// + /// An implementation must ensure that all related state and storage items are cleaned. + fn stop(); + + /// Sets current status. Only used for benchmarks and tests. + #[cfg(any(test, feature = "runtime-benchmarks"))] + fn set_status(status: Status); +} + +/// Encapsulates the result of the verification of a candidate solution. +#[derive(Clone, Copy, RuntimeDebug)] +#[cfg_attr(test, derive(PartialEq, Eq))] +pub enum VerificationResult { + /// Solution is valid and is queued. + Queued, + /// Solution is rejected, for whichever of the multiple reasons that it could be. + Rejected, + /// The data needed (solution pages or the score) was unavailable. This should rarely happen. + DataUnavailable, +} + +/// Something that provides paged solution data for the verifier. +/// +/// This can be implemented by [`crate::signed::Pallet`] where signed solutions are queued and +/// sorted based on the solution's score. +pub trait SolutionDataProvider { + // The solution type. + type Solution; + + /// Returns the `page`th page of the current best solution that the data provider has in store, + /// if it exists. Otherwise it returns `None`. + fn get_paged_solution(page: PageIndex) -> Option; + + /// Get the claimed score of the current best solution. + fn get_score() -> Option; + + /// Hook to report back the results of the verification of the current candidate solution that + /// is being exposed via [`Self::get_paged_solution`] and [`Self::get_score`]. + fn report_result(result: VerificationResult); +} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/tests.rs b/substrate/frame/election-provider-multi-block/src/verifier/tests.rs new file mode 100644 index 0000000000000..66b4696edf4a7 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/verifier/tests.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{ + mock::*, + verifier::{impls::pallet::*, *}, + Phase, +}; +use frame_support::assert_noop; +use sp_npos_elections::ElectionScore; + +mod solution { + use super::*; + + #[test] + fn variant_flipping_works() { + ExtBuilder::default().build_and_execute(|| { + assert!(QueuedSolution::::valid() != QueuedSolution::::invalid()); + + let valid_before = QueuedSolution::::valid(); + let invalid_before = valid_before.other(); + + let mock_score = ElectionScore { minimal_stake: 10, ..Default::default() }; + + // queue solution and flip variant. + QueuedSolution::::finalize_solution(mock_score); + + // solution has been queued + assert_eq!(QueuedSolution::::queued_score().unwrap(), mock_score); + // variant has flipped. + assert_eq!(QueuedSolution::::valid(), invalid_before); + assert_eq!(QueuedSolution::::invalid(), valid_before); + }) + } +} + +mod feasibility_check { + use super::*; + + #[test] + fn winner_indices_page_in_bounds() { + ExtBuilder::default().pages(1).desired_targets(2).build_and_execute(|| { + roll_to_phase(Phase::Signed); + let mut solution = mine_full(1).unwrap(); + assert_eq!(crate::Snapshot::::targets().unwrap().len(), 8); + + // swap all votes from 3 to 4 to invalidate index 4. + solution.solution_pages[0] + .votes1 + .iter_mut() + .filter(|(_, t)| *t == TargetIndex::from(3u16)) + .for_each(|(_, t)| *t += 1); + + assert_noop!( + VerifierPallet::feasibility_check(solution.solution_pages[0].clone(), 0), + FeasibilityError::InvalidVote, + ); + }) + } +} + +mod sync_verifier { + use super::*; + + #[test] + fn sync_verifier_simple_works() { + ExtBuilder::default().build_and_execute(|| {}) + } + + #[test] + fn next_missing_solution_works() { + ExtBuilder::default().build_and_execute(|| { + let supports: SupportsOf> = Default::default(); + let msp = crate::Pallet::::msp(); + assert!(msp == ::Pages::get() - 1 && msp == 2); + + // run to snapshot phase to reset `RemainingUnsignedPages`. + roll_to_phase(Phase::Snapshot(crate::Pallet::::lsp())); + + // msp page is the next missing. + assert_eq!(::next_missing_solution_page(), Some(msp)); + + // X is the current valid solution, let's work with it. + assert_eq!(QueuedSolution::::valid(), SolutionPointer::X); + + // set msp and check the next missing page again. + QueuedSolution::::set_page(msp, supports.clone()); + assert_eq!(::next_missing_solution_page(), Some(msp - 1)); + + QueuedSolution::::set_page(msp - 1, supports.clone()); + assert_eq!(::next_missing_solution_page(), Some(0)); + + // set last page, missing page after is None as solution is complete. + QueuedSolution::::set_page(0, supports.clone()); + assert_eq!(::next_missing_solution_page(), None); + }) + } +} + +mod async_verifier { + use super::*; + + #[test] + fn async_verifier_simple_works() { + ExtBuilder::default().build_and_execute(|| {}) + } +} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/weights.rs b/substrate/frame/election-provider-multi-block/src/verifier/weights.rs new file mode 100644 index 0000000000000..1fd78c0df43c4 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/verifier/weights.rs @@ -0,0 +1,249 @@ + +//! Autogenerated weights for `pallet_epm_verifier` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-06, STEPS: `3`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gpestanas-MBP.Home`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 + +// Executed Command: +// /Users/gpestana/cargo_target/debug/staking-node +// benchmark +// pallet +// --wasm-execution +// compiled +// --pallet +// pallet-epm-verifier +// --extrinsic +// * +// --steps +// 3 +// --repeat +// 1 +// --output +// epm_verifier_weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +pub trait WeightInfo { + fn on_initialize_ongoing(v: u32, t: u32) -> Weight; + fn on_initialize_ongoing_failed(v: u32, t: u32) -> Weight; + fn on_initialize_ongoing_finalize(v: u32, t: u32) -> Weight; + fn on_initialize_ongoing_finalize_failed(v: u32, t: u32) -> Weight; + fn finalize_async_verification(v: u32, t: u32, ) -> Weight; + fn verify_sync_paged(v: u32, t: u32, ) -> Weight; +} + +/// Weight functions for `pallet_epm_verifier`. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) + /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:0) + /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:0) + /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn on_initialize_ongoing(v: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `12992 + t * (26 ±0) + v * (80 ±0)` + // Estimated: `15414 + t * (27 ±1) + v * (80 ±2)` + // Minimum execution time: 2_036_000_000 picoseconds. + Weight::from_parts(2_036_000_000, 0) + .saturating_add(Weight::from_parts(0, 15414)) + // Standard Error: 3_307_370 + .saturating_add(Weight::from_parts(20_614_626, 0).saturating_mul(v.into())) + // Standard Error: 1_618_727 + .saturating_add(Weight::from_parts(1_324_037, 0).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 27).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) + } + /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) + /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:1) + /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:1) + /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SubmissionMetadataStorage` (r:1 w:1) + /// Proof: `ElectionSignedPallet::SubmissionMetadataStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn on_initialize_ongoing_failed(v: u32, _t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + t * (4 ±0) + v * (112 ±0)` + // Estimated: `7604 + v * (108 ±2)` + // Minimum execution time: 1_034_000_000 picoseconds. + Weight::from_parts(1_576_541_397, 0) + .saturating_add(Weight::from_parts(0, 7604)) + // Standard Error: 296_982 + .saturating_add(Weight::from_parts(3_076_310, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 108).saturating_mul(v.into())) + } + /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) + /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:0) + /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:0) + /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:1) + /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:3 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn on_initialize_ongoing_finalize(v: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + t * (41 ±0) + v * (125 ±0)` + // Estimated: `79043 + t * (10 ±8) + v * (85 ±17)` + // Minimum execution time: 1_724_000_000 picoseconds. + Weight::from_parts(1_466_010_752, 0) + .saturating_add(Weight::from_parts(0, 79043)) + // Standard Error: 199_409 + .saturating_add(Weight::from_parts(3_322_580, 0).saturating_mul(v.into())) + // Standard Error: 128_785 + .saturating_add(Weight::from_parts(128_906, 0).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(12)) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(Weight::from_parts(0, 10).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 85).saturating_mul(v.into())) + } + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn on_initialize_ongoing_finalize_failed(_v: u32, _t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_659_677, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn finalize_async_verification(v: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_354_301, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 2_197 + .saturating_add(Weight::from_parts(907, 0).saturating_mul(v.into())) + // Standard Error: 1_419 + .saturating_add(Weight::from_parts(65, 0).saturating_mul(t.into())) + } + /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::MinimumScore` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::MinimumScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ValidatorCount` (r:1 w:0) + /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) + /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) + /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + /// The range of component `t` is `[512, 2048]`. + fn verify_sync_paged(v: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `15968 + t * (24 ±0) + v * (73 ±0)` + // Estimated: `18127 + t * (25 ±2) + v * (72 ±3)` + // Minimum execution time: 1_403_000_000 picoseconds. + Weight::from_parts(1_403_000_000, 0) + .saturating_add(Weight::from_parts(0, 18127)) + // Standard Error: 3_979_877 + .saturating_add(Weight::from_parts(24_084_766, 0).saturating_mul(v.into())) + // Standard Error: 1_947_873 + .saturating_add(Weight::from_parts(1_727_080, 0).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 25).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 72).saturating_mul(v.into())) + } +} + +impl WeightInfo for () { + fn on_initialize_ongoing(_v: u32, _t: u32) -> Weight { + Default::default() + } + + fn on_initialize_ongoing_failed(_v: u32, _t: u32) -> Weight { + Default::default() + } + + fn on_initialize_ongoing_finalize(_v: u32, _t: u32) -> Weight { + Default::default() + } + + fn on_initialize_ongoing_finalize_failed(_v: u32, _t: u32) -> Weight { + Default::default() + } + + fn finalize_async_verification(_v: u32, _t: u32, ) -> Weight { + Default::default() + } + + fn verify_sync_paged(_v: u32, _t: u32, ) -> Weight { + Default::default() + } +} + diff --git a/substrate/frame/election-provider-multi-block/src/weights.rs b/substrate/frame/election-provider-multi-block/src/weights.rs new file mode 100644 index 0000000000000..ce764ca6f80b8 --- /dev/null +++ b/substrate/frame/election-provider-multi-block/src/weights.rs @@ -0,0 +1,188 @@ + +//! Autogenerated weights for `pallet_epm_core` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-02, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gpestanas-MBP.lan`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 + +// Executed Command: +// /Users/gpestana/cargo_target/debug/staking-node +// benchmark +// pallet +// --chain +// dev +// --pallet +// pallet-epm-core +// --extrinsic +// * +// --steps +// 2 +// --repeat +// 1 +// --output +// core_weights.rs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +pub trait WeightInfo { + fn create_voters_snapshot_paged(t: u32) -> Weight; + fn create_targets_snapshot_paged(v: u32) -> Weight; + fn on_initialize_start_signed() -> Weight; + fn on_initialize_do_nothing() -> Weight; + fn on_phase_transition() -> Weight; + fn on_initialize_start_export() -> Weight; +} + +/// Weight functions for `pallet_epm_core`. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Staking::CounterForValidators` (r:1 w:0) + /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::TargetSnapshotStatus` (r:1 w:1) + /// Proof: `Staking::TargetSnapshotStatus` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:2049 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `t` is `[512, 2048]`. + fn create_targets_snapshot_paged(t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1041 + t * (46 ±0)` + // Estimated: `3510 + t * (2520 ±0)` + // Minimum execution time: 47_198_000_000 picoseconds. + Weight::from_parts(3_209_333_333, 0) + .saturating_add(Weight::from_parts(0, 3510)) + // Standard Error: 1_207_323 + .saturating_add(Weight::from_parts(86_960_937, 0).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(t.into())) + } + /// Storage: `VoterList::CounterForListNodes` (r:1 w:0) + /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::VoterSnapshotStatus` (r:1 w:1) + /// Proof: `Staking::VoterSnapshotStatus` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListBags` (r:200 w:0) + /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `VoterList::ListNodes` (r:1025 w:0) + /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1024 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Ledger` (r:1024 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1024 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `Staking::Validators` (r:1000 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::MinimumActiveStake` (r:0 w:1) + /// Proof: `Staking::MinimumActiveStake` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:0 w:1) + /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `v` is `[32, 1024]`. + fn create_voters_snapshot_paged(v: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73175 + v * (946 ±0)` + // Estimated: `512390 + v * (3566 ±0)` + // Minimum execution time: 13_398_000_000 picoseconds. + Weight::from_parts(4_906_354_838, 0) + .saturating_add(Weight::from_parts(0, 512390)) + // Standard Error: 534_281 + .saturating_add(Weight::from_parts(260_582_661, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(208)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) + } + /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ElectionDataLock` (r:0 w:1) + /// Proof: `Staking::ElectionDataLock` (`max_values`: Some(1), `max_size`: Some(0), added: 495, mode: `MaxEncodedLen`) + fn on_initialize_start_signed() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 66_000_000 picoseconds. + Weight::from_parts(66_000_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:1) + /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_phase_transition() -> Weight { + // Proof Size summary in bytes: + // Measured: `76` + // Estimated: `1561` + // Minimum execution time: 62_000_000 picoseconds. + Weight::from_parts(62_000_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn on_initialize_start_export() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(3_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) + /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) + /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `Staking::ForceEra` (r:1 w:0) + /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) + /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) + /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn on_initialize_do_nothing() -> Weight { + // Proof Size summary in bytes: + // Measured: `502` + // Estimated: `3481` + // Minimum execution time: 111_000_000 picoseconds. + Weight::from_parts(111_000_000, 0) + .saturating_add(Weight::from_parts(0, 3481)) + .saturating_add(T::DbWeight::get().reads(5)) + } +} + +impl WeightInfo for () { + fn create_voters_snapshot_paged(_v: u32) -> Weight { + Default::default() + } + + fn create_targets_snapshot_paged(_t: u32) -> Weight { + Default::default() + } + + fn on_initialize_start_signed() -> Weight { + Default::default() + } + + fn on_initialize_do_nothing() -> Weight { + Default::default() + } + + fn on_phase_transition() -> Weight { + Default::default() + } + + fn on_initialize_start_export() -> Weight { + Default::default() + } +} diff --git a/substrate/frame/election-provider-support/Cargo.toml b/substrate/frame/election-provider-support/Cargo.toml index cae20d1b46a48..da50d73328aac 100644 --- a/substrate/frame/election-provider-support/Cargo.toml +++ b/substrate/frame/election-provider-support/Cargo.toml @@ -24,6 +24,7 @@ sp-arithmetic = { workspace = true } sp-npos-elections = { workspace = true } sp-runtime = { workspace = true } sp-core = { workspace = true } +sp-std = { workspace = true } [dev-dependencies] rand = { features = ["small_rng"], workspace = true, default-features = true } @@ -43,6 +44,7 @@ std = [ "sp-io/std", "sp-npos-elections/std", "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", diff --git a/substrate/frame/election-provider-support/solution-type/src/codec.rs b/substrate/frame/election-provider-support/solution-type/src/codec.rs index 16d5f17469b7e..c1dd62fe55506 100644 --- a/substrate/frame/election-provider-support/solution-type/src/codec.rs +++ b/substrate/frame/election-provider-support/solution-type/src/codec.rs @@ -33,6 +33,7 @@ pub(crate) fn codec_and_info_impl( let scale_info = scale_info_impl(&ident, &voter_type, &target_type, &weight_type, count); quote! { + impl _fepsp::codec::EncodeLike for #ident {} #encode #decode #scale_info diff --git a/substrate/frame/election-provider-support/solution-type/src/single_page.rs b/substrate/frame/election-provider-support/solution-type/src/single_page.rs index de59df162c8ad..35ac5a7394f3f 100644 --- a/substrate/frame/election-provider-support/solution-type/src/single_page.rs +++ b/substrate/frame/election-provider-support/solution-type/src/single_page.rs @@ -189,7 +189,7 @@ pub(crate) fn generate(def: crate::SolutionDef) -> Result { fn max_encoded_len() -> usize { use frame_support::traits::Get; use _fepsp::codec::Encode; - let s: u32 = #max_voters::get(); + let s: u32 = <#max_voters as _feps::Get>::get(); let max_element_size = // the first voter.. #voter_type::max_encoded_len() diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index cb3249e388a31..09b0d65b3e6fb 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -21,10 +21,9 @@ //! within FRAME pallets. //! //! Something that will provide the functionality of election will implement -//! [`ElectionProvider`] and its parent-trait [`ElectionProviderBase`], whilst needing an -//! associated [`ElectionProviderBase::DataProvider`], which needs to be -//! fulfilled by an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* -//! the receiver of the election, resulting in a diagram as below: +//! [`ElectionProvider`], whilst needing an associated [`ElectionProvider::DataProvider`], which +//! needs to be fulfilled by an entity implementing [`ElectionDataProvider`]. Most often, *the data +//! provider is* the receiver of the election, resulting in a diagram as below: //! //! ```ignore //! ElectionDataProvider @@ -109,12 +108,12 @@ //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } -//! fn electing_voters(bounds: DataProviderBounds) +//! fn electing_voters(bounds: DataProviderBounds, _remaining_pages: PageIndex) //! -> data_provider::Result>> //! { //! Ok(Default::default()) //! } -//! fn electable_targets(bounds: DataProviderBounds) -> data_provider::Result> { +//! fn electable_targets(bounds: DataProviderBounds, _remaining_pages: PageIndex) -> data_provider::Result> { //! Ok(vec![10, 20, 30]) //! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { @@ -126,40 +125,50 @@ //! //! mod generic_election_provider { //! use super::*; +//! use sp_runtime::traits::Zero; //! //! pub struct GenericElectionProvider(std::marker::PhantomData); //! //! pub trait Config { //! type DataProvider: ElectionDataProvider; +//! type MaxWinnersPerPage: Get; +//! type MaxBackersPerWinner: Get; +//! type Pages: Get; //! } //! -//! impl ElectionProviderBase for GenericElectionProvider { +//! impl ElectionProvider for GenericElectionProvider { //! type AccountId = AccountId; //! type BlockNumber = BlockNumber; //! type Error = &'static str; +//! type MaxBackersPerWinner = T::MaxBackersPerWinner; +//! type MaxWinnersPerPage = T::MaxWinnersPerPage; +//! type Pages = T::Pages; //! type DataProvider = T::DataProvider; -//! type MaxWinners = ConstU32<{ u32::MAX }>; -//! -//! } //! -//! impl ElectionProvider for GenericElectionProvider { -//! fn ongoing() -> bool { false } -//! fn elect() -> Result, Self::Error> { -//! Self::DataProvider::electable_targets(DataProviderBounds::default()) -//! .map_err(|_| "failed to elect") -//! .map(|t| bounded_vec![(t[0], Support::default())]) +//! fn elect(remaining_pages: PageIndex) -> Result, Self::Error> { +//! unimplemented!() //! } //! } //! } //! //! mod runtime { +//! use frame_support::parameter_types; //! use super::generic_election_provider; //! use super::data_provider_mod; //! use super::AccountId; //! +//! parameter_types! { +//! pub static MaxWinnersPerPage: u32 = 10; +//! pub static MaxBackersPerWinner: u32 = 20; +//! pub static Pages: u32 = 2; +//! } +//! //! struct Runtime; //! impl generic_election_provider::Config for Runtime { //! type DataProvider = data_provider_mod::Pallet; +//! type MaxWinnersPerPage = MaxWinnersPerPage; +//! type MaxBackersPerWinner = MaxBackersPerWinner; +//! type Pages = Pages; //! } //! //! impl data_provider_mod::Config for Runtime { @@ -181,21 +190,23 @@ extern crate alloc; use alloc::{boxed::Box, vec::Vec}; use core::fmt::Debug; +use sp_core::ConstU32; use sp_runtime::{ traits::{Bounded, Saturating, Zero}, RuntimeDebug, }; pub use bounds::DataProviderBounds; -pub use codec::{Decode, Encode}; +pub use codec::{Decode, Encode, MaxEncodedLen}; /// Re-export the solution generation macro. pub use frame_election_provider_solution_type::generate_solution_type; -pub use frame_support::{traits::Get, weights::Weight, BoundedVec}; +pub use frame_support::{traits::Get, weights::Weight, BoundedVec, DefaultNoBound}; +use scale_info::TypeInfo; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, BalancingConfig, BoundedSupports, ElectionResult, Error, ExtendedBalance, - IdentifierT, PerThing128, Support, Supports, VoteWeight, + Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, + Support, Supports, VoteWeight, }; pub use traits::NposSolution; @@ -251,7 +262,9 @@ pub struct IndexAssignment { pub distribution: Vec<(TargetIndex, P)>, } -impl IndexAssignment { +impl + IndexAssignment +{ pub fn new( assignment: &Assignment, voter_index: impl Fn(&AccountId) -> Option, @@ -298,8 +311,10 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn electable_targets(bounds: DataProviderBounds) - -> data_provider::Result>; + fn electable_targets( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> data_provider::Result>; /// All the voters that participate in the election, thus "electing". /// @@ -307,7 +322,10 @@ pub trait ElectionDataProvider { /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn electing_voters(bounds: DataProviderBounds) -> data_provider::Result>>; + fn electing_voters( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> data_provider::Result>>; /// The number of targets to elect. /// @@ -361,28 +379,39 @@ pub trait ElectionDataProvider { /// Clear all voters and targets. #[cfg(any(feature = "runtime-benchmarks", test))] fn clear() {} + + #[cfg(any(feature = "runtime-benchmarks", test))] + fn set_desired_targets(_count: u32) {} } -/// Base trait for types that can provide election -pub trait ElectionProviderBase { - /// The account identifier type. +/// An [`ElectionDataProvider`] that exposes for an external entity to request a lock/unlock on +/// updates in the election data. +pub trait LockableElectionDataProvider: ElectionDataProvider { + fn set_lock() -> data_provider::Result<()>; + fn unlock(); +} + +/// Something that can compute the result of an election and pass it back to the caller in a paged +/// way. +pub trait ElectionProvider { + /// The account ID identifier; type AccountId; /// The block number type. type BlockNumber; - /// The error type that is returned by the provider. - type Error: Debug; + /// The error type returned by the provider; + type Error: Debug + PartialEq; - /// The upper bound on election winners that can be returned. - /// - /// # WARNING - /// - /// when communicating with the data provider, one must ensure that - /// `DataProvider::desired_targets` returns a value less than this bound. An - /// implementation can chose to either return an error and/or sort and - /// truncate the output to meet this bound. - type MaxWinners: Get; + /// The maximum number of winners per page in results returned by this election provider. + type MaxWinnersPerPage: Get; + + /// The maximum number of backers that a single page may have in results returned by this + /// election provider. + type MaxBackersPerWinner: Get; + + /// The number of pages that this election provider supports. + type Pages: Get; /// The data provider of the election. type DataProvider: ElectionDataProvider< @@ -390,11 +419,29 @@ pub trait ElectionProviderBase { BlockNumber = Self::BlockNumber, >; + /// Elect a new set of winners. + /// + /// The result is returned in a target major format, namely as vector of supports. + /// + /// This should be implemented as a self-weighing function. The implementor should register its + /// appropriate weight at the end of execution with the system pallet directly. + fn elect(remaining: PageIndex) -> Result, Self::Error>; + + /// The index of the *most* significant page that this election provider supports. + fn msp() -> PageIndex { + Self::Pages::get().saturating_sub(1) + } + + /// The index of the *least* significant page that this election provider supports. + fn lsp() -> PageIndex { + Zero::zero() + } + /// checked call to `Self::DataProvider::desired_targets()` ensuring the value never exceeds - /// [`Self::MaxWinners`]. + /// [`Self::MaxWinnersPerPage`]. fn desired_targets_checked() -> data_provider::Result { Self::DataProvider::desired_targets().and_then(|desired_targets| { - if desired_targets <= Self::MaxWinners::get() { + if desired_targets <= Self::MaxWinnersPerPage::get() { Ok(desired_targets) } else { Err("desired_targets must not be greater than MaxWinners.") @@ -403,30 +450,13 @@ pub trait ElectionProviderBase { } } -/// Elect a new set of winners, bounded by `MaxWinners`. -/// -/// It must always use [`ElectionProviderBase::DataProvider`] to fetch the data it needs. -/// -/// This election provider that could function asynchronously. This implies that this election might -/// needs data ahead of time (ergo, receives no arguments to `elect`), and might be `ongoing` at -/// times. -pub trait ElectionProvider: ElectionProviderBase { - /// Indicate if this election provider is currently ongoing an asynchronous election or not. - fn ongoing() -> bool; - - /// Performs the election. This should be implemented as a self-weighing function. The - /// implementor should register its appropriate weight at the end of execution with the - /// system pallet directly. - fn elect() -> Result, Self::Error>; -} - /// A (almost) marker trait that signifies an election provider as working synchronously. i.e. being /// *instant*. /// -/// This must still use the same data provider as with [`ElectionProviderBase::DataProvider`]. +/// This must still use the same data provider as with [`ElectionProvider::DataProvider`]. /// However, it can optionally overwrite the amount of voters and targets that are fetched from the /// data provider at runtime via `forced_input_voters_bound` and `forced_input_target_bound`. -pub trait InstantElectionProvider: ElectionProviderBase { +pub trait InstantElectionProvider: ElectionProvider { fn instant_elect( forced_input_voters_bound: DataProviderBounds, forced_input_target_bound: DataProviderBounds, @@ -436,39 +466,33 @@ pub trait InstantElectionProvider: ElectionProviderBase { /// An election provider that does nothing whatsoever. pub struct NoElection(core::marker::PhantomData); -impl ElectionProviderBase - for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> +impl ElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)> where DataProvider: ElectionDataProvider, - MaxWinners: Get, + MaxWinnersPerPage: Get, + MaxBackersPerWinner: Get, { type AccountId = AccountId; type BlockNumber = BlockNumber; type Error = &'static str; - type MaxWinners = MaxWinners; + type Pages = ConstU32<1>; type DataProvider = DataProvider; -} + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; -impl ElectionProvider - for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> -where - DataProvider: ElectionDataProvider, - MaxWinners: Get, -{ - fn ongoing() -> bool { - false - } - - fn elect() -> Result, Self::Error> { + fn elect(_remaining_pages: PageIndex) -> Result, Self::Error> { Err("`NoElection` cannot do anything.") } } -impl InstantElectionProvider - for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinners)> +impl + InstantElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider, MaxWinnersPerPage, MaxBackersPerWinner)> where DataProvider: ElectionDataProvider, - MaxWinners: Get, + MaxWinnersPerPage: Get, + MaxBackersPerWinner: Get, { fn instant_elect( _: DataProviderBounds, @@ -674,12 +698,161 @@ pub type Voter = (AccountId, VoteWeight, BoundedVec = Voter<::AccountId, ::MaxVotesPerVoter>; -/// Same as `BoundedSupports` but parameterized by a `ElectionProviderBase`. +/// A bounded vector of supports. Bounded equivalent to [`sp_npos_elections::Supports`]. +#[derive(Default, RuntimeDebug, Encode, Decode, scale_info::TypeInfo, MaxEncodedLen)] +#[codec(mel_bound(AccountId: MaxEncodedLen, Bound: Get))] +#[scale_info(skip_type_params(Bound))] +pub struct BoundedSupport> { + /// Total support. + pub total: ExtendedBalance, + /// Support from voters. + pub voters: BoundedVec<(AccountId, ExtendedBalance), Bound>, +} + +impl> sp_npos_elections::Backings for BoundedSupport { + fn total(&self) -> ExtendedBalance { + self.total + } +} + +impl> PartialEq for BoundedSupport { + fn eq(&self, other: &Self) -> bool { + self.total == other.total && self.voters == other.voters + } +} + +impl> From> for Support { + fn from(b: BoundedSupport) -> Self { + Support { total: b.total, voters: b.voters.into_inner() } + } +} + +impl> Clone for BoundedSupport { + fn clone(&self) -> Self { + Self { voters: self.voters.clone(), total: self.total } + } +} + +impl> TryFrom> + for BoundedSupport +{ + type Error = &'static str; + fn try_from(s: sp_npos_elections::Support) -> Result { + let voters = s.voters.try_into().map_err(|_| "voters bound not respected")?; + Ok(Self { voters, total: s.total }) + } +} + +/// A bounded vector of [`BoundedSupport`]. +#[derive(Encode, Decode, TypeInfo, DefaultNoBound, MaxEncodedLen)] +#[codec(mel_bound(AccountId: MaxEncodedLen, BOuter: Get, BInner: Get))] +#[scale_info(skip_type_params(BOuter, BInner))] +pub struct BoundedSupports, BInner: Get>( + pub BoundedVec<(AccountId, BoundedSupport), BOuter>, +); + +impl, BInner: Get> Debug + for BoundedSupports +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + for s in self.0.iter() { + write!(f, "({:?}, {:?}, {:?}) ", s.0, s.1.total, s.1.voters)?; + } + Ok(()) + } +} + +impl, BInner: Get> PartialEq + for BoundedSupports +{ + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl, BInner: Get> + From), BOuter>> + for BoundedSupports +{ + fn from(t: BoundedVec<(AccountId, BoundedSupport), BOuter>) -> Self { + Self(t) + } +} + +impl, BInner: Get> Clone + for BoundedSupports +{ + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl, BInner: Get> sp_std::ops::Deref + for BoundedSupports +{ + type Target = BoundedVec<(AccountId, BoundedSupport), BOuter>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl, BInner: Get> IntoIterator + for BoundedSupports +{ + type Item = (AccountId, BoundedSupport); + type IntoIter = sp_std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +/// An extension trait to convert from [`sp_npos_elections::Supports`] into +/// [`BoundedSupports`]. +pub trait TryIntoBoundedSupports, BInner: Get> { + /// Perform the conversion. + fn try_into_bounded_supports(self) -> Result, ()>; +} + +impl, BInner: Get> + TryIntoBoundedSupports for sp_npos_elections::Supports +{ + fn try_into_bounded_supports(self) -> Result, ()> { + let inner_bounded_supports = self + .into_iter() + .map(|(a, s)| s.try_into().map(|s| (a, s))) + .collect::, _>>() + .map_err(|_| ())?; + let outer_bounded_supports: BoundedVec<_, BOuter> = + inner_bounded_supports.try_into().map_err(|_| ())?; + Ok(outer_bounded_supports.into()) + } +} + +pub trait TryIntoSupports, BInner: Get> { + fn try_into_supports(self) -> Result, ()>; +} + +impl, BInner: Get> TryIntoSupports + for BoundedSupports +{ + fn try_into_supports(self) -> Result, ()> { + // TODO + Ok(Default::default()) + } +} + +/// Same as `BoundedSupports` but parameterized by an `ElectionProvider`. pub type BoundedSupportsOf = BoundedSupports< - ::AccountId, - ::MaxWinners, + ::AccountId, + ::MaxWinnersPerPage, + ::MaxBackersPerWinner, >; +/// A page index for the multi-block elections pagination. +pub type PageIndex = u32; + sp_core::generate_feature_enabled_macro!( runtime_benchmarks_enabled, feature = "runtime-benchmarks", diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 1063d5d35aee7..f7349d5fd0cda 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -21,14 +21,15 @@ use crate::{ bounds::{DataProviderBounds, ElectionBounds, ElectionBoundsBuilder}, - BoundedSupportsOf, Debug, ElectionDataProvider, ElectionProvider, ElectionProviderBase, - InstantElectionProvider, NposSolver, WeightInfo, + BoundedSupportsOf, Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, + NposSolver, PageIndex, TryIntoBoundedSupports, WeightInfo, Zero, }; use alloc::collections::btree_map::BTreeMap; use core::marker::PhantomData; use frame_support::{dispatch::DispatchClass, traits::Get}; +use frame_system::pallet_prelude::BlockNumberFor; use sp_npos_elections::{ - assignment_ratio_to_staked_normalized, to_supports, BoundedSupports, ElectionResult, VoteWeight, + assignment_ratio_to_staked_normalized, to_supports, ElectionResult, VoteWeight, }; /// Errors of the on-chain election. @@ -41,6 +42,8 @@ pub enum Error { /// Configurational error caused by `desired_targets` requested by data provider exceeding /// `MaxWinners`. TooManyWinners, + /// Single page election called with multi-page configs. + SinglePageExpected, } impl From for Error { @@ -71,6 +74,18 @@ pub trait Config { Error = sp_npos_elections::Error, >; + /// Maximum number of backers allowed per target. + /// + /// If the bounds are exceeded due to the data returned by the data provider, the election will + /// fail. + type MaxBackersPerWinner: Get; + + /// Maximum number of winners in an election. + /// + /// If the bounds are exceeded due to the data returned by the data provider, the election will + /// fail. + type MaxWinnersPerPage: Get; + /// Something that provides the data for election. type DataProvider: ElectionDataProvider< AccountId = ::AccountId, @@ -80,78 +95,64 @@ pub trait Config { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - /// Upper bound on maximum winners from electable targets. - /// - /// As noted in the documentation of [`ElectionProviderBase::MaxWinners`], this value should - /// always be more than `DataProvider::desired_target`. - type MaxWinners: Get; - /// Elections bounds, to use when calling into [`Config::DataProvider`]. It might be overwritten /// in the `InstantElectionProvider` impl. type Bounds: Get; } -/// Same as `BoundedSupportsOf` but for `onchain::Config`. -pub type OnChainBoundedSupportsOf = BoundedSupports< - <::System as frame_system::Config>::AccountId, - ::MaxWinners, ->; - -fn elect_with_input_bounds( - bounds: ElectionBounds, -) -> Result, Error> { - let (voters, targets) = T::DataProvider::electing_voters(bounds.voters) - .and_then(|voters| Ok((voters, T::DataProvider::electable_targets(bounds.targets)?))) - .map_err(Error::DataProvider)?; - - let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; - - if desired_targets > T::MaxWinners::get() { - // early exit - return Err(Error::TooManyWinners) - } - - let voters_len = voters.len() as u32; - let targets_len = targets.len() as u32; +impl OnChainExecution { + fn elect_with( + bounds: ElectionBounds, + remaining: PageIndex, + ) -> Result, Error> { + let (voters, targets) = T::DataProvider::electing_voters(bounds.voters, remaining) + .and_then(|voters| { + Ok((voters, T::DataProvider::electable_targets(bounds.targets, remaining)?)) + }) + .map_err(Error::DataProvider)?; + + let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; + + if desired_targets > T::MaxWinnersPerPage::get() { + // early exit + return Err(Error::TooManyWinners) + } - let stake_map: BTreeMap<_, _> = voters - .iter() - .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) - .collect(); + let voters_len = voters.len() as u32; + let targets_len = targets.len() as u32; - let stake_of = |w: &::AccountId| -> VoteWeight { - stake_map.get(w).cloned().unwrap_or_default() - }; + let stake_map: BTreeMap<_, _> = voters + .iter() + .map(|(validator, vote_weight, _)| (validator.clone(), *vote_weight)) + .collect(); - let ElectionResult { winners: _, assignments } = - T::Solver::solve(desired_targets as usize, targets, voters).map_err(Error::from)?; + let stake_of = |w: &::AccountId| -> VoteWeight { + stake_map.get(w).cloned().unwrap_or_default() + }; - let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; + let ElectionResult { winners: _, assignments } = + T::Solver::solve(desired_targets as usize, targets, voters).map_err(Error::from)?; - let weight = T::Solver::weight::( - voters_len, - targets_len, - ::MaxVotesPerVoter::get(), - ); - frame_system::Pallet::::register_extra_weight_unchecked( - weight, - DispatchClass::Mandatory, - ); + let staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; - // defensive: Since npos solver returns a result always bounded by `desired_targets`, this is - // never expected to happen as long as npos solver does what is expected for it to do. - let supports: OnChainBoundedSupportsOf = - to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; + let weight = T::Solver::weight::( + voters_len, + targets_len, + ::MaxVotesPerVoter::get(), + ); + frame_system::Pallet::::register_extra_weight_unchecked( + weight, + DispatchClass::Mandatory, + ); - Ok(supports) -} + // defensive: Since npos solver returns a result always bounded by `desired_targets`, this + // is never expected to happen as long as npos solver does what is expected for it to do. + let supports: BoundedSupportsOf = to_supports(&staked) + .try_into_bounded_supports() + .map_err(|_| Error::TooManyWinners)?; -impl ElectionProviderBase for OnChainExecution { - type AccountId = ::AccountId; - type BlockNumber = frame_system::pallet_prelude::BlockNumberFor; - type Error = Error; - type MaxWinners = T::MaxWinners; - type DataProvider = T::DataProvider; + Ok(supports) + } } impl InstantElectionProvider for OnChainExecution { @@ -164,18 +165,27 @@ impl InstantElectionProvider for OnChainExecution { .targets_or_lower(forced_input_targets_bounds) .build(); - elect_with_input_bounds::(elections_bounds) + // NOTE: instant provider is *always* single page. + Self::elect_with(elections_bounds, Zero::zero()) } } impl ElectionProvider for OnChainExecution { - fn ongoing() -> bool { - false - } + type AccountId = ::AccountId; + type BlockNumber = BlockNumberFor; + type Error = Error; + type MaxWinnersPerPage = T::MaxWinnersPerPage; + type MaxBackersPerWinner = T::MaxBackersPerWinner; + type Pages = sp_core::ConstU32<1>; + type DataProvider = T::DataProvider; + + fn elect(remaining_pages: PageIndex) -> Result, Self::Error> { + if remaining_pages > 0 { + return Err(Error::SinglePageExpected) + } - fn elect() -> Result, Self::Error> { let election_bounds = ElectionBoundsBuilder::from(T::Bounds::get()).build(); - elect_with_input_bounds::(election_bounds) + Self::elect_with(election_bounds, Zero::zero()) } } @@ -231,7 +241,8 @@ mod tests { struct PhragMMSParams; parameter_types! { - pub static MaxWinners: u32 = 10; + pub static MaxWinnersPerPage: u32 = 10; + pub static MaxBackersPerWinner: u32 = 20; pub static DesiredTargets: u32 = 2; pub static Bounds: ElectionBounds = ElectionBoundsBuilder::default().voters_count(600.into()).targets_count(400.into()).build(); } @@ -240,17 +251,19 @@ mod tests { type System = Runtime; type Solver = SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; - type WeightInfo = (); - type MaxWinners = MaxWinners; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type Bounds = Bounds; + type WeightInfo = (); } impl Config for PhragMMSParams { type System = Runtime; type Solver = PhragMMS; type DataProvider = mock_data_provider::DataProvider; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type WeightInfo = (); - type MaxWinners = MaxWinners; type Bounds = Bounds; } @@ -259,14 +272,17 @@ mod tests { use sp_runtime::bounded_vec; use super::*; - use crate::{data_provider, VoterOf}; + use crate::{data_provider, PageIndex, VoterOf}; pub struct DataProvider; impl ElectionDataProvider for DataProvider { type AccountId = AccountId; type BlockNumber = BlockNumber; type MaxVotesPerVoter = ConstU32<2>; - fn electing_voters(_: DataProviderBounds) -> data_provider::Result>> { + fn electing_voters( + _: DataProviderBounds, + _remaining_pages: PageIndex, + ) -> data_provider::Result>> { Ok(vec![ (1, 10, bounded_vec![10, 20]), (2, 20, bounded_vec![30, 20]), @@ -274,7 +290,10 @@ mod tests { ]) } - fn electable_targets(_: DataProviderBounds) -> data_provider::Result> { + fn electable_targets( + _: DataProviderBounds, + _remaining_pages: PageIndex, + ) -> data_provider::Result> { Ok(vec![10, 20, 30]) } @@ -291,12 +310,19 @@ mod tests { #[test] fn onchain_seq_phragmen_works() { sp_io::TestExternalities::new_empty().execute_with(|| { + let expected_suports = vec![ + ( + 10 as AccountId, + Support { total: 25, voters: vec![(1 as AccountId, 10), (3, 15)] }, + ), + (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }), + ] + .try_into_bounded_supports() + .unwrap(); + assert_eq!( - as ElectionProvider>::elect().unwrap(), - vec![ - (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), - (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) - ] + as ElectionProvider>::elect(0).unwrap(), + expected_suports, ); }) } @@ -306,10 +332,10 @@ mod tests { sp_io::TestExternalities::new_empty().execute_with(|| { // given desired targets larger than max winners DesiredTargets::set(10); - MaxWinners::set(9); + MaxWinnersPerPage::set(9); assert_noop!( - as ElectionProvider>::elect(), + as ElectionProvider>::elect(0), Error::TooManyWinners, ); }) @@ -319,11 +345,16 @@ mod tests { fn onchain_phragmms_works() { sp_io::TestExternalities::new_empty().execute_with(|| { assert_eq!( - as ElectionProvider>::elect().unwrap(), + as ElectionProvider>::elect(0).unwrap(), vec![ - (10, Support { total: 25, voters: vec![(1, 10), (3, 15)] }), + ( + 10 as AccountId, + Support { total: 25, voters: vec![(1 as AccountId, 10), (3, 15)] } + ), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) ] + .try_into_bounded_supports() + .unwrap() ); }) } diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 82ac40fe27378..9a9d33aa8e20d 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -83,7 +83,7 @@ use scale_info::TypeInfo; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; -use sp_core::{bounded::BoundedVec, RuntimeDebug}; +use sp_core::RuntimeDebug; #[cfg(test)] mod mock; @@ -110,7 +110,7 @@ pub use reduce::reduce; pub use traits::{IdentifierT, PerThing128}; /// The errors that might occur in this crate and `frame-election-provider-solution-type`. -#[derive(Eq, PartialEq, RuntimeDebug)] +#[derive(Eq, PartialEq, RuntimeDebug, Clone)] pub enum Error { /// While going from solution indices to ratio, the weight of all the edges has gone above the /// total. @@ -444,6 +444,12 @@ impl Default for Support { } } +impl Backings for &Support { + fn total(&self) -> ExtendedBalance { + self.total + } +} + /// A target-major representation of the the election outcome. /// /// Essentially a flat variant of [`SupportMap`]. @@ -451,11 +457,6 @@ impl Default for Support { /// The main advantage of this is that it is encodable. pub type Supports = Vec<(A, Support)>; -/// Same as `Supports` but bounded by `B`. -/// -/// To note, the inner `Support` is still unbounded. -pub type BoundedSupports = BoundedVec<(A, Support), B>; - /// Linkage from a winner to their [`Support`]. /// /// This is more helpful than a normal [`Supports`] as it allows faster error checking. @@ -499,23 +500,34 @@ pub trait EvaluateSupport { impl EvaluateSupport for Supports { fn evaluate(&self) -> ElectionScore { - let mut minimal_stake = ExtendedBalance::max_value(); - let mut sum_stake: ExtendedBalance = Zero::zero(); - // NOTE: The third element might saturate but fine for now since this will run on-chain and - // need to be fast. - let mut sum_stake_squared: ExtendedBalance = Zero::zero(); - - for (_, support) in self { - sum_stake = sum_stake.saturating_add(support.total); - let squared = support.total.saturating_mul(support.total); - sum_stake_squared = sum_stake_squared.saturating_add(squared); - if support.total < minimal_stake { - minimal_stake = support.total; - } - } + evaluate_support(self.iter().map(|(_, s)| s)) + } +} + +/// Generic representation of a support. +pub trait Backings { + /// The total backing of an individual target. + fn total(&self) -> ExtendedBalance; +} - ElectionScore { minimal_stake, sum_stake, sum_stake_squared } +/// General evaluation of a list of backings that returns an election score. +pub fn evaluate_support(backings: impl Iterator) -> ElectionScore { + let mut minimal_stake = ExtendedBalance::max_value(); + let mut sum_stake: ExtendedBalance = Zero::zero(); + // NOTE: The third element might saturate but fine for now since this will run on-chain and + // need to be fast. + let mut sum_stake_squared: ExtendedBalance = Zero::zero(); + + for support in backings { + sum_stake = sum_stake.saturating_add(support.total()); + let squared = support.total().saturating_mul(support.total()); + sum_stake_squared = sum_stake_squared.saturating_add(squared); + if support.total() < minimal_stake { + minimal_stake = support.total(); + } } + + ElectionScore { minimal_stake, sum_stake, sum_stake_squared } } /// Converts raw inputs to types used in this crate. diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 35e7e4f604136..80220cd1f6fcc 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -23,6 +23,7 @@ impl-trait-for-tuples = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } [features] default = ["std"] @@ -32,5 +33,6 @@ std = [ "serde/std", "sp-core/std", "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 17010a8907fc2..8dd29bb835de6 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -357,6 +357,8 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[codec(mel_bound(T: Config))] +#[scale_info(skip_type_params(T))] pub struct Exposure { /// The total balance backing this validator. #[codec(compact)] @@ -432,6 +434,44 @@ impl Default for ExposurePage { } } +impl + From>> for ExposurePage +{ + fn from(exposures: Vec>) -> Self { + let mut page: Self = Default::default(); + + let _ = exposures + .into_iter() + .map(|e| { + page.page_total += e.value.clone(); + page.others.push(e) + }) + .collect::>(); + + page + } +} + +impl< + A, + B: Default + + HasCompact + + core::fmt::Debug + + sp_std::ops::AddAssign + + sp_std::ops::SubAssign + + Clone, + > ExposurePage +{ + /// Split the current exposure page into two pages where the new page takes up to `num` + /// individual exposures. The remaining individual exposures are left in `self`. + pub fn from_split_others(&mut self, num: usize) -> Self { + let new: ExposurePage<_, _> = self.others.split_off(num).into(); + self.page_total -= new.page_total.clone(); + + new + } +} + /// Metadata for Paged Exposure of a validator such as total stake across pages and page count. /// /// In combination with the associated `ExposurePage`s, it can be used to reconstruct a full @@ -449,6 +489,7 @@ impl Default for ExposurePage { TypeInfo, Default, MaxEncodedLen, + Copy, )] pub struct PagedExposureMetadata { /// The total balance backing this validator. @@ -463,6 +504,28 @@ pub struct PagedExposureMetadata { pub page_count: Page, } +impl PagedExposureMetadata +where + Balance: HasCompact + + codec::MaxEncodedLen + + sp_std::ops::Add + + sp_std::ops::Sub + + PartialEq + + Copy, +{ + pub fn merge(self, other: Self) -> Self { + debug_assert!(self.own == other.own); + + Self { + total: self.total + other.total - self.own, + own: self.own, + nominator_count: self.nominator_count + other.nominator_count, + // TODO: merge the pages correctly. + page_count: self.page_count + other.page_count, + } + } +} + /// A type that belongs only in the context of an `Agent`. /// /// `Agent` is someone that manages delegated funds from [`Delegator`] accounts. It can From 8a682b8b9d74d462d8f8151778a369ea50499f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 14 Oct 2024 00:47:07 +0200 Subject: [PATCH 02/95] refactors staking pallet with new paginated types --- Cargo.lock | 3229 ++++++++++--------- substrate/frame/staking/src/benchmarking.rs | 5 +- substrate/frame/staking/src/lib.rs | 60 +- substrate/frame/staking/src/mock.rs | 27 +- substrate/frame/staking/src/pallet/impls.rs | 267 +- substrate/frame/staking/src/pallet/mod.rs | 220 +- substrate/frame/staking/src/tests.rs | 347 +- substrate/primitives/staking/src/lib.rs | 3 +- 8 files changed, 2393 insertions(+), 1765 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba5f04aaf9997..f9dd4d9781b63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.28.0", + "gimli 0.28.1", ] [[package]] @@ -36,6 +36,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "adler32" version = "1.2.0" @@ -54,9 +60,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher 0.4.4", @@ -74,7 +80,7 @@ dependencies = [ "cipher 0.4.4", "ctr", "ghash", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -112,18 +118,18 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-primitives" @@ -147,13 +153,12 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +checksum = "26154390b1d205a4a7ac7352aa2eb4f81f391399d4e2f546fb81a2f8bb383f62" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bytes", - "smol_str", ] [[package]] @@ -166,7 +171,7 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", "syn-solidity", @@ -223,57 +228,58 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "approx" @@ -293,7 +299,7 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -483,7 +489,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -527,7 +533,7 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -558,20 +564,6 @@ dependencies = [ "hashbrown 0.13.2", ] -[[package]] -name = "ark-scale" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "parity-scale-codec", - "scale-info", -] - [[package]] name = "ark-scale" version = "0.0.12" @@ -629,7 +621,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -670,15 +662,15 @@ dependencies = [ [[package]] name = "array-bytes" -version = "6.2.2" +version = "6.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" +checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293" [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" @@ -697,9 +689,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "asn1-rs" @@ -719,11 +711,11 @@ dependencies = [ [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ - "asn1-rs-derive 0.5.0", + "asn1-rs-derive 0.5.1", "asn1-rs-impl 0.2.0", "displaydoc", "nom", @@ -739,7 +731,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", "synstructure 0.12.6", @@ -747,11 +739,11 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", "synstructure 0.13.1", @@ -763,7 +755,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -774,21 +766,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "assert_cmd" -version = "2.0.14" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ "anstyle", "bstr", "doc-comment", - "predicates 3.0.3", + "libc", + "predicates 3.1.2", "predicates-core", "predicates-tree", "wait-timeout", @@ -1134,12 +1127,11 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.2.0", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -1147,15 +1139,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.5.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ - "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand 1.9.0", - "futures-lite 1.13.0", + "fastrand 2.1.1", + "futures-lite 2.3.0", "slab", ] @@ -1184,16 +1175,16 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 1.9.0", + "async-channel 2.3.1", "async-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io 2.3.4", + "async-lock 3.4.0", "blocking", - "futures-lite 1.13.0", + "futures-lite 2.3.0", "once_cell", ] @@ -1211,17 +1202,17 @@ dependencies = [ "log", "parking", "polling 2.8.0", - "rustix 0.37.23", + "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if", @@ -1229,11 +1220,11 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.4.0", - "rustix 0.38.21", + "polling 3.7.3", + "rustix 0.38.37", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1251,19 +1242,18 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.2.0", + "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-net" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" +checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" dependencies = [ "async-io 1.13.0", - "autocfg", "blocking", "futures-lite 1.13.0", ] @@ -1274,26 +1264,25 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "blocking", "futures-lite 2.3.0", ] [[package]] name = "async-process" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" +checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", - "autocfg", + "async-signal", "blocking", "cfg-if", - "event-listener 2.5.3", + "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.37.23", - "signal-hook", + "rustix 0.38.37", "windows-sys 0.48.0", ] @@ -1303,53 +1292,53 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ - "async-channel 2.3.0", - "async-io 2.3.3", + "async-channel 2.3.1", + "async-io 2.3.4", "async-lock 3.4.0", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.2.0", + "event-listener 5.3.1", "futures-lite 2.3.0", - "rustix 0.38.21", + "rustix 0.38.37", "tracing", ] [[package]] name = "async-signal" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.21", + "rustix 0.38.37", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io 2.3.4", + "async-lock 3.4.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite 2.3.0", "gloo-timers", "kv-log-macro", "log", @@ -1363,9 +1352,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -1374,11 +1363,11 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -1391,11 +1380,11 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -1421,9 +1410,9 @@ checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attohttpc" @@ -1431,7 +1420,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" dependencies = [ - "http 0.2.9", + "http 0.2.12", "log", "url", ] @@ -1449,21 +1438,20 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backoff" @@ -1486,7 +1474,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object 0.32.2", "rustc-demangle", ] @@ -1554,15 +1542,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "basic-toml" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" -dependencies = [ - "serde", -] - [[package]] name = "beef" version = "0.5.2" @@ -1607,7 +1586,7 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "rustc-hash 1.1.0", @@ -1617,11 +1596,11 @@ dependencies = [ [[package]] name = "bip39" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" dependencies = [ - "bitcoin_hashes 0.11.0", + "bitcoin_hashes", "serde", "unicode-normalization", ] @@ -1647,12 +1626,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" -[[package]] -name = "bitcoin_hashes" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" - [[package]] name = "bitcoin_hashes" version = "0.13.0" @@ -1737,8 +1710,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.4", - "constant_time_eq 0.3.0", + "arrayvec 0.7.6", + "constant_time_eq 0.3.1", ] [[package]] @@ -1754,13 +1727,13 @@ dependencies = [ [[package]] name = "blake2s_simd" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" dependencies = [ "arrayref", - "arrayvec 0.7.4", - "constant_time_eq 0.2.6", + "arrayvec 0.7.6", + "constant_time_eq 0.3.1", ] [[package]] @@ -1770,10 +1743,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "cc", "cfg-if", - "constant_time_eq 0.3.0", + "constant_time_eq 0.3.1", ] [[package]] @@ -1803,24 +1776,22 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.3.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "async-channel 1.9.0", - "async-lock 2.8.0", + "async-channel 2.3.1", "async-task", - "atomic-waker", - "fastrand 1.9.0", - "futures-lite 1.13.0", - "log", + "futures-io", + "futures-lite 2.3.0", + "piper", ] [[package]] name = "bounded-collections" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32385ecb91a31bddaf908e8dcf4a15aef1bcd3913cc03ebfad02ff6d568abc1" +checksum = "db436177db0d505b1507f03aca56a41442ae6efdf8b6eaa855d73e52c5b078dc" dependencies = [ "log", "parity-scale-codec", @@ -2569,12 +2540,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.3.6", + "regex-automata 0.4.8", "serde", ] @@ -2589,9 +2560,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byte-slice-cast" @@ -2607,9 +2578,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" [[package]] name = "byteorder" @@ -2665,18 +2636,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -2689,7 +2660,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.18", + "semver 1.0.23", "serde", "serde_json", "thiserror", @@ -2709,9 +2680,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.1.24" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", @@ -2735,9 +2706,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.5" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", ] @@ -2821,9 +2792,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2831,14 +2802,14 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -2847,15 +2818,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -2929,9 +2900,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -2967,48 +2938,48 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] name = "clap" -version = "4.5.13" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", - "clap_derive 4.5.13", + "clap_derive 4.5.18", ] [[package]] name = "clap-num" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" +checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" dependencies = [ "num-traits", ] [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.0", + "clap_lex 0.7.2", "strsim 0.11.1", "terminal_size", ] [[package]] name = "clap_complete" -version = "4.5.13" +version = "4.5.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa3c596da3cf0983427b0df0dba359df9182c13bd5b519b585a482b0c351f4e8" +checksum = "9646e2e245bf62f45d39a0f3f36f1171ad1ea0d6967fd114bca72cb02a8fcdfb" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", ] [[package]] @@ -3019,19 +2990,19 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -3047,19 +3018,18 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "coarsetime" -version = "0.1.23" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" +checksum = "13b3839cf01bb7960114be3ccf2340f541b6d0c81f8690b007b2b39f750f7e5d" dependencies = [ "libc", - "once_cell", - "wasi", + "wasix", "wasm-bindgen", ] @@ -3207,47 +3177,46 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" dependencies = [ "nom", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", "windows-sys 0.48.0", ] [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -3255,12 +3224,12 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.0" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686" +checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" dependencies = [ - "strum 0.25.0", - "strum_macros 0.25.3", + "strum 0.26.3", + "strum_macros 0.26.4", "unicode-width", ] @@ -3305,7 +3274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a54b9c40054eb8999c5d1d36fdc90e4e5f7ff0d1d9621706f360b3cbc8beb828" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -3317,16 +3286,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5437e327e861081c91270becff184859f706e3e50f5301a9d4dc8eb50752c3" dependencies = [ "convert_case 0.6.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -3356,9 +3325,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.10.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" dependencies = [ "cfg-if", "cpufeatures", @@ -3369,29 +3338,27 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const-random" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", - "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ "getrandom", "once_cell", - "proc-macro-hack", "tiny-keccak", ] @@ -3403,21 +3370,15 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" - -[[package]] -name = "constant_time_eq" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "constcat" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f272d0c4cf831b4fa80ee529c7707f76585986e910e1fbce1d7921970bc1a241" +checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" [[package]] name = "contracts-rococo-runtime" @@ -3516,9 +3477,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -3739,9 +3700,9 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] @@ -3758,9 +3719,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -3859,15 +3820,15 @@ dependencies = [ "itertools 0.10.5", "log", "smallvec", - "wasmparser", + "wasmparser 0.102.0", "wasmtime-types", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -3881,7 +3842,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.13", + "clap 4.5.20", "criterion-plot", "futures", "is-terminal", @@ -3912,46 +3873,37 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -3961,13 +3913,13 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -3999,7 +3951,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -4015,7 +3967,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -4387,8 +4339,8 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -4478,7 +4430,7 @@ name = "cumulus-pov-validator" version = "0.1.0" dependencies = [ "anyhow", - "clap 4.5.13", + "clap 4.5.20", "parity-scale-codec", "polkadot-node-primitives", "polkadot-parachain-primitives", @@ -4617,7 +4569,7 @@ dependencies = [ "async-trait", "cumulus-primitives-core", "futures", - "jsonrpsee-core 0.24.3", + "jsonrpsee-core 0.24.6", "parity-scale-codec", "polkadot-overseer", "sc-client-api", @@ -4672,7 +4624,7 @@ dependencies = [ "either", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "pin-project", "polkadot-overseer", @@ -4798,7 +4750,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.13", + "clap 4.5.20", "criterion", "cumulus-client-cli", "cumulus-client-collator", @@ -4821,7 +4773,7 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "pallet-timestamp", "pallet-transaction-payment", "parachains-common", @@ -4876,9 +4828,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" dependencies = [ "curl-sys", "libc", @@ -4891,9 +4843,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.72+curl-8.6.0" +version = "0.4.77+curl-8.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "f469e8a5991f277a208224f6c7ad72ecb5f986e36d09ae1f2c1bb9259478a480" dependencies = [ "cc", "libc", @@ -4914,7 +4866,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -4929,18 +4881,18 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", - "subtle 2.5.0", + "rustc_version 0.4.1", + "subtle 2.6.1", "zeroize", ] [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -4960,9 +4912,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.106" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" +checksum = "54ccead7d199d584d139148b04b4a368d1ec7556a1d9ea2548febb1b9d49f9a4" dependencies = [ "cc", "cxxbridge-flags", @@ -4972,14 +4924,14 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.106" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" +checksum = "c77953e99f01508f89f55c494bfa867171ef3a6c8cea03d26975368f2121a5c1" dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "scratch", "syn 2.0.79", @@ -4987,17 +4939,17 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.106" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" +checksum = "65777e06cc48f0cb0152024c77d6cf9e4bdb4408e7b48bea993d42fa0f5b02b6" [[package]] name = "cxxbridge-macro" -version = "1.0.106" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" +checksum = "98532a60dedaebc4848cb2cba5023337cc9ea3af16a5b062633fabfd9f18fb60" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -5030,7 +4982,7 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "strsim 0.10.0", "syn 1.0.109", @@ -5044,7 +4996,7 @@ checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "strsim 0.11.1", "syn 2.0.79", @@ -5074,28 +5026,28 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.1" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.10", ] [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -5103,9 +5055,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" dependencies = [ "data-encoding", "syn 1.0.109", @@ -5122,9 +5074,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "zeroize", @@ -5150,7 +5102,7 @@ version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", "displaydoc", "nom", "num-bigint", @@ -5173,7 +5125,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -5184,7 +5136,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -5195,7 +5147,7 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -5206,22 +5158,22 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", - "rustc_version 0.4.0", - "syn 1.0.109", + "rustc_version 0.4.1", + "syn 2.0.79", ] [[package]] @@ -5263,7 +5215,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -5310,20 +5262,20 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "dissimilar" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" [[package]] name = "dleq_vrf" @@ -5332,22 +5284,24 @@ source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b dependencies = [ "ark-ec", "ark-ff 0.4.2", - "ark-scale 0.0.12", + "ark-scale", "ark-secret-scalar", "ark-serialize 0.4.2", "ark-std 0.4.0", "ark-transcript", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "zeroize", ] [[package]] name = "dlmalloc" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" +checksum = "d9b5e0d321d61de16390ed273b647ce51605b575916d3c25e6ddf27a1e140035" dependencies = [ + "cfg-if", "libc", + "windows-sys 0.59.0", ] [[package]] @@ -5374,12 +5328,12 @@ dependencies = [ "common-path", "derive-syn-parse", "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "syn 2.0.79", "termcolor", - "toml 0.8.12", + "toml 0.8.19", "walkdir", ] @@ -5400,9 +5354,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "dtoa" @@ -5412,9 +5366,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clonable" @@ -5432,22 +5386,22 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "dyn-clone" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "ecdsa" -version = "0.16.8" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest 0.10.7", @@ -5460,9 +5414,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", @@ -5479,7 +5433,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -5534,7 +5488,7 @@ dependencies = [ "rand_core 0.6.4", "sec1", "serdect", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -5580,9 +5534,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -5594,59 +5548,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "enum-as-inner" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.86", + "heck 0.5.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "enumflags2" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" +checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" +checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "enumn" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -5664,9 +5618,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -5677,9 +5631,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -5717,11 +5671,12 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" dependencies = [ "serde", + "typeid", ] [[package]] @@ -5736,32 +5691,32 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "ethabi-decode" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "09d398648d65820a727d6a81e58b962f874473396a047e4c30bafe3240953417" dependencies = [ - "cc", - "libc", + "ethereum-types 0.14.1", + "tiny-keccak", ] [[package]] -name = "ethabi-decode" -version = "1.1.0" +name = "ethbloom" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9af52ec57c5147716872863c2567c886e7d62f539465b94352dbc0108fe5293" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ - "ethereum-types", + "crunchy", + "fixed-hash", "tiny-keccak", ] @@ -5780,13 +5735,25 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash", + "primitive-types 0.12.2", + "uint 0.9.5", +] + [[package]] name = "ethereum-types" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab15ed80916029f878e0267c3a9f92b67df55e79af370bf66199059ae2b4ee3" dependencies = [ - "ethbloom", + "ethbloom 0.14.1", "fixed-hash", "impl-codec 0.7.0", "impl-rlp", @@ -5804,7 +5771,18 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.3" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ @@ -5814,9 +5792,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5fb89194fa3cad959b833185b3063ba881dbfc7030680b314250779fb4cc91" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -5829,7 +5807,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.2.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -5852,16 +5830,16 @@ dependencies = [ "file-guard", "fs-err", "prettyplease", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "eyre" -version = "0.6.8" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ "indenter", "once_cell", @@ -5890,9 +5868,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fastrlp" @@ -5900,7 +5878,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "auto_impl", "bytes", ] @@ -5922,9 +5900,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", - "indexmap 2.2.3", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "indexmap 2.6.0", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -5962,7 +5940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -5980,9 +5958,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file-guard" @@ -6000,20 +5978,20 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.1", + "env_logger 0.10.2", "log", ] [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -6090,12 +6068,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -6113,6 +6091,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -6203,7 +6187,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.5.13", + "clap 4.5.20", "comfy-table", "frame-benchmarking", "frame-support", @@ -6264,8 +6248,8 @@ dependencies = [ "frame-election-provider-support", "frame-support", "parity-scale-codec", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", @@ -6295,7 +6279,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -6378,7 +6362,7 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "cumulus-primitives-proof-size-hostfunction", "frame-benchmarking-cli", "log", @@ -6394,7 +6378,7 @@ version = "0.35.0" dependencies = [ "futures", "indicatif", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "serde", @@ -6473,8 +6457,8 @@ dependencies = [ "macro_magic", "parity-scale-codec", "pretty_assertions", - "proc-macro-warning 1.0.0", - "proc-macro2 1.0.86", + "proc-macro-warning 1.0.2", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "scale-info", @@ -6492,8 +6476,8 @@ name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -6502,7 +6486,7 @@ dependencies = [ name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -6627,9 +6611,12 @@ dependencies = [ [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "fs2" @@ -6647,7 +6634,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.37", "windows-sys 0.48.0", ] @@ -6665,9 +6652,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -6690,9 +6677,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -6700,15 +6687,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -6718,9 +6705,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -6743,7 +6730,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -6752,11 +6739,11 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -6768,20 +6755,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd3cf68c183738046838e300353e4716c674dc5e56890de4826801a6622a28" dependencies = [ "futures-io", - "rustls 0.21.7", + "rustls 0.21.12", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -6791,9 +6778,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -6861,9 +6848,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -6882,11 +6869,11 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "polyval", ] @@ -6903,9 +6890,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator 0.3.0", "stable_deref_trait", @@ -6925,9 +6912,9 @@ checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -6982,9 +6969,9 @@ dependencies = [ [[package]] name = "governor" -version = "0.6.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ "cfg-if", "dashmap", @@ -6993,9 +6980,11 @@ dependencies = [ "no-std-compat", "nonzero_ext", "parking_lot 0.12.3", + "portable-atomic", "quanta", "rand", "smallvec", + "spinning_top", ] [[package]] @@ -7006,7 +6995,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -7020,8 +7009,8 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.9", - "indexmap 2.2.3", + "http 0.2.12", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -7030,9 +7019,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", @@ -7040,7 +7029,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.3", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -7049,15 +7038,19 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "handlebars" -version = "5.1.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", @@ -7111,6 +7104,17 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashlink" version = "0.8.4" @@ -7156,6 +7160,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -7164,9 +7174,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex-literal" @@ -7183,7 +7193,7 @@ dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner 0.6.0", + "enum-as-inner 0.6.1", "futures-channel", "futures-io", "futures-util", @@ -7269,14 +7279,14 @@ dependencies = [ [[package]] name = "honggfuzz" -version = "0.5.55" +version = "0.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" dependencies = [ "arbitrary", "lazy_static", - "memmap2 0.5.10", - "rustc_version 0.4.0", + "memmap2 0.9.5", + "rustc_version 0.4.1", ] [[package]] @@ -7292,9 +7302,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -7314,20 +7324,20 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http 0.2.9", + "http 0.2.12", "pin-project-lite", ] [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http 1.1.0", @@ -7342,7 +7352,7 @@ dependencies = [ "bytes", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -7354,9 +7364,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -7372,17 +7382,17 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -7396,16 +7406,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", + "h2 0.4.6", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -7422,10 +7432,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.9", - "hyper 0.14.29", + "http 0.2.12", + "hyper 0.14.30", "log", - "rustls 0.21.7", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -7433,21 +7443,21 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", "log", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -7456,7 +7466,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.29", + "hyper 0.14.30", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -7469,7 +7479,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.29", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", @@ -7477,36 +7487,35 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", + "http-body 1.0.1", + "hyper 1.4.1", "pin-project-lite", "socket2 0.5.7", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows 0.48.0", + "windows-core 0.52.0", ] [[package]] @@ -7571,7 +7580,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "core-foundation", "fnv", "futures", @@ -7594,8 +7603,8 @@ dependencies = [ "attohttpc", "bytes", "futures", - "http 0.2.9", - "hyper 0.14.29", + "http 0.2.12", + "hyper 0.14.30", "log", "rand", "tokio", @@ -7676,27 +7685,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "include_dir" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", ] @@ -7719,12 +7728,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -7735,9 +7744,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -7799,7 +7808,7 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -7827,30 +7836,36 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", - "rustix 0.38.21", - "windows-sys 0.48.0", + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", ] [[package]] name = "is_executable" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" dependencies = [ "winapi", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "isahc" version = "1.7.2" @@ -7865,7 +7880,7 @@ dependencies = [ "encoding_rs", "event-listener 2.5.3", "futures-lite 1.13.0", - "http 0.2.9", + "http 0.2.12", "log", "mime", "once_cell", @@ -7905,11 +7920,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jemalloc_pprof" @@ -7959,9 +7983,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -8032,16 +8056,16 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" +checksum = "02f01f48e04e0d7da72280ab787c9943695699c9b32b99158ece105e8ad0afea" dependencies = [ - "jsonrpsee-core 0.24.3", - "jsonrpsee-http-client 0.24.3", + "jsonrpsee-core 0.24.6", + "jsonrpsee-http-client 0.24.6", "jsonrpsee-proc-macros", "jsonrpsee-server", - "jsonrpsee-types 0.24.3", - "jsonrpsee-ws-client 0.24.3", + "jsonrpsee-types 0.24.6", + "jsonrpsee-ws-client 0.24.6", "tokio", "tracing", ] @@ -8053,10 +8077,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" dependencies = [ "futures-util", - "http 0.2.9", + "http 0.2.12", "jsonrpsee-core 0.22.5", "pin-project", - "rustls-native-certs 0.7.0", + "rustls-native-certs 0.7.3", "rustls-pki-types", "soketto 0.7.1", "thiserror", @@ -8078,7 +8102,7 @@ dependencies = [ "http 1.1.0", "jsonrpsee-core 0.23.2", "pin-project", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", @@ -8092,16 +8116,16 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" +checksum = "d80eccbd47a7b9f1e67663fd846928e941cb49c65236e297dd11c9ea3c5e3387" dependencies = [ "base64 0.22.1", "futures-util", "http 1.1.0", - "jsonrpsee-core 0.24.3", + "jsonrpsee-core 0.24.6", "pin-project", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "rustls-platform-verifier", "soketto 0.8.0", @@ -8124,7 +8148,7 @@ dependencies = [ "beef", "futures-timer", "futures-util", - "hyper 0.14.29", + "hyper 0.14.30", "jsonrpsee-types 0.22.5", "pin-project", "rustc-hash 1.1.0", @@ -8160,18 +8184,18 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" +checksum = "3c2709a32915d816a6e8f625bf72cf74523ebe5d8829f895d6b041b1d3137818" dependencies = [ "async-trait", "bytes", "futures-timer", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "jsonrpsee-types 0.24.3", + "jsonrpsee-types 0.24.6", "parking_lot 0.12.3", "pin-project", "rand", @@ -8191,7 +8215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", - "hyper 0.14.29", + "hyper 0.14.30", "hyper-rustls 0.24.2", "jsonrpsee-core 0.22.5", "jsonrpsee-types 0.22.5", @@ -8206,19 +8230,19 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" +checksum = "cc54db939002b030e794fbfc9d5a925aa2854889c5a2f0352b0bffa54681707e" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.0", - "hyper 1.3.1", - "hyper-rustls 0.27.2", + "http-body 1.0.1", + "hyper 1.4.1", + "hyper-rustls 0.27.3", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", - "rustls 0.23.10", + "jsonrpsee-core 0.24.6", + "jsonrpsee-types 0.24.6", + "rustls 0.23.14", "rustls-platform-verifier", "serde", "serde_json", @@ -8231,31 +8255,31 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" +checksum = "3a9a4b2eaba8cc928f49c4ccf4fcfa65b690a73997682da99ed08f3393b51f07" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "jsonrpsee-server" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +checksum = "e30110d0f2d7866c8cc6c86483bdab2eb9f4d2f0e20db55518b2bca84651ba8e" dependencies = [ "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-core 0.24.6", + "jsonrpsee-types 0.24.6", "pin-project", "route-recognizer", "serde", @@ -8297,9 +8321,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +checksum = "1ca331cd7b3fe95b33432825c2d4c9f5a43963e207fdc01ae67f9fd80ab0930f" dependencies = [ "http 1.1.0", "serde", @@ -8322,14 +8346,14 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.3" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" +checksum = "755ca3da1c67671f1fae01cd1a47f41dfb2233a8f19a643e587ab0a663942044" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport 0.24.3", - "jsonrpsee-core 0.24.3", - "jsonrpsee-types 0.24.3", + "jsonrpsee-client-transport 0.24.6", + "jsonrpsee-core 0.24.6", + "jsonrpsee-types 0.24.6", "url", ] @@ -8363,9 +8387,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -8428,9 +8452,9 @@ dependencies = [ "either", "futures", "home", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.29", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-rustls 0.24.2", "hyper-timeout", "jsonpath-rust", @@ -8439,8 +8463,8 @@ dependencies = [ "pem 3.0.4", "pin-project", "rand", - "rustls 0.21.7", - "rustls-pemfile 1.0.3", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "secrecy", "serde", "serde_json", @@ -8462,7 +8486,7 @@ checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae" dependencies = [ "chrono", "form_urlencoded", - "http 0.2.9", + "http 0.2.12", "json-patch", "k8s-openapi", "once_cell", @@ -8550,9 +8574,9 @@ dependencies = [ [[package]] name = "landlock" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc" +checksum = "9baa9eeb6e315942429397e617a190f4fdc696ef1ee0342939d641029cbb4ea7" dependencies = [ "enumflags2", "libc", @@ -8579,9 +8603,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libflate" @@ -8616,12 +8640,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.52.6", ] [[package]] @@ -8632,9 +8656,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libnghttp2-sys" -version = "0.1.9+1.58.0" +version = "0.1.10+1.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b57e858af2798e167e709b9d969325b6d8e9d50232fcbc494d7d54f976854a64" +checksum = "959c25552127d2e1fa72f0e52548ec04fc386e827ba71a7bd01db46a447dc135" dependencies = [ "cc", "libc", @@ -8671,7 +8695,7 @@ dependencies = [ "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "pin-project", "rw-stream-sink", "thiserror", @@ -8714,7 +8738,7 @@ dependencies = [ "instant", "libp2p-identity", "log", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "multihash 0.19.1", "multistream-select", "once_cell", @@ -8760,7 +8784,7 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "lru 0.12.3", + "lru 0.12.5", "quick-protobuf 0.8.1", "quick-protobuf-codec", "smallvec", @@ -8792,7 +8816,7 @@ version = "0.44.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16ea178dabba6dde6ffc260a8e0452ccdc8f79becf544946692fff9d412fc29d" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "asynchronous-codec", "bytes", "either", @@ -8865,7 +8889,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "log", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "multihash 0.19.1", "once_cell", "quick-protobuf 0.8.1", @@ -8914,7 +8938,7 @@ dependencies = [ "quinn 0.10.2", "rand", "ring 0.16.20", - "rustls 0.21.7", + "rustls 0.21.12", "socket2 0.5.7", "thiserror", "tokio", @@ -8969,7 +8993,7 @@ checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" dependencies = [ "heck 0.4.1", "proc-macro-warning 0.4.2", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -9003,8 +9027,8 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.16.20", - "rustls 0.21.7", - "rustls-webpki 0.101.4", + "rustls 0.21.12", + "rustls-webpki 0.101.7", "thiserror", "x509-parser 0.15.1", "yasna", @@ -9058,7 +9082,7 @@ dependencies = [ "soketto 0.8.0", "thiserror", "url", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", ] [[package]] @@ -9074,6 +9098,17 @@ dependencies = [ "yamux", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.5.7", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -9116,7 +9151,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -9139,9 +9174,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -9175,9 +9210,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" +checksum = "a9eda9dcf4f2a99787827661f312ac3219292549c2ee992bf9a6248ffb066bf7" dependencies = [ "nalgebra", ] @@ -9196,9 +9231,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lioness" @@ -9245,7 +9280,7 @@ dependencies = [ "futures-timer", "hex-literal", "hickory-resolver", - "indexmap 2.2.3", + "indexmap 2.6.0", "libc", "mockall 0.13.0", "multiaddr 0.17.1", @@ -9255,7 +9290,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "prost 0.12.6", - "prost-build 0.13.2", + "prost-build 0.13.3", "rand", "rcgen", "ring 0.16.20", @@ -9290,9 +9325,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -9310,17 +9345,17 @@ dependencies = [ [[package]] name = "lru" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" +checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -9334,19 +9369,18 @@ dependencies = [ [[package]] name = "lz4" -version = "1.24.0" +version = "1.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "4d1febb2b4a79ddd1980eede06a8f7902197960aa0383ffcfdd62fe723036725" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -9361,15 +9395,6 @@ dependencies = [ "libc", ] -[[package]] -name = "mach2" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" -dependencies = [ - "libc", -] - [[package]] name = "macro_magic" version = "0.5.1" @@ -9391,7 +9416,7 @@ dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -9402,7 +9427,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -9469,9 +9494,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", "rawpointer", @@ -9485,11 +9510,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.37.23", + "rustix 0.38.37", ] [[package]] @@ -9503,9 +9528,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -9519,15 +9544,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-db" version = "0.32.0" @@ -9587,6 +9603,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -9597,11 +9623,11 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "docify", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "minimal-template-runtime", "polkadot-sdk", "serde_json", @@ -9620,13 +9646,22 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.2" @@ -9646,7 +9681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", @@ -9659,7 +9694,7 @@ dependencies = [ "rand", "rand_chacha", "rand_distr", - "subtle 2.5.0", + "subtle 2.6.1", "thiserror", "zeroize", ] @@ -9691,7 +9726,7 @@ dependencies = [ name = "mmr-rpc" version = "28.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "serde", "serde_json", @@ -9727,7 +9762,7 @@ dependencies = [ "downcast", "fragile", "mockall_derive 0.13.0", - "predicates 3.0.3", + "predicates 3.1.2", "predicates-tree", ] @@ -9738,7 +9773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -9750,7 +9785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -9782,9 +9817,9 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" dependencies = [ "arrayref", "byteorder", @@ -9795,7 +9830,7 @@ dependencies = [ "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.7.2", + "unsigned-varint 0.8.0", "url", ] @@ -9843,7 +9878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ "blake2b_simd 1.0.2", - "blake2s_simd 1.0.1", + "blake2s_simd 1.0.2", "blake3", "core2", "digest 0.10.7", @@ -9860,7 +9895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd8a792c1694c6da4f68db0a9d707c72bd260994da179e6030a5dcee00bb815" dependencies = [ "blake2b_simd 1.0.2", - "blake2s_simd 1.0.1", + "blake2s_simd 1.0.2", "blake3", "core2", "digest 0.10.7", @@ -9882,13 +9917,13 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 1.1.3", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", "synstructure 0.12.6", @@ -9896,9 +9931,9 @@ dependencies = [ [[package]] name = "multimap" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" [[package]] name = "multistream-select" @@ -9916,13 +9951,12 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.3" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +checksum = "3c4b5f057b303842cf3262c27e465f4c303572e7f6b0648f60e16248ac3397f4" dependencies = [ "approx", "matrixmultiply", - "nalgebra-macros", "num-complex", "num-rational", "num-traits", @@ -9930,17 +9964,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "nalgebra-macros" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" -dependencies = [ - "proc-macro2 1.0.86", - "quote 1.0.37", - "syn 1.0.109", -] - [[package]] name = "names" version = "0.14.0" @@ -10029,9 +10052,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" dependencies = [ "bytes", "futures", @@ -10042,9 +10065,9 @@ dependencies = [ [[package]] name = "network-interface" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae72fd9dbd7f55dda80c00d66acc3b2130436fcba9ea89118fc508eaae48dfb0" +checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" dependencies = [ "cc", "libc", @@ -10065,14 +10088,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -10115,7 +10137,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.5.13", + "clap 4.5.20", "derive_more", "fs_extra", "futures", @@ -10157,7 +10179,7 @@ dependencies = [ name = "node-rpc" version = "3.0.0-dev" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "mmr-rpc", "node-primitives", "pallet-transaction-payment-rpc", @@ -10191,7 +10213,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "generate-bags", "kitchensink-runtime", ] @@ -10200,7 +10222,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "flate2", "fs_extra", "glob", @@ -10310,9 +10332,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -10324,20 +10346,19 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] @@ -10354,7 +10375,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -10365,25 +10386,24 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "itoa", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -10392,11 +10412,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -10404,9 +10423,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -10460,9 +10479,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.1" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -10478,24 +10497,24 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "opaque-debug" @@ -10505,15 +10524,15 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -10530,7 +10549,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -10543,9 +10562,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -10583,11 +10602,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7b1d40dd8f367db3c65bec8d3dd47d4a604ee8874480738f93191bddab4e0e0" dependencies = [ "expander", - "indexmap 2.2.3", + "indexmap 2.6.0", "itertools 0.11.0", "petgraph", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -10603,9 +10622,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "overload" @@ -11256,7 +11275,7 @@ dependencies = [ "parity-wasm", "sp-runtime 31.0.1", "tempfile", - "toml 0.8.12", + "toml 0.8.19", "twox-hash", ] @@ -11301,7 +11320,7 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -12384,7 +12403,7 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "tempfile", - "toml 0.8.12", + "toml 0.8.19", ] [[package]] @@ -12427,7 +12446,7 @@ dependencies = [ name = "pallet-revive-proc-macro" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -12670,8 +12689,8 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "sp-runtime 31.0.1", "syn 2.0.79", @@ -12822,7 +12841,7 @@ dependencies = [ name = "pallet-transaction-payment-rpc" version = "30.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "sp-api 26.0.0", @@ -13067,7 +13086,7 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -13082,7 +13101,7 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "pallet-transaction-payment-rpc", "parachain-template-runtime", @@ -13264,7 +13283,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand", "rand_core 0.6.4", "serde", @@ -13279,9 +13298,9 @@ checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" [[package]] name = "parity-db" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" +checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" dependencies = [ "blake2 0.10.6", "crc32fast", @@ -13295,6 +13314,7 @@ dependencies = [ "rand", "siphasher 0.3.11", "snap", + "winapi", ] [[package]] @@ -13303,7 +13323,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "bitvec", "byte-slice-cast", "bytes", @@ -13318,8 +13338,8 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -13354,7 +13374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.8", + "parking_lot_core 0.9.10", ] [[package]] @@ -13373,15 +13393,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", + "redox_syscall 0.5.7", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -13398,7 +13418,7 @@ checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -13725,19 +13745,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.2" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.2" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -13745,22 +13766,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.2" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "pest_meta" -version = "2.7.2" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -13769,30 +13790,30 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.3", + "indexmap 2.6.0", ] [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -13809,6 +13830,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.1.1", + "futures-io", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -13821,21 +13853,21 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "platforms" -version = "3.0.2" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "0e4c7666f2019727f9e8e14bf14456e99c707d780922869f1ba473eee101fa49" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -13846,15 +13878,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -14015,7 +14047,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.13", + "clap 4.5.20", "frame-benchmarking-cli", "futures", "log", @@ -14091,7 +14123,7 @@ dependencies = [ "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.6.0", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -14687,7 +14719,7 @@ dependencies = [ "futures", "futures-timer", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", "log", "parity-scale-codec", @@ -14871,7 +14903,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "async-trait", - "clap 4.5.13", + "clap 4.5.20", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -14892,7 +14924,7 @@ dependencies = [ "frame-try-runtime", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "nix 0.28.0", "pallet-transaction-payment", @@ -15057,7 +15089,7 @@ dependencies = [ name = "polkadot-rpc" version = "7.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "mmr-rpc", "pallet-transaction-payment-rpc", "polkadot-primitives", @@ -15836,14 +15868,14 @@ dependencies = [ name = "polkadot-statement-distribution" version = "7.0.0" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "assert_matches", "async-channel 1.9.0", "bitvec", "fatality", "futures", "futures-timer", - "indexmap 2.2.3", + "indexmap 2.6.0", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -15885,7 +15917,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.13", + "clap 4.5.20", "clap-num", "color-eyre", "colored", @@ -15987,7 +16019,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.13", + "clap 4.5.20", "color-eyre", "futures", "futures-timer", @@ -16129,7 +16161,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "generate-bags", "sp-io 30.0.0", "westend-runtime", @@ -16140,7 +16172,7 @@ name = "polkadot-zombienet-sdk-tests" version = "0.1.0" dependencies = [ "anyhow", - "env_logger 0.11.3", + "env_logger 0.11.5", "log", "parity-scale-codec", "serde", @@ -16257,7 +16289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c10b2654a8a10a83c260bfb93e97b262cf0017494ab94a65d389e0eda6de6c9c" dependencies = [ "polkavm-common 0.8.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -16269,7 +16301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common 0.9.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -16281,7 +16313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d179eddaaef62ce5960faaa2ec9e8f131c81661c8b9365c4d55b275011688534" dependencies = [ "polkavm-common 0.12.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -16322,7 +16354,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ - "gimli 0.28.0", + "gimli 0.28.1", "hashbrown 0.14.5", "log", "object 0.32.2", @@ -16337,10 +16369,10 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f917b16db9ab13819a738a321b48a2d0d20d9e32dedcff75054148676afbec4" dependencies = [ - "gimli 0.28.0", + "gimli 0.28.1", "hashbrown 0.14.5", "log", - "object 0.36.1", + "object 0.36.5", "polkavm-common 0.12.0", "regalloc2 0.9.3", "rustc-demangle", @@ -16376,16 +16408,17 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.21", + "rustix 0.38.37", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -16395,27 +16428,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "polyval" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.4.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "portpicker" @@ -16443,7 +16476,7 @@ dependencies = [ "findshlibs", "libc", "log", - "nix 0.26.2", + "nix 0.26.4", "once_cell", "parking_lot 0.12.3", "smallvec", @@ -16467,9 +16500,12 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -16487,27 +16523,26 @@ dependencies = [ [[package]] name = "predicates" -version = "3.0.3" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "difflib", - "itertools 0.10.5", "predicates-core", ] [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -16515,9 +16550,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -16525,11 +16560,11 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.12" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "syn 2.0.79", ] @@ -16580,21 +16615,21 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "thiserror", + "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.0", + "toml_edit 0.22.22", ] [[package]] @@ -16604,7 +16639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", "version_check", @@ -16616,35 +16651,29 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro-warning" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "proc-macro-warning" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" +checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -16660,9 +16689,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -16679,7 +16708,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.21", + "rustix 0.38.37", ] [[package]] @@ -16695,9 +16724,9 @@ dependencies = [ [[package]] name = "prometheus" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" dependencies = [ "cfg-if", "fnv", @@ -16725,28 +16754,28 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "prometheus-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2aa5feb83bf4b2c8919eaf563f51dbab41183de73ba2353c0e03cd7b6bd892" +checksum = "811031bea65e5a401fb2e1f37d802cca6601e204ac463809a3189352d13b78a5" dependencies = [ "chrono", - "itertools 0.10.5", + "itertools 0.12.1", "once_cell", "regex", ] [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ "bit-set", "bit-vec", @@ -16756,7 +16785,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -16784,19 +16813,19 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", - "prost-derive 0.13.2", + "prost-derive 0.13.3", ] [[package]] name = "prost-build" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", "heck 0.5.0", @@ -16807,7 +16836,7 @@ dependencies = [ "petgraph", "prettyplease", "prost 0.12.6", - "prost-types 0.12.4", + "prost-types 0.12.6", "regex", "syn 2.0.79", "tempfile", @@ -16815,20 +16844,20 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.12.1", + "itertools 0.13.0", "log", "multimap", "once_cell", "petgraph", "prettyplease", - "prost 0.13.2", - "prost-types 0.13.2", + "prost 0.13.3", + "prost-types 0.13.3", "regex", "syn 2.0.79", "tempfile", @@ -16842,7 +16871,7 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -16855,47 +16884,47 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "prost-derive" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.12.1", - "proc-macro2 1.0.86", + "itertools 0.13.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "prost-types" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ "prost 0.12.6", ] [[package]] name = "prost-types" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ - "prost 0.13.2", + "prost 0.13.3", ] [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -16912,7 +16941,7 @@ dependencies = [ "log", "names", "prost 0.11.9", - "reqwest 0.11.20", + "reqwest 0.11.27", "thiserror", "url", "winapi", @@ -16932,13 +16961,12 @@ dependencies = [ [[package]] name = "quanta" -version = "0.11.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ "crossbeam-utils", "libc", - "mach2", "once_cell", "raw-cpuid", "wasi", @@ -17017,7 +17045,7 @@ dependencies = [ "quinn-proto 0.10.6", "quinn-udp 0.4.1", "rustc-hash 1.1.0", - "rustls 0.21.7", + "rustls 0.21.12", "thiserror", "tokio", "tracing", @@ -17032,9 +17060,9 @@ dependencies = [ "bytes", "pin-project-lite", "quinn-proto 0.11.8", - "quinn-udp 0.5.4", + "quinn-udp 0.5.5", "rustc-hash 2.0.0", - "rustls 0.23.10", + "rustls 0.23.14", "socket2 0.5.7", "thiserror", "tokio", @@ -17051,7 +17079,7 @@ dependencies = [ "rand", "ring 0.16.20", "rustc-hash 1.1.0", - "rustls 0.21.7", + "rustls 0.21.12", "slab", "thiserror", "tinyvec", @@ -17066,9 +17094,9 @@ checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring 0.17.7", + "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.10", + "rustls 0.23.14", "slab", "thiserror", "tinyvec", @@ -17090,15 +17118,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -17116,7 +17144,7 @@ version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", ] [[package]] @@ -17191,11 +17219,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.7.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] @@ -17283,30 +17311,21 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -17337,7 +17356,7 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -17369,14 +17388,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.2", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -17390,19 +17409,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" - -[[package]] -name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.5", ] [[package]] @@ -17413,15 +17426,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "relay-substrate-client" @@ -17436,7 +17449,7 @@ dependencies = [ "finality-relay", "frame-support", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "num-traits", "pallet-transaction-payment", @@ -17493,7 +17506,7 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "frame-system", "log", "pallet-bags-list-remote-tests", @@ -17506,9 +17519,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", @@ -17516,9 +17529,9 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.29", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-rustls 0.24.2", "hyper-tls", "ipnet", @@ -17529,11 +17542,13 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.7", - "rustls-pemfile 1.0.3", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", @@ -17542,15 +17557,15 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.2", - "winreg 0.50.0", + "webpki-roots 0.25.4", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -17558,10 +17573,10 @@ dependencies = [ "futures-core", "futures-util", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", - "hyper 1.3.1", - "hyper-rustls 0.27.2", + "hyper 1.4.1", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "js-sys", @@ -17571,13 +17586,13 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn 0.11.5", - "rustls 0.23.10", - "rustls-pemfile 2.0.0", + "rustls 0.23.14", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "tokio", "tokio-rustls 0.26.0", "tower-service", @@ -17585,8 +17600,8 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.3", - "winreg 0.52.0", + "webpki-roots 0.26.6", + "windows-registry", ] [[package]] @@ -17606,7 +17621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -17619,7 +17634,7 @@ dependencies = [ "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "blake2 0.10.6", "common", "fflonk", @@ -17643,16 +17658,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -17914,13 +17930,13 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -17932,7 +17948,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -17943,11 +17959,11 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "regex", "relative-path", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "syn 2.0.79", "unicode-ident", ] @@ -17969,12 +17985,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -18009,9 +18025,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -18051,11 +18067,11 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.18", + "semver 1.0.23", ] [[package]] @@ -18069,9 +18085,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.15" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -18083,9 +18099,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.23" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", @@ -18097,15 +18113,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", ] [[package]] @@ -18121,13 +18137,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.16.20", - "rustls-webpki 0.101.4", + "ring 0.17.8", + "rustls-webpki 0.101.7", "sct", ] @@ -18138,25 +18154,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", - "subtle 2.5.0", + "rustls-webpki 0.102.8", + "subtle 2.6.1", "zeroize", ] [[package]] name = "rustls" -version = "0.23.10" +version = "0.23.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" dependencies = [ "log", "once_cell", - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.4", - "subtle 2.5.0", + "rustls-webpki 0.102.8", + "subtle 2.6.1", "zeroize", ] @@ -18167,19 +18183,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.3", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] [[package]] name = "rustls-native-certs" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.0.0", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -18187,73 +18203,72 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] [[package]] name = "rustls-pemfile" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.21.7", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.10", - "rustls-native-certs 0.7.0", + "rustls 0.23.14", + "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", - "rustls-webpki 0.102.4", + "rustls-webpki 0.102.8", "security-framework", "security-framework-sys", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", "winapi", ] [[package]] name = "rustls-platform-verifier-android" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", ] @@ -18311,9 +18326,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "safe-mix" @@ -18326,9 +18341,9 @@ dependencies = [ [[package]] name = "safe_arch" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" dependencies = [ "bytemuck", ] @@ -18360,7 +18375,7 @@ checksum = "a3f01218e73ea57916be5f08987995ac802d6f4ede4ea5ce0242e468c590e4e2" dependencies = [ "log", "sp-core 33.0.1", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "thiserror", ] @@ -18378,7 +18393,7 @@ dependencies = [ "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build 0.12.6", "quickcheck", "rand", "sc-client-api", @@ -18442,10 +18457,10 @@ name = "sc-chain-spec" version = "28.0.0" dependencies = [ "array-bytes", - "clap 4.5.13", + "clap 4.5.20", "docify", "log", - "memmap2 0.9.3", + "memmap2 0.9.5", "parity-scale-codec", "regex", "sc-chain-spec-derive", @@ -18473,8 +18488,8 @@ dependencies = [ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -18485,7 +18500,7 @@ version = "0.36.0" dependencies = [ "array-bytes", "chrono", - "clap 4.5.13", + "clap 4.5.20", "fdlimit", "futures", "futures-timer", @@ -18693,7 +18708,7 @@ name = "sc-consensus-babe-rpc" version = "0.34.0" dependencies = [ "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "sc-consensus", "sc-consensus-babe", "sc-consensus-epochs", @@ -18765,7 +18780,7 @@ name = "sc-consensus-beefy-rpc" version = "13.0.0" dependencies = [ "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -18850,7 +18865,7 @@ version = "0.19.0" dependencies = [ "finality-grandpa", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "sc-block-builder", @@ -18876,7 +18891,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "sc-basic-authorship", @@ -19012,7 +19027,7 @@ dependencies = [ "sp-runtime-interface 27.0.0", "sp-trie 35.0.0", "sp-version 35.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "tracing", ] @@ -19037,7 +19052,7 @@ dependencies = [ "polkavm 0.9.3", "sc-allocator 28.0.0", "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "thiserror", "wasm-instrument", ] @@ -19061,7 +19076,7 @@ dependencies = [ "log", "polkavm 0.9.3", "sc-executor-common 0.34.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", ] [[package]] @@ -19076,7 +19091,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "rustix 0.36.15", + "rustix 0.36.17", "sc-allocator 23.0.0", "sc-executor-common 0.29.0", "sc-runtime-test", @@ -19099,11 +19114,11 @@ dependencies = [ "libc", "log", "parking_lot 0.12.3", - "rustix 0.36.15", + "rustix 0.36.17", "sc-allocator 28.0.0", "sc-executor-common 0.34.0", "sp-runtime-interface 27.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "wasmtime", ] @@ -19142,14 +19157,14 @@ name = "sc-mixnet" version = "0.4.0" dependencies = [ "array-bytes", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "blake2 0.10.6", "bytes", "futures", "futures-timer", "log", "mixnet", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "parity-scale-codec", "parking_lot 0.12.3", "sc-client-api", @@ -19193,7 +19208,7 @@ dependencies = [ "partial_sort", "pin-project", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build 0.12.6", "rand", "sc-block-builder", "sc-client-api", @@ -19238,7 +19253,7 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build 0.12.4", + "prost-build 0.12.6", "sc-consensus", "sc-network-types", "sp-consensus", @@ -19280,7 +19295,7 @@ dependencies = [ "log", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build 0.12.6", "sc-client-api", "sc-network", "sc-network-types", @@ -19323,7 +19338,7 @@ dependencies = [ "mockall 0.11.4", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build 0.12.6", "quickcheck", "sc-block-builder", "sc-client-api", @@ -19407,7 +19422,7 @@ dependencies = [ "libp2p-identity", "litep2p", "log", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "multihash 0.19.1", "quickcheck", "rand", @@ -19425,7 +19440,7 @@ dependencies = [ "fnv", "futures", "futures-timer", - "hyper 0.14.29", + "hyper 0.14.30", "hyper-rustls 0.24.2", "log", "num_cpus", @@ -19470,7 +19485,7 @@ version = "29.0.0" dependencies = [ "assert_matches", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19508,7 +19523,7 @@ dependencies = [ name = "sc-rpc-api" version = "0.33.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -19533,9 +19548,9 @@ dependencies = [ "governor", "http 1.1.0", "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "ip_network", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "sc-rpc-api", "serde", @@ -19555,7 +19570,7 @@ dependencies = [ "futures", "futures-util", "hex", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19609,7 +19624,7 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -19735,7 +19750,7 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "fs4", "log", "sp-core 28.0.0", @@ -19747,7 +19762,7 @@ dependencies = [ name = "sc-sync-state-rpc" version = "0.34.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "sc-chain-spec", "sc-client-api", @@ -19834,8 +19849,8 @@ dependencies = [ name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -19938,7 +19953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb22f574168103cdd3133b19281639ca65ad985e24612728f727339dcaf4021" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -19965,8 +19980,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82ab7e60e2d9c8d47105f44527b26f04418e5e624ffc034f6b4a86c0ba19c5bf" dependencies = [ "darling 0.14.4", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.86", + "proc-macro-crate 1.1.3", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -19991,8 +20006,8 @@ version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -20013,7 +20028,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498d1aecf2ea61325d4511787c115791639c0fd21ef4f8e11e49dd09eff2bbac" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "scale-info", "syn 2.0.79", @@ -20022,9 +20037,9 @@ dependencies = [ [[package]] name = "scale-value" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4d772cfb7569e03868400344a1695d16560bf62b86b918604773607d39ec84" +checksum = "8cd6ab090d823e75cfdb258aad5fe92e13f2af7d04b43a55d607d25fcc38c811" dependencies = [ "base58", "blake2 0.10.6", @@ -20043,18 +20058,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "schemars" -version = "0.8.13" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" dependencies = [ "dyn-clone", "schemars_derive", @@ -20064,14 +20079,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.13" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] @@ -20092,7 +20107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "curve25519-dalek-ng", "merlin", "rand_core 0.6.4", @@ -20109,14 +20124,14 @@ checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" dependencies = [ "aead", "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.6", "curve25519-dalek 4.1.3", "getrandom_or_panic", "merlin", "rand_core 0.6.4", "serde_bytes", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -20140,12 +20155,12 @@ checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -20159,7 +20174,7 @@ dependencies = [ "generic-array 0.14.7", "pkcs8", "serdect", - "subtle 2.5.0", + "subtle 2.6.1", "zeroize", ] @@ -20202,9 +20217,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -20216,9 +20231,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -20253,9 +20268,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] @@ -20317,9 +20332,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] @@ -20330,20 +20345,20 @@ version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] @@ -20361,7 +20376,7 @@ version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -20370,9 +20385,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -20395,7 +20410,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -20432,7 +20447,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -20447,7 +20462,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -20471,7 +20486,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -20494,7 +20509,7 @@ dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", "keccak", - "opaque-debug 0.3.0", + "opaque-debug 0.3.1", ] [[package]] @@ -20509,9 +20524,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -20522,30 +20537,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -20553,9 +20558,9 @@ dependencies = [ [[package]] name = "simba" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" dependencies = [ "approx", "num-complex", @@ -20623,9 +20628,9 @@ dependencies = [ [[package]] name = "slotmap" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" dependencies = [ "version_check", ] @@ -20658,8 +20663,8 @@ dependencies = [ "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-net 1.7.0", - "async-process 1.7.0", + "async-net 1.8.0", + "async-process 1.8.1", "blocking", "futures-lite 1.13.0", ] @@ -20670,10 +20675,10 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.3.0", + "async-channel 2.3.1", "async-executor", "async-fs 2.1.2", - "async-io 2.3.3", + "async-io 2.3.4", "async-lock 3.4.0", "async-net 2.0.0", "async-process 2.3.0", @@ -20681,22 +20686,13 @@ dependencies = [ "futures-lite 2.3.0", ] -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - [[package]] name = "smoldot" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "async-lock 2.8.0", "atomic-take", "base64 0.21.7", @@ -20750,7 +20746,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "async-lock 3.4.0", "atomic-take", "base64 0.21.7", @@ -20820,7 +20816,7 @@ dependencies = [ "hex", "itertools 0.11.0", "log", - "lru 0.11.0", + "lru 0.11.1", "no-std-net", "parking_lot 0.12.3", "pin-project", @@ -20841,7 +20837,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" dependencies = [ - "async-channel 2.3.0", + "async-channel 2.3.1", "async-lock 3.4.0", "base64 0.21.7", "blake2-rfc", @@ -20856,7 +20852,7 @@ dependencies = [ "hex", "itertools 0.12.1", "log", - "lru 0.12.3", + "lru 0.12.5", "no-std-net", "parking_lot 0.12.3", "pin-project", @@ -20873,9 +20869,9 @@ dependencies = [ [[package]] name = "snap" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snow" @@ -20888,10 +20884,10 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.1.3", "rand_core 0.6.4", - "ring 0.17.7", - "rustc_version 0.4.0", + "ring 0.17.8", + "rustc_version 0.4.1", "sha2 0.10.8", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -20955,8 +20951,8 @@ name = "snowbridge-ethereum" version = "0.3.0" dependencies = [ "ethabi-decode", - "ethbloom", - "ethereum-types", + "ethbloom 0.14.1", + "ethereum-types 0.15.1", "hex-literal", "parity-bytes", "parity-scale-codec", @@ -21217,9 +21213,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -21270,12 +21266,12 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "frame-benchmarking-cli", "frame-metadata-hash-extension", "frame-system", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "sc-basic-authorship", @@ -21402,8 +21398,8 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -21417,8 +21413,8 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -21575,7 +21571,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-bls12-381-ext", - "sp-crypto-ec-utils 0.4.1", + "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -21584,7 +21580,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils 0.4.1", + "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -21958,8 +21954,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" -version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "0.10.0" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -21972,14 +21967,14 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.11", - "sp-runtime-interface 17.0.0", - "sp-std 8.0.0", + "ark-scale", + "sp-runtime-interface 24.0.0", ] [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -21992,8 +21987,8 @@ dependencies = [ "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.12", - "sp-runtime-interface 24.0.0", + "ark-scale", + "sp-runtime-interface 24.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -22054,10 +22049,9 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "14.0.0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -22065,8 +22059,10 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -22074,32 +22070,30 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "sp-externalities" -version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "0.25.0" dependencies = [ "environmental", "parity-scale-codec", - "sp-std 8.0.0", - "sp-storage 13.0.0", + "sp-storage 19.0.0", ] [[package]] name = "sp-externalities" version = "0.25.0" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 19.0.0", + "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -22222,7 +22216,7 @@ dependencies = [ "sp-runtime-interface 27.0.0", "sp-state-machine 0.40.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-tracing 17.0.0", + "sp-tracing 17.0.1", "sp-trie 34.0.0", "tracing", "tracing-core", @@ -22249,7 +22243,7 @@ dependencies = [ "sp-runtime-interface 27.0.0", "sp-state-machine 0.41.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-tracing 17.0.0", + "sp-tracing 17.0.1", "sp-trie 35.0.0", "tracing", "tracing-core", @@ -22395,7 +22389,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "honggfuzz", "rand", "sp-npos-elections", @@ -22549,24 +22543,6 @@ dependencies = [ "sp-weights 31.0.0", ] -[[package]] -name = "sp-runtime-interface" -version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "primitive-types 0.12.2", - "sp-externalities 0.19.0", - "sp-runtime-interface-proc-macro 11.0.0", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-tracing 10.0.0", - "sp-wasm-interface 14.0.0", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "24.0.0" @@ -22591,6 +22567,25 @@ dependencies = [ "trybuild", ] +[[package]] +name = "sp-runtime-interface" +version = "24.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "primitive-types 0.13.1", + "sp-externalities 0.25.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-runtime-interface-proc-macro 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-wasm-interface 20.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "static_assertions", +] + [[package]] name = "sp-runtime-interface" version = "26.0.0" @@ -22626,19 +22621,19 @@ dependencies = [ "sp-runtime-interface-proc-macro 18.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-storage 21.0.0", - "sp-tracing 17.0.0", - "sp-wasm-interface 21.0.0", + "sp-tracing 17.0.1", + "sp-wasm-interface 21.0.1", "static_assertions", ] [[package]] name = "sp-runtime-interface-proc-macro" -version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "17.0.0" dependencies = [ "Inflector", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.86", + "expander", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -22646,11 +22641,12 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -22663,8 +22659,8 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -22845,41 +22841,40 @@ dependencies = [ [[package]] name = "sp-std" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "14.0.0" [[package]] name = "sp-std" version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" [[package]] name = "sp-std" version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" [[package]] name = "sp-storage" -version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "19.0.0" dependencies = [ "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 8.0.0", - "sp-std 8.0.0", + "sp-debug-derive 14.0.0", ] [[package]] name = "sp-storage" version = "19.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 14.0.0", + "sp-debug-derive 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", ] [[package]] @@ -22934,49 +22929,48 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "16.0.0" dependencies = [ "parity-scale-codec", - "sp-std 8.0.0", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.18", ] [[package]] name = "sp-tracing" version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0351810b9d074df71c4514c5228ed05c250607cba131c1c9d1526760ab69c05c" dependencies = [ "parity-scale-codec", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tracing", "tracing-core", - "tracing-subscriber 0.3.18", + "tracing-subscriber 0.2.25", ] [[package]] name = "sp-tracing" version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0351810b9d074df71c4514c5228ed05c250607cba131c1c9d1526760ab69c05c" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "parity-scale-codec", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.18", ] [[package]] name = "sp-tracing" -version = "17.0.0" +version = "17.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b3decf116db9f1dfaf1f1597096b043d0e12c952d3bcdc018c6d6b77deec7e" +checksum = "cf641a1d17268c8fcfdb8e0fa51a79c2d4222f4cfda5f3944dbdbc384dced8d5" dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber 0.2.25", + "tracing-subscriber 0.3.18", ] [[package]] @@ -23138,8 +23132,8 @@ name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro-warning 1.0.0", - "proc-macro2 1.0.86", + "proc-macro-warning 1.0.2", + "proc-macro2 1.0.87", "quote 1.0.37", "sp-version 29.0.0", "syn 2.0.79", @@ -23152,54 +23146,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aee8f6730641a65fcf0c8f9b1e448af4b3bb083d08058b47528188bccc7b7a7" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "sp-wasm-interface" -version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +version = "20.0.0" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 8.0.0", "wasmtime", ] [[package]] name = "sp-wasm-interface" version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef97172c42eb4c6c26506f325f48463e9bc29b2034a587f1b9e48c751229bee" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmtime", ] [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef97172c42eb4c6c26506f325f48463e9bc29b2034a587f1b9e48c751229bee" +source = "git+https://github.com/paritytech/polkadot-sdk#d1c115b6197bf6c45d5640594f0432e6c2781a4f" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", - "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmtime", ] [[package]] name = "sp-wasm-interface" -version = "21.0.0" +version = "21.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b04b919e150b4736d85089d49327eab65507deb1485eec929af69daa2278eb3" +checksum = "b066baa6d57951600b14ffe1243f54c47f9c23dd89c262e17ca00ae8dca58be9" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -23276,11 +23268,20 @@ dependencies = [ "strum 0.24.1", ] +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -23288,17 +23289,17 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.43.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" +checksum = "19409f13998e55816d1c728395af0b52ec066206341d939e22e7766df9b494b8" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "serde", "serde_json", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] @@ -23319,7 +23320,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -23334,7 +23335,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "log", "sc-chain-spec", "serde", @@ -23349,11 +23350,11 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.5.13", + "clap 4.5.20", "clap_complete", "criterion", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "kitchensink-runtime", "log", "nix 0.28.0", @@ -23384,7 +23385,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -23514,7 +23515,7 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases 0.1.1", "memchr", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -23567,7 +23568,7 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", ] @@ -23581,12 +23582,6 @@ dependencies = [ "strum_macros 0.24.3", ] -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "strum" version = "0.26.3" @@ -23603,25 +23598,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "rustversion", "syn 1.0.109", ] -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.86", - "quote 1.0.37", - "rustversion", - "syn 2.0.79", -] - [[package]] name = "strum_macros" version = "0.26.4" @@ -23629,7 +23611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "rustversion", "syn 2.0.79", @@ -23639,7 +23621,7 @@ dependencies = [ name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "sc-cli", ] @@ -23737,7 +23719,7 @@ version = "29.0.0" dependencies = [ "frame-support", "frame-system", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "sc-rpc-api", "scale-info", @@ -23756,7 +23738,7 @@ dependencies = [ "docify", "frame-system-rpc-runtime-api", "futures", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "parity-scale-codec", "sc-rpc-api", @@ -23777,7 +23759,7 @@ name = "substrate-prometheus-endpoint" version = "0.17.0" dependencies = [ "http-body-util", - "hyper 1.3.1", + "hyper 1.4.1", "hyper-util", "log", "prometheus", @@ -23833,7 +23815,7 @@ name = "substrate-rpc-client" version = "0.33.0" dependencies = [ "async-trait", - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "log", "sc-rpc-api", "serde", @@ -23854,7 +23836,7 @@ dependencies = [ "sp-core 32.0.0", "sp-io 35.0.0", "sp-runtime 36.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "thiserror", ] @@ -23862,7 +23844,7 @@ dependencies = [ name = "substrate-state-trie-migration-rpc" version = "27.0.0" dependencies = [ - "jsonrpsee 0.24.3", + "jsonrpsee 0.24.6", "parity-scale-codec", "sc-client-api", "sc-rpc-api", @@ -24019,7 +24001,7 @@ dependencies = [ "sp-version 29.0.0", "strum 0.26.3", "tempfile", - "toml 0.8.12", + "toml 0.8.19", "walkdir", "wasm-opt", ] @@ -24032,9 +24014,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "subtle-ng" @@ -24054,9 +24036,9 @@ dependencies = [ "log", "num-format", "rand", - "reqwest 0.12.5", + "reqwest 0.12.8", "scale-info", - "semver 1.0.18", + "semver 1.0.23", "serde", "serde_json", "sp-version 35.0.0", @@ -24115,7 +24097,7 @@ dependencies = [ "hex", "jsonrpsee 0.22.5", "parity-scale-codec", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "scale-info", "scale-typegen", @@ -24223,15 +24205,15 @@ dependencies = [ [[package]] name = "sval" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1" +checksum = "eaf38d1fa2ce984086ea42fb856a9f374d94680a4f796831a7fc868d7f2af1b9" [[package]] name = "sval_buffer" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028" +checksum = "81682ff859964ca1d7cf3d3d0f9ec7204ea04c2c32acb8cc2cf68ecbd3127354" dependencies = [ "sval", "sval_ref", @@ -24239,18 +24221,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf" +checksum = "2a213b93bb4c6f4c9f9b17f2e740e077fd18746bbf7c80c72bbadcac68fa7ee4" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326" +checksum = "6902c6d3fb52c89206fe0dc93546c0123f7d48b5997fd14e61c9e64ff0b63275" dependencies = [ "itoa", "ryu", @@ -24259,55 +24241,65 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d" +checksum = "11a28041ea78cdc394b930ae6b897d36246dc240a29a6edf82d76562487fb0b4" dependencies = [ "itoa", "ryu", "sval", ] +[[package]] +name = "sval_nested" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850346e4b0742a7f2fd2697d703ff80084d0b658f0f2e336d71b8a06abf9b68e" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + [[package]] name = "sval_ref" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c" +checksum = "824afd97a8919f28a35b0fdea979845cc2ae461a8a3aaa129455cb89c88bb77a" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.6.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046" +checksum = "8ada7520dd719ed672c786c7db7de4f5230f4d504b0821bd8305cd30ca442315" dependencies = [ "serde", "sval", - "sval_buffer", - "sval_fmt", + "sval_nested", ] [[package]] name = "symbolic-common" -version = "12.3.0" +version = "12.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167a4ffd7c35c143fd1030aa3c2caf76ba42220bd5a6b5f4781896434723b8c3" +checksum = "366f1b4c6baf6cfefc234bbd4899535fca0b06c74443039a73f6dfb2fad88d77" dependencies = [ "debugid", - "memmap2 0.5.10", + "memmap2 0.9.5", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "12.3.0" +version = "12.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e378c50e80686c1c5c205674e1f86a2858bec3d2a7dfdd690331a8a19330f293" +checksum = "aba05ba5b9962ea5617baf556293720a8b2d0a282aa14ee4bf10e22efc7da8c8" dependencies = [ - "cpp_demangle 0.4.3", + "cpp_demangle 0.4.4", "rustc-demangle", "symbolic-common", ] @@ -24329,7 +24321,7 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "unicode-ident", ] @@ -24340,7 +24332,7 @@ version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "unicode-ident", ] @@ -24352,16 +24344,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -24369,10 +24370,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid 0.2.6", ] [[package]] @@ -24381,16 +24382,16 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "sysinfo" -version = "0.30.5" +version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" dependencies = [ "cfg-if", "core-foundation-sys", @@ -24430,9 +24431,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -24441,21 +24442,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.11" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", - "fastrand 2.1.0", - "redox_syscall 0.4.1", - "rustix 0.38.21", - "windows-sys 0.48.0", + "fastrand 2.1.1", + "once_cell", + "rustix 0.38.37", + "windows-sys 0.59.0", ] [[package]] @@ -24463,7 +24464,7 @@ name = "template-zombienet-tests" version = "0.0.0" dependencies = [ "anyhow", - "env_logger 0.11.3", + "env_logger 0.11.5", "log", "tokio", "zombienet-sdk", @@ -24471,21 +24472,21 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ - "rustix 0.38.21", - "windows-sys 0.48.0", + "rustix 0.38.37", + "windows-sys 0.59.0", ] [[package]] @@ -24500,7 +24501,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" dependencies = [ - "env_logger 0.11.3", + "env_logger 0.11.5", "test-log-macros", "tracing-subscriber 0.3.18", ] @@ -24511,7 +24512,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -24532,7 +24533,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "futures", "futures-timer", "log", @@ -24579,7 +24580,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.13", + "clap 4.5.20", "futures", "futures-timer", "log", @@ -24647,46 +24648,46 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-core" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" +checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" dependencies = [ "thiserror-core-impl", ] [[package]] name = "thiserror-core-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" +checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -24699,9 +24700,9 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -24801,9 +24802,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -24848,7 +24849,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -24880,7 +24881,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.7", + "rustls 0.21.12", "tokio", ] @@ -24901,7 +24902,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "tokio", ] @@ -24920,9 +24921,9 @@ dependencies = [ [[package]] name = "tokio-test" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ "async-stream", "bytes", @@ -24939,7 +24940,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.7", + "rustls 0.21.12", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -24948,9 +24949,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -24984,21 +24985,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.22", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -25009,35 +25010,24 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.15", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.3", - "toml_datetime", - "winnow 0.5.15", -] - -[[package]] -name = "toml_edit" -version = "0.22.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" -dependencies = [ - "indexmap 2.2.3", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] [[package]] @@ -25068,8 +25058,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 0.2.9", - "http-body 0.4.5", + "http 0.2.12", + "http-body 0.4.6", "http-range-header", "mime", "pin-project-lite", @@ -25087,7 +25077,7 @@ dependencies = [ "bitflags 2.6.0", "bytes", "http 1.1.0", - "http-body 1.0.0", + "http-body 1.0.1", "http-body-util", "pin-project-lite", "tower-layer", @@ -25096,15 +25086,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -25124,7 +25114,7 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -25165,20 +25155,20 @@ version = "5.0.0" dependencies = [ "assert_matches", "expander", - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.86", + "proc-macro-crate 3.2.0", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -25221,7 +25211,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.1.3", + "tracing-log 0.1.4", "tracing-serde", ] @@ -25324,7 +25314,7 @@ dependencies = [ "lazy_static", "rand", "smallvec", - "socket2 0.4.9", + "socket2 0.4.10", "thiserror", "tinyvec", "tokio", @@ -25341,7 +25331,7 @@ dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner 0.6.0", + "enum-as-inner 0.6.1", "futures-channel", "futures-io", "futures-util", @@ -25380,24 +25370,23 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.89" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" +checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" dependencies = [ - "basic-toml", "dissimilar", "glob", - "once_cell", "serde", "serde_derive", "serde_json", "termcolor", + "toml 0.8.19", ] [[package]] @@ -25415,11 +25404,11 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.9", + "http 0.2.12", "httparse", "log", "rand", - "rustls 0.21.7", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -25440,7 +25429,7 @@ dependencies = [ "log", "rand", "rustls 0.22.4", - "rustls-native-certs 0.7.0", + "rustls-native-certs 0.7.3", "rustls-pki-types", "sha1", "thiserror", @@ -25466,17 +25455,23 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "uint" @@ -25510,15 +25505,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" @@ -25531,15 +25526,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" @@ -25549,9 +25544,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -25560,7 +25555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.5.0", + "subtle 2.6.1", ] [[package]] @@ -25625,12 +25620,12 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.10", + "rustls 0.23.14", "rustls-pki-types", "serde", "serde_json", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.6", ] [[package]] @@ -25653,15 +25648,15 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", ] @@ -25674,9 +25669,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec26a25bd6fca441cdd0f769fd7f891bae119f996de31f86a5eddccef54c1d" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -25684,9 +25679,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ead5b693d906686203f19a49e88c477fb8c15798b68cf72f60b4b5521b4ad891" +checksum = "ccacf50c5cb077a9abb723c5bcb5e0754c1a433f1e1de89edc328e2760b6328b" dependencies = [ "erased-serde", "serde", @@ -25695,9 +25690,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9d0f4a816370c3a0d7d82d603b62198af17675b12fe5e91de6b47ceb505882" +checksum = "1785bae486022dfb9703915d42287dcb284c1ee37bd1080eeba78cc04721285b" dependencies = [ "sval", "sval_buffer", @@ -25722,9 +25717,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -25734,9 +25729,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "w3f-bls" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" +checksum = "9c5da5fa2c6afa2c9158eaa7cd9aee249765eb32b5fb0c63ad8b9e79336a47ec" dependencies = [ "ark-bls12-377", "ark-bls12-381", @@ -25767,9 +25762,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -25796,11 +25791,20 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasix" +version = "0.12.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d" +dependencies = [ + "wasi", +] + [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -25811,14 +25815,14 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", "wasm-bindgen-shared", @@ -25826,9 +25830,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -25838,9 +25842,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote 1.0.37", "wasm-bindgen-macro-support", @@ -25848,11 +25852,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", "wasm-bindgen-backend", @@ -25861,18 +25865,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-bindgen-test" -version = "0.3.37" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" +checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -25881,21 +25886,23 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.37" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" +checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", + "syn 2.0.79", ] [[package]] name = "wasm-encoder" -version = "0.31.1" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" +checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" dependencies = [ "leb128", + "wasmparser 0.219.1", ] [[package]] @@ -25928,9 +25935,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.116.0" +version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" dependencies = [ "anyhow", "libc", @@ -25983,7 +25990,7 @@ dependencies = [ "sp-runtime 37.0.0", "sp-state-machine 0.41.0", "sp-version 35.0.0", - "sp-wasm-interface 21.0.0", + "sp-wasm-interface 21.0.1", "substrate-runtime-proposal-hash", "thiserror", "wasm-loader", @@ -26023,7 +26030,7 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50386c99b9c32bd2ed71a55b6dd4040af2580530fae8bdb9a6576571a80d0cca" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.6", "multi-stash", "num-derive", "num-traits", @@ -26085,6 +26092,16 @@ dependencies = [ "url", ] +[[package]] +name = "wasmparser" +version = "0.219.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" +dependencies = [ + "bitflags 2.6.0", + "indexmap 2.6.0", +] + [[package]] name = "wasmparser-nostd" version = "0.100.2" @@ -26113,7 +26130,7 @@ dependencies = [ "rayon", "serde", "target-lexicon", - "wasmparser", + "wasmparser 0.102.0", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -26143,7 +26160,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.15", + "rustix 0.36.17", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -26168,7 +26185,7 @@ dependencies = [ "object 0.30.4", "target-lexicon", "thiserror", - "wasmparser", + "wasmparser 0.102.0", "wasmtime-cranelift-shared", "wasmtime-environ", ] @@ -26203,7 +26220,7 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser", + "wasmparser 0.102.0", "wasmtime-types", ] @@ -26239,7 +26256,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.15", + "rustix 0.36.17", ] [[package]] @@ -26267,10 +26284,10 @@ dependencies = [ "log", "mach", "memfd", - "memoffset 0.8.0", + "memoffset", "paste", "rand", - "rustix 0.36.15", + "rustix 0.36.17", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -26286,15 +26303,16 @@ dependencies = [ "cranelift-entity", "serde", "thiserror", - "wasmparser", + "wasmparser 0.102.0", ] [[package]] name = "wast" -version = "63.0.0" +version = "219.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" +checksum = "4f79a9d9df79986a68689a6b40bcc8d5d40d807487b235bebc2ac69a242b54a1" dependencies = [ + "bumpalo", "leb128", "memchr", "unicode-width", @@ -26303,18 +26321,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.70" +version = "1.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" +checksum = "8bc3cf014fb336883a411cd662f987abf6a1d2a27f2f0008616a0070bbf6bd0d" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -26326,21 +26344,21 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -26508,9 +26526,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.11" +version = "0.7.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" dependencies = [ "bytemuck", "safe_arch", @@ -26518,9 +26536,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "winapi" @@ -26540,11 +26558,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] @@ -26553,15 +26571,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows" version = "0.51.1" @@ -26579,7 +26588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core 0.52.0", - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -26597,7 +26606,37 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -26624,7 +26663,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -26659,17 +26707,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -26686,9 +26735,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -26704,9 +26753,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -26722,9 +26771,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -26740,9 +26795,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -26758,9 +26813,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -26776,9 +26831,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -26794,24 +26849,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -26826,16 +26881,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "wyz" version = "0.5.1" @@ -26847,9 +26892,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek 4.1.3", "rand_core 0.6.4", @@ -26880,12 +26925,12 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs 0.6.1", + "asn1-rs 0.6.2", "data-encoding", "der-parser 9.0.0", "lazy_static", "nom", - "oid-registry 0.7.0", + "oid-registry 0.7.1", "rusticata-macros", "thiserror", "time", @@ -26893,11 +26938,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys 0.4.14", + "rustix 0.38.37", ] [[package]] @@ -26985,7 +27032,7 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "staging-xcm", "syn 2.0.79", @@ -27093,9 +27140,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "xmltree" @@ -27123,9 +27170,9 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yap" @@ -27144,20 +27191,21 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -27177,7 +27225,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.86", + "proc-macro2 1.0.87", "quote 1.0.37", "syn 2.0.79", ] @@ -27188,7 +27236,7 @@ version = "1.0.0" dependencies = [ "futures-util", "parity-scale-codec", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -27206,9 +27254,9 @@ checksum = "ebbfc98adb25076777967f7aad078e74029e129b102eb0812c425432f8c2be7b" dependencies = [ "anyhow", "lazy_static", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "thiserror", @@ -27231,10 +27279,10 @@ dependencies = [ "hex", "libp2p", "libsecp256k1", - "multiaddr 0.18.1", + "multiaddr 0.18.2", "rand", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "sha2 0.10.8", @@ -27277,7 +27325,7 @@ dependencies = [ "kube", "nix 0.27.1", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "serde", "serde_json", "serde_yaml", @@ -27322,7 +27370,7 @@ dependencies = [ "nix 0.27.1", "rand", "regex", - "reqwest 0.11.20", + "reqwest 0.11.27", "thiserror", "tokio", "tracing", @@ -27369,11 +27417,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index a25085a180369..fea16c7cf6545 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -42,6 +42,7 @@ use frame_system::RawOrigin; const SEED: u32 = 0; const MAX_SPANS: u32 = 100; const MAX_SLASHES: u32 = 1000; +const SINGLE_PAGE: u32 = 0; type MaxValidators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxValidators; type MaxNominators = <::BenchmarkingConfig as BenchmarkingConfig>::MaxNominators; @@ -827,7 +828,7 @@ benchmarks! { let num_voters = (v + n) as usize; }: { // default bounds are unbounded. - let voters = >::get_npos_voters(DataProviderBounds::default()); + let voters = >::get_npos_voters(DataProviderBounds::default(), SINGLE_PAGE); assert_eq!(voters.len(), num_voters); } @@ -842,7 +843,7 @@ benchmarks! { )?; }: { // default bounds are unbounded. - let targets = >::get_npos_targets(DataProviderBounds::default()); + let targets = >::get_npos_targets(DataProviderBounds::default(), SINGLE_PAGE); assert_eq!(targets.len() as u32, v); } diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 19d999109d8dd..bf8417d1ac74d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -309,6 +309,7 @@ extern crate alloc; use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; +use frame_election_provider_support::ElectionProvider; use frame_support::{ defensive, defensive_assert, traits::{ @@ -347,9 +348,14 @@ macro_rules! log { }; } -/// Maximum number of winners (aka. active validators), as defined in the election provider of this -/// pallet. -pub type MaxWinnersOf = <::ElectionProvider as frame_election_provider_support::ElectionProviderBase>::MaxWinners; +/// Alias fo the maximum number of winners (aka. active validators), as defined in by this pallet's +/// config. +pub type MaxWinnersOf = ::MaxValidatorSet; + +/// Maximum number of exposures (validators) that each page of [`Config::ElectionProvider`] might +/// might return. +pub type MaxExposuresPerPageOf = + <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage; /// Maximum number of nominations per nominator. pub type MaxNominationsOf = @@ -382,6 +388,13 @@ pub struct ActiveEraInfo { pub start: Option, } +/// Pointer to the last iterated indices for targets and voters used when generating the snapshot. +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub(crate) struct LastIteratedStakers { + voter: AccountId, + target: AccountId, +} + /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. @@ -440,6 +453,23 @@ pub struct UnlockChunk { era: EraIndex, } +/// Status of a paged snapshot progress. +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub enum SnapshotStatus { + /// Paged snapshot is in progress, the `AccountId` was the last staker iterated. + Ongoing(AccountId), + /// All the stakers in the system have been consumed since the snapshot started. + Consumed, + /// Waiting for a new snapshot to be requested. + Waiting, +} + +impl Default for SnapshotStatus { + fn default() -> Self { + Self::Waiting + } +} + /// The ledger of a (bonded) stash. /// /// Note: All the reads and mutations to the [`Ledger`], [`Bonded`] and [`Payee`] storage items @@ -1237,9 +1267,21 @@ impl EraInfo { let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); - >::insert(era, &validator, &exposure_metadata); - exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| { - >::insert((era, &validator, page as Page), &paged_exposure); + // insert or update validator's overview. + let append_from = ErasStakersOverview::::mutate(era, &validator, |stored| { + if let Some(stored_overview) = stored { + let append_from = stored_overview.page_count; + *stored = Some(stored_overview.merge(exposure_metadata)); + append_from + } else { + *stored = Some(exposure_metadata); + Zero::zero() + } + }); + + exposure_pages.iter().enumerate().for_each(|(idx, paged_exposure)| { + let append_at = (append_from + idx as u32) as Page; + >::insert((era, &validator, append_at), &paged_exposure); }); } @@ -1247,6 +1289,12 @@ impl EraInfo { pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { >::insert(era, total_stake); } + + pub(crate) fn add_total_stake(era: EraIndex, stake: BalanceOf) { + >::mutate(era, |total_stake| { + *total_stake += stake; + }); + } } /// Configurations of the benchmarking of the pallet. diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4a0209fc5b083..e9a761a59a81b 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -20,7 +20,7 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, - onchain, SequentialPhragmen, VoteWeight, + onchain, BoundedSupports, SequentialPhragmen, Support, TryIntoBoundedSupports, VoteWeight, }; use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, @@ -38,8 +38,9 @@ use sp_staking::{ OnStakingUpdate, }; -pub const INIT_TIMESTAMP: u64 = 30_000; -pub const BLOCK_TIME: u64 = 1000; +pub(crate) const INIT_TIMESTAMP: u64 = 30_000; +pub(crate) const BLOCK_TIME: u64 = 1000; +pub(crate) const SINGLE_PAGE: u32 = 0; /// The AccountId alias in this test module. pub(crate) type AccountId = u64; @@ -204,7 +205,7 @@ parameter_types! { pub static MaxExposurePageSize: u32 = 64; pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; - pub static MaxWinners: u32 = 100; + pub static MaxValidatorSet: u32 = 100; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static AbsoluteMaxNominations: u32 = 16; } @@ -225,8 +226,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = MaxWinners; type Bounds = ElectionsBounds; + type MaxBackersPerWinner = ConstU32<{ u32::MAX }>; + type MaxWinnersPerPage = ConstU32<{ u32::MAX }>; } pub struct MockReward {} @@ -274,6 +276,7 @@ impl crate::pallet::pallet::Config for Test { type EraPayout = ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = MaxExposurePageSize; + type MaxValidatorSet = MaxValidatorSet; type ElectionProvider = onchain::OnChainExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. @@ -419,6 +422,10 @@ impl ExtBuilder { self.stakers.push((stash, ctrl, stake, status)); self } + pub fn exposures_page_size(self, max: u32) -> Self { + MaxExposurePageSize::set(max); + self + } pub fn balance_factor(mut self, factor: Balance) -> Self { self.balance_factor = factor; self @@ -928,3 +935,13 @@ pub(crate) fn staking_events_since_last_call() -> Vec> { pub(crate) fn balances(who: &AccountId) -> (Balance, Balance) { (Balances::free_balance(who), Balances::reserved_balance(who)) } + +pub(crate) fn to_bounded_supports( + supports: Vec<(AccountId, Support)>, +) -> BoundedSupports< + AccountId, + <::ElectionProvider as ElectionProvider>::MaxBackersPerWinner, + <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage, +> { + supports.try_into_bounded_supports().unwrap() +} diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 6c4fe8140e8ef..b6892c5676801 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -17,10 +17,14 @@ //! Implementations for the Staking FRAME Pallet. +// TODO: remove +#![allow(dead_code)] + use frame_election_provider_support::{ bounds::{CountBound, SizeBound}, data_provider, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, - ScoreProvider, SortedListProvider, VoteWeight, VoterOf, + LockableElectionDataProvider, PageIndex, ScoreProvider, SortedListProvider, VoteWeight, + VoterOf, }; use frame_support::{ defensive, @@ -52,8 +56,9 @@ use sp_staking::{ use crate::{ asset, election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, - LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, Nominations, NominationsQuota, - PositiveImbalanceOf, RewardDestination, SessionInterface, StakingLedger, ValidatorPrefs, + LedgerIntegrityState, MaxExposuresPerPageOf, MaxNominationsOf, MaxWinnersOf, Nominations, + NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, SnapshotStatus, + StakingLedger, ValidatorPrefs, }; use alloc::{boxed::Box, vec, vec::Vec}; @@ -480,6 +485,10 @@ impl Pallet { Self::set_force_era(Forcing::NotForcing); } + //TODO: we may want to keep track of the past 1/N era's stashes + // reset electable stashes. + ElectableStashes::::kill(); + maybe_new_era_validators } else { // Set initial era. @@ -616,9 +625,9 @@ impl Pallet { start_session_index: SessionIndex, exposures: BoundedVec< (T::AccountId, Exposure>), - MaxWinnersOf, + MaxExposuresPerPageOf, >, - ) -> BoundedVec> { + ) -> BoundedVec> { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { *s = Some(s.map(|s| s + 1).unwrap_or(0)); @@ -635,6 +644,20 @@ impl Pallet { Self::store_stakers_info(exposures, new_planned_era) } + pub fn trigger_new_era_paged(start_session_index: SessionIndex) { + // Increment or set current era. + let new_planned_era = CurrentEra::::mutate(|s| { + *s = Some(s.map(|s| s + 1).unwrap_or(0)); + s.unwrap() + }); + ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); + + // Clean old era information. + if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { + Self::clear_era_information(old_era); + } + } + /// Potentially plan a new era. /// /// Get election result from `T::ElectionProvider`. @@ -645,28 +668,29 @@ impl Pallet { start_session_index: SessionIndex, is_genesis: bool, ) -> Option>> { - let election_result: BoundedVec<_, MaxWinnersOf> = if is_genesis { - let result = ::elect().map_err(|e| { + let validators: BoundedVec> = if is_genesis { + // genesis election only use the lsp of the election result. + let result = ::elect(Zero::zero()).map_err(|e| { log!(warn, "genesis election provider failed due to {:?}", e); Self::deposit_event(Event::StakingElectionFailed); }); - result - .ok()? - .into_inner() - .try_into() - // both bounds checked in integrity test to be equal - .defensive_unwrap_or_default() + let (_, planned_era) = ElectingStartedAt::::get().unwrap_or_default(); + let exposures = Self::collect_exposures(result.ok().unwrap_or_default()); + Self::store_stakers_info_paged(exposures.clone(), planned_era); + + exposures + .into_iter() + .map(|(validator, _)| validator) + .try_collect() + .unwrap_or_default() } else { - let result = ::elect().map_err(|e| { - log!(warn, "election provider failed due to {:?}", e); - Self::deposit_event(Event::StakingElectionFailed); - }); - result.ok()? + ElectableStashes::::get() }; - let exposures = Self::collect_exposures(election_result); - if (exposures.len() as u32) < Self::minimum_validator_count().max(1) { + log!(info, "electable validators for session {:?}: {:?}", start_session_index, validators); + + if (validators.len() as u32) < Self::minimum_validator_count().max(1) { // Session will panic if we ever return an empty validator set, thus max(1) ^^. match CurrentEra::::get() { Some(current_era) if current_era > 0 => log!( @@ -674,7 +698,7 @@ impl Pallet { "chain does not have enough staking candidates to operate for era {:?} ({} \ elected, minimum is {})", CurrentEra::::get().unwrap_or(0), - exposures.len(), + validators.len(), Self::minimum_validator_count(), ), None => { @@ -685,7 +709,7 @@ impl Pallet { CurrentEra::::put(0); ErasStartSessionIndex::::insert(&0, &start_session_index); }, - _ => (), + _ => {}, } Self::deposit_event(Event::StakingElectionFailed); @@ -693,7 +717,82 @@ impl Pallet { } Self::deposit_event(Event::StakersElected); - Some(Self::trigger_new_era(start_session_index, exposures)) + Self::trigger_new_era_paged(start_session_index); + Some(validators) + } + + /// Paginated elect. + /// + /// TODO: rust-docs + pub(crate) fn do_elect_paged(page: PageIndex) { + let paged_result = match ::elect(page) { + Ok(result) => result, + Err(e) => { + log!(warn, "electiong provider page failed due to {:?} (page: {})", e, page); + // TODO: be resilient here, not all pages need to be submitted successfuly for an + // election to be OK, provided that the election score is good enough. + Self::deposit_event(Event::StakingElectionFailed); + return + }, + }; + + let new_planned_era = CurrentEra::::get().unwrap_or_default().saturating_add(1); + let stashes = + Self::store_stakers_info_paged(Self::collect_exposures(paged_result), new_planned_era); + + ElectableStashes::::mutate(|v| { + // TODO: be even more defensive and handle potential error? (should not happen if page + // bounds and T::MaxValidatorSet configs are in sync). + let _ = (*v).try_extend(stashes.into_iter()).defensive(); + }); + } + + /// Process the output of a paged election. + /// + /// Store staking information for the new planned era + pub fn store_stakers_info_paged( + exposures: BoundedVec< + (T::AccountId, Exposure>), + MaxExposuresPerPageOf, + >, + new_planned_era: EraIndex, + ) -> BoundedVec> { + // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. + let mut total_stake: BalanceOf = Zero::zero(); + let mut elected_stashes = Vec::with_capacity(exposures.len()); + + exposures.into_iter().for_each(|(stash, exposure)| { + // build elected stash + elected_stashes.push(stash.clone()); + // accumulate total stake + total_stake = total_stake.saturating_add(exposure.total); + // store staker exposure for this era + EraInfo::::set_exposure(new_planned_era, &stash, exposure); + }); + + // TODO: correct?? + let elected_stashes: BoundedVec<_, MaxExposuresPerPageOf> = elected_stashes + .try_into() + .expect("elected_stashes.len() always equal to exposures.len(); qed"); + + EraInfo::::add_total_stake(new_planned_era, total_stake); + + // Collect the pref of all winners. + for stash in &elected_stashes { + let pref = Self::validators(stash); + >::insert(&new_planned_era, stash, pref); + } + + if new_planned_era > 0 { + log!( + info, + "updated validator set (current size {:?}) for era {:?}", + elected_stashes.len(), + new_planned_era, + ); + } + + elected_stashes } /// Process the output of the election. @@ -702,10 +801,10 @@ impl Pallet { pub fn store_stakers_info( exposures: BoundedVec< (T::AccountId, Exposure>), - MaxWinnersOf, + MaxExposuresPerPageOf, >, new_planned_era: EraIndex, - ) -> BoundedVec> { + ) -> BoundedVec> { // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. let mut total_stake: BalanceOf = Zero::zero(); let mut elected_stashes = Vec::with_capacity(exposures.len()); @@ -719,7 +818,7 @@ impl Pallet { EraInfo::::set_exposure(new_planned_era, &stash, exposure); }); - let elected_stashes: BoundedVec<_, MaxWinnersOf> = elected_stashes + let elected_stashes: BoundedVec<_, MaxExposuresPerPageOf> = elected_stashes .try_into() .expect("elected_stashes.len() always equal to exposures.len(); qed"); @@ -747,7 +846,8 @@ impl Pallet { /// [`Exposure`]. fn collect_exposures( supports: BoundedSupportsOf, - ) -> BoundedVec<(T::AccountId, Exposure>), MaxWinnersOf> { + ) -> BoundedVec<(T::AccountId, Exposure>), MaxExposuresPerPageOf> + { let total_issuance = asset::total_issuance::(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -891,7 +991,10 @@ impl Pallet { /// nominators. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_voters(bounds: DataProviderBounds) -> Vec> { + pub fn get_npos_voters( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> Vec> { let mut voters_size_tracker: StaticTracker = StaticTracker::default(); let final_predicted_len = { @@ -909,7 +1012,16 @@ impl Pallet { let mut nominators_taken = 0u32; let mut min_active_stake = u64::MAX; - let mut sorted_voters = T::VoterList::iter(); + let mut sorted_voters = match VoterSnapshotStatus::::get() { + // snapshot continues, start from last iterated voter in the list. + SnapshotStatus::Ongoing(start_at) => + T::VoterList::iter_from(&start_at).unwrap_or_else(|_| T::TargetList::iter()), + // all the voters have been consumed, return an empty iterator. + SnapshotStatus::Consumed => Box::new(vec![].into_iter()), + // start the snapshot processing, start from the beginning. + SnapshotStatus::Waiting => T::VoterList::iter(), + }; + while all_voters.len() < final_predicted_len as usize && voters_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -982,6 +1094,21 @@ impl Pallet { } } + match (remaining_pages, VoterSnapshotStatus::::get()) { + // last page requested, reset. + (0, _) => VoterSnapshotStatus::::set(SnapshotStatus::Waiting), + // all voters have been consumed, do nothing. + (_, SnapshotStatus::Consumed) => {}, + (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { + if let Some(last) = all_voters.last().map(|(x, _, _)| x).cloned() { + VoterSnapshotStatus::::set(SnapshotStatus::Ongoing(last)); + } else { + // no more to consume, next pages will be empty. + VoterSnapshotStatus::::set(SnapshotStatus::Consumed); + } + }, + }; + // all_voters should have not re-allocated. debug_assert!(all_voters.capacity() == final_predicted_len as usize); @@ -1006,7 +1133,10 @@ impl Pallet { /// Get the targets for an upcoming npos election. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets(bounds: DataProviderBounds) -> Vec { + pub fn get_npos_targets( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> Vec { let mut targets_size_tracker: StaticTracker = StaticTracker::default(); let final_predicted_len = { @@ -1017,7 +1147,16 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - let mut targets_iter = T::TargetList::iter(); + let mut targets_iter = match TargetSnapshotStatus::::get() { + // snapshot continues, start from last iterated target in the list. + SnapshotStatus::Ongoing(start_at) => + T::TargetList::iter_from(&start_at).unwrap_or_else(|_| T::TargetList::iter()), + // all the targets have been consumed, return an empty iterator. + SnapshotStatus::Consumed => Box::new(vec![].into_iter()), + // start the snapshot processing, start from the beginning. + SnapshotStatus::Waiting => T::TargetList::iter(), + }; + while all_targets.len() < final_predicted_len as usize && targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -1042,6 +1181,21 @@ impl Pallet { } } + match (remaining_pages, TargetSnapshotStatus::::get()) { + // last page requested, reset. + (0, _) => TargetSnapshotStatus::::set(SnapshotStatus::Waiting), + // all targets have been consumed, do nothing. + (_, SnapshotStatus::Consumed) => {}, + (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { + if let Some(last) = all_targets.last().cloned() { + TargetSnapshotStatus::::set(SnapshotStatus::Ongoing(last)); + } else { + // no more to consume, next pages will be empty. + TargetSnapshotStatus::::set(SnapshotStatus::Consumed); + } + }, + }; + Self::register_weight(T::WeightInfo::get_npos_targets(all_targets.len() as u32)); log!(info, "generated {} npos targets", all_targets.len()); @@ -1187,6 +1341,23 @@ impl Pallet { } } +// TODO(gpestana): add unit tests. +impl LockableElectionDataProvider for Pallet { + fn set_lock() -> data_provider::Result<()> { + match ElectionDataLock::::get() { + Some(_) => Err("lock already set"), + None => { + ElectionDataLock::::set(Some(())); + Ok(()) + }, + } + } + + fn unlock() { + ElectionDataLock::::set(None); + } +} + impl ElectionDataProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; @@ -1197,9 +1368,11 @@ impl ElectionDataProvider for Pallet { Ok(Self::validator_count()) } - fn electing_voters(bounds: DataProviderBounds) -> data_provider::Result>> { - // This can never fail -- if `maybe_max_len` is `Some(_)` we handle it. - let voters = Self::get_npos_voters(bounds); + fn electing_voters( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> data_provider::Result>> { + let voters = Self::get_npos_voters(bounds, remaining_pages); debug_assert!(!bounds.exhausted( SizeBound(voters.encoded_size() as u32).into(), @@ -1209,12 +1382,14 @@ impl ElectionDataProvider for Pallet { Ok(voters) } - fn electable_targets(bounds: DataProviderBounds) -> data_provider::Result> { - let targets = Self::get_npos_targets(bounds); - + fn electable_targets( + bounds: DataProviderBounds, + remaining: PageIndex, + ) -> data_provider::Result> { + let targets = Self::get_npos_targets(bounds, remaining); // We can't handle this case yet -- return an error. WIP to improve handling this case in // . - if bounds.exhausted(None, CountBound(T::TargetList::count() as u32).into()) { + if bounds.exhausted(None, CountBound(targets.len() as u32).into()) { return Err("Target snapshot too big") } @@ -1276,7 +1451,7 @@ impl ElectionDataProvider for Pallet { #[cfg(feature = "runtime-benchmarks")] fn add_target(target: T::AccountId) { - let stake = MinValidatorBond::::get() * 100u32.into(); + let stake = (MinValidatorBond::::get() + 1u32.into()) * 100u32.into(); >::insert(target.clone(), target.clone()); >::insert(target.clone(), StakingLedger::::new(target.clone(), stake)); Self::do_add_validator( @@ -1329,6 +1504,11 @@ impl ElectionDataProvider for Pallet { ); }); } + + #[cfg(feature = "runtime-benchmarks")] + fn set_desired_targets(count: u32) { + ValidatorCount::::put(count); + } } /// In this implementation `new_session(session)` must be called before `end_session(session-1)` @@ -1836,7 +2016,9 @@ impl StakingInterface for Pallet { } fn election_ongoing() -> bool { - T::ElectionProvider::ongoing() + // TODO(gpestana) + //T::ElectionProvider::ongoing() + false } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { @@ -2071,11 +2253,6 @@ impl Pallet { ::TargetList::count() == Validators::::count(), "wrong external count" ); - ensure!( - ValidatorCount::::get() <= - ::MaxWinners::get(), - Error::::TooManyValidators - ); Ok(()) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 28aa4f89b6227..f03b110c64db2 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -19,9 +19,7 @@ use alloc::vec::Vec; use codec::Codec; -use frame_election_provider_support::{ - ElectionProvider, ElectionProviderBase, SortedListProvider, VoteWeight, -}; +use frame_election_provider_support::{ElectionProvider, SortedListProvider, VoteWeight}; use frame_support::{ pallet_prelude::*, traits::{ @@ -33,8 +31,8 @@ use frame_support::{ }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ - traits::{SaturatedConversion, StaticLookup, Zero}, - ArithmeticError, Perbill, Percent, + traits::{One, SaturatedConversion, StaticLookup, Zero}, + ArithmeticError, Perbill, Percent, Saturating, }; use sp_staking::{ @@ -62,12 +60,11 @@ pub(crate) const SPECULATIVE_NUM_SPANS: u32 = 32; #[frame_support::pallet] pub mod pallet { - use frame_election_provider_support::ElectionDataProvider; - - use crate::{BenchmarkingConfig, PagedExposureMetadata}; - use super::*; + use crate::{BenchmarkingConfig, PagedExposureMetadata, SnapshotStatus}; + use frame_election_provider_support::{ElectionDataProvider, PageIndex}; + /// The in-code storage version. const STORAGE_VERSION: StorageVersion = StorageVersion::new(15); @@ -136,6 +133,9 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = BlockNumberFor, DataProvider = Pallet, + Pages = ConstU32<1>, + MaxWinnersPerPage = ::MaxWinnersPerPage, + MaxBackersPerWinner = ::MaxBackersPerWinner, >; /// Something that defines the maximum number of nominations per nominator. @@ -232,6 +232,11 @@ pub mod pallet { #[pallet::constant] type MaxExposurePageSize: Get; + /// The absolute maximum of next winner validators this pallet should return. + #[pallet::constant] + #[pallet::no_default] + type MaxValidatorSet: Get; + /// Something that provides a best-effort sorted list of voters aka electing nominators, /// used for NPoS election. /// @@ -735,6 +740,43 @@ pub mod pallet { #[pallet::storage] pub(crate) type ChillThreshold = StorageValue<_, Percent, OptionQuery>; + /// Voter snapshot progress status. + /// + /// If the status is `Ongoing`, it keeps track of the last voter account returned in the + /// snapshot. + #[pallet::storage] + pub(crate) type VoterSnapshotStatus = + StorageValue<_, SnapshotStatus, ValueQuery>; + + /// Target snapshot progress status. + /// + /// If the status is `Ongoing`, it keeps track of the last target account returned in the + /// snapshot. + #[pallet::storage] + pub(crate) type TargetSnapshotStatus = + StorageValue<_, SnapshotStatus, ValueQuery>; + + /// Keeps track of an ongoing multi-page election solution request and the block the first paged + /// was requested, if any. In addition, it also keeps track of the current era that is being + /// plannet. + #[pallet::storage] + pub(crate) type ElectingStartedAt = + StorageValue<_, (BlockNumberFor, EraIndex), OptionQuery>; + + // TODO: + // * maybe use pallet-paged-list? (https://paritytech.github.io/polkadot-sdk/master/pallet_paged_list/index.html) + #[pallet::storage] + pub(crate) type ElectableStashes = + StorageValue<_, BoundedVec, ValueQuery>; + + /// Lock for election data provider. + /// + /// While the lock is set, the data to build a snapshot is frozen, i.e. the returned data from + /// `ElectionDataProvider` implementation will not change. + #[pallet::storage] + #[pallet::getter(fn election_data_lock)] + pub(crate) type ElectionDataLock = StorageValue<_, (), OptionQuery>; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { @@ -798,10 +840,6 @@ pub mod pallet { ), _ => Ok(()), }); - assert!( - ValidatorCount::::get() <= - ::MaxWinners::get() - ); } // all voters are reported to the `VoterList`. @@ -818,7 +856,11 @@ pub mod pallet { pub enum Event { /// The era payout has been set; the first balance is the validator-payout; the second is /// the remainder from the maximum amount of reward. - EraPaid { era_index: EraIndex, validator_payout: BalanceOf, remainder: BalanceOf }, + EraPaid { + era_index: EraIndex, + validator_payout: BalanceOf, + remainder: BalanceOf, + }, /// The nominator has been rewarded by this amount to this destination. Rewarded { stash: T::AccountId, @@ -826,43 +868,79 @@ pub mod pallet { amount: BalanceOf, }, /// A staker (validator or nominator) has been slashed by the given amount. - Slashed { staker: T::AccountId, amount: BalanceOf }, + Slashed { + staker: T::AccountId, + amount: BalanceOf, + }, /// A slash for the given validator, for the given percentage of their stake, at the given /// era as been reported. - SlashReported { validator: T::AccountId, fraction: Perbill, slash_era: EraIndex }, + SlashReported { + validator: T::AccountId, + fraction: Perbill, + slash_era: EraIndex, + }, /// An old slashing report from a prior era was discarded because it could /// not be processed. - OldSlashingReportDiscarded { session_index: SessionIndex }, + OldSlashingReportDiscarded { + session_index: SessionIndex, + }, /// A new set of stakers was elected. StakersElected, /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, /// it will not be emitted for staking rewards when they are added to stake. - Bonded { stash: T::AccountId, amount: BalanceOf }, + Bonded { + stash: T::AccountId, + amount: BalanceOf, + }, /// An account has unbonded this amount. - Unbonded { stash: T::AccountId, amount: BalanceOf }, + Unbonded { + stash: T::AccountId, + amount: BalanceOf, + }, /// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance` /// from the unlocking queue. - Withdrawn { stash: T::AccountId, amount: BalanceOf }, + Withdrawn { + stash: T::AccountId, + amount: BalanceOf, + }, /// A nominator has been kicked from a validator. - Kicked { nominator: T::AccountId, stash: T::AccountId }, + Kicked { + nominator: T::AccountId, + stash: T::AccountId, + }, /// The election failed. No new era is planned. StakingElectionFailed, /// An account has stopped participating as either a validator or nominator. - Chilled { stash: T::AccountId }, + Chilled { + stash: T::AccountId, + }, /// The stakers' rewards are getting paid. - PayoutStarted { era_index: EraIndex, validator_stash: T::AccountId }, + PayoutStarted { + era_index: EraIndex, + validator_stash: T::AccountId, + }, /// A validator has set their preferences. - ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs }, + ValidatorPrefsSet { + stash: T::AccountId, + prefs: ValidatorPrefs, + }, /// Voters size limit reached. - SnapshotVotersSizeExceeded { size: u32 }, + SnapshotVotersSizeExceeded { + size: u32, + }, /// Targets size limit reached. - SnapshotTargetsSizeExceeded { size: u32 }, - /// A new force era mode was set. - ForceEra { mode: Forcing }, + SnapshotTargetsSizeExceeded { + size: u32, + }, + ForceEra { + mode: Forcing, + }, /// Report of a controller batch deprecation. - ControllerBatchDeprecated { failures: u32 }, + ControllerBatchDeprecated { + failures: u32, + }, } #[pallet::error] @@ -938,8 +1016,58 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(_now: BlockNumberFor) -> Weight { - // just return the weight of the on_finalize. + /// Start fetching the election pages `Pages` blocks before the election prediction, so + /// that the `ElectableStashes` is ready with all the pages on time. + fn on_initialize(now: BlockNumberFor) -> Weight { + let pages: BlockNumberFor = + <::ElectionProvider as ElectionProvider>::Pages::get().into(); + + if let Some((started_at, planning_era)) = ElectingStartedAt::::get() { + let remaining_pages = + pages.saturating_sub(One::one()).saturating_sub(now.saturating_sub(started_at)); + + if remaining_pages == Zero::zero() { + Self::do_elect_paged(Zero::zero()); + + // last page, reset elect status and update era. + crate::log!(info, "elect(): finished fetching all paged solutions."); + CurrentEra::::set(Some(planning_era)); + ElectingStartedAt::::kill(); + } else { + crate::log!( + info, + "elect(): progressing with calling elect, remaining pages {:?}.", + remaining_pages + ); + Self::do_elect_paged(remaining_pages.saturated_into::()); + } + } else { + let next_election = ::next_election_prediction(now); + + if now == (next_election.saturating_sub(pages)) { + // start calling elect. + crate::log!( + info, + "elect(): next election in {:?} pages, start fetching solution pages.", + pages, + ); + Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)); + + // set `ElectingStartedAt` only in multi-paged election. + if pages > One::one() { + ElectingStartedAt::::set(Some(( + now, + CurrentEra::::get().unwrap_or_default().saturating_add(1), + ))); + } else { + crate::log!(info, "elect(): finished fetching the single paged solution."); + } + } + }; + + // TODO: benchmarls of fetching/ not fetching election page on_initialize. + + // return the weight of the on_finalize. T::DbWeight::get().reads(1) } @@ -966,12 +1094,6 @@ pub mod pallet { // and that MaxNominations is always greater than 1, since we count on this. assert!(!MaxNominationsOf::::get().is_zero()); - // ensure election results are always bounded with the same value - assert!( - ::MaxWinners::get() == - ::MaxWinners::get() - ); - assert!( T::SlashDeferDuration::get() < T::BondingDuration::get() || T::BondingDuration::get() == 0, "As per documentation, slash defer duration ({}) should be less than bonding duration ({}).", @@ -1425,18 +1547,15 @@ pub mod pallet { #[pallet::compact] new: u32, ) -> DispatchResult { ensure_root(origin)?; - // ensure new validator count does not exceed maximum winners - // support by election provider. - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + + ensure!(new <= T::MaxValidatorSet::get(), Error::::TooManyValidators); + ValidatorCount::::put(new); Ok(()) } /// Increments the ideal number of validators up to maximum of - /// `ElectionProviderBase::MaxWinners`. + /// `T::MaxValidatorSet`. /// /// The dispatch origin must be Root. /// @@ -1451,17 +1570,15 @@ pub mod pallet { ensure_root(origin)?; let old = ValidatorCount::::get(); let new = old.checked_add(additional).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + + ensure!(new <= T::MaxValidatorSet::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) } /// Scale up the ideal number of validators by a factor up to maximum of - /// `ElectionProviderBase::MaxWinners`. + /// `T::MaxValidatorSet`. /// /// The dispatch origin must be Root. /// @@ -1474,10 +1591,7 @@ pub mod pallet { let old = ValidatorCount::::get(); let new = old.checked_add(factor.mul_floor(old)).ok_or(ArithmeticError::Overflow)?; - ensure!( - new <= ::MaxWinners::get(), - Error::::TooManyValidators - ); + ensure!(new <= T::MaxValidatorSet::get(), Error::::TooManyValidators); ValidatorCount::::put(new); Ok(()) diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 639f4096456fb..a153f065ed19d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2215,14 +2215,14 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { // winners should be 21 and 31. Otherwise this election is taking duplicates into // account. - let supports = ::ElectionProvider::elect().unwrap(); - assert_eq!( - supports, - vec![ - (21, Support { total: 1800, voters: vec![(21, 1000), (1, 400), (3, 400)] }), - (31, Support { total: 2200, voters: vec![(31, 1000), (1, 600), (3, 600)] }) - ], - ); + let supports = ::ElectionProvider::elect(SINGLE_PAGE).unwrap(); + + let expected_supports = vec![ + (21, Support { total: 1800, voters: vec![(21, 1000), (1, 400), (3, 400)] }), + (31, Support { total: 2200, voters: vec![(31, 1000), (1, 600), (3, 600)] }), + ]; + + assert_eq!(supports, to_bounded_supports(expected_supports)); }); } @@ -2267,14 +2267,13 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { assert_ok!(Staking::nominate(RuntimeOrigin::signed(3), vec![21])); // winners should be 21 and 11. - let supports = ::ElectionProvider::elect().unwrap(); - assert_eq!( - supports, - vec![ - (11, Support { total: 1500, voters: vec![(11, 1000), (1, 500)] }), - (21, Support { total: 2500, voters: vec![(21, 1000), (1, 500), (3, 1000)] }) - ], - ); + let supports = ::ElectionProvider::elect(SINGLE_PAGE).unwrap(); + let expected_supports = vec![ + (11, Support { total: 1500, voters: vec![(11, 1000), (1, 500)] }), + (21, Support { total: 2500, voters: vec![(21, 1000), (1, 500), (3, 1000)] }), + ]; + + assert_eq!(supports, to_bounded_supports(expected_supports)); }); } @@ -3792,12 +3791,17 @@ fn six_session_delay() { // pallet-session is delaying session by one, thus the next session to plan is +2. assert_eq!(>::new_session(init_session + 2), None); + + // note a new election happens independently of the call to `new_session`. + Staking::do_elect_paged(0); assert_eq!( >::new_session(init_session + 3), Some(val_set.clone()) ); assert_eq!(>::new_session(init_session + 4), None); assert_eq!(>::new_session(init_session + 5), None); + + Staking::do_elect_paged(0); assert_eq!( >::new_session(init_session + 6), Some(val_set.clone()) @@ -5159,14 +5163,15 @@ mod election_data_provider { .build_and_execute(|| { // default bounds are unbounded. assert_ok!(::electing_voters( - DataProviderBounds::default() + DataProviderBounds::default(), + 0 )); assert_eq!(MinimumActiveStake::::get(), 10); // remove staker with lower bond by limiting the number of voters and check // `MinimumActiveStake` again after electing voters. let bounds = ElectionBoundsBuilder::default().voters_count(5.into()).build(); - assert_ok!(::electing_voters(bounds.voters)); + assert_ok!(::electing_voters(bounds.voters, 0)); assert_eq!(MinimumActiveStake::::get(), 50); }); } @@ -5177,7 +5182,8 @@ mod election_data_provider { ExtBuilder::default().has_stakers(false).build_and_execute(|| { // default bounds are unbounded. assert_ok!(::electing_voters( - DataProviderBounds::default() + DataProviderBounds::default(), + 0 )); assert_eq!(::VoterList::count(), 0); assert_eq!(MinimumActiveStake::::get(), 0); @@ -5193,9 +5199,11 @@ mod election_data_provider { assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); assert_eq!(::VoterList::count(), 5); - let voters_before = - ::electing_voters(DataProviderBounds::default()) - .unwrap(); + let voters_before = ::electing_voters( + DataProviderBounds::default(), + 0, + ) + .unwrap(); assert_eq!(MinimumActiveStake::::get(), 5); // update minimum nominator bond. @@ -5205,9 +5213,11 @@ mod election_data_provider { // lower than `MinNominatorBond`. assert_eq!(::VoterList::count(), 5); - let voters = - ::electing_voters(DataProviderBounds::default()) - .unwrap(); + let voters = ::electing_voters( + DataProviderBounds::default(), + 0, + ) + .unwrap(); assert_eq!(voters_before, voters); // minimum active stake is lower than `MinNominatorBond`. @@ -5225,6 +5235,7 @@ mod election_data_provider { assert_eq!(Staking::weight_of(&101), 500); let voters = ::electing_voters( DataProviderBounds::default(), + 0, ) .unwrap(); assert_eq!(voters.len(), 5); @@ -5240,6 +5251,7 @@ mod election_data_provider { let voters = ::electing_voters( DataProviderBounds::default(), + 0, ) .unwrap(); // number of returned voters decreases since ledger entry of stash 101 is now @@ -5261,7 +5273,8 @@ mod election_data_provider { ExtBuilder::default().nominate(false).build_and_execute(|| { // default bounds are unbounded. assert!(>::iter().map(|(x, _)| x).all(|v| Staking::electing_voters( - DataProviderBounds::default() + DataProviderBounds::default(), + 0 ) .unwrap() .into_iter() @@ -5315,12 +5328,15 @@ mod election_data_provider { // 11 is taken; // we finish since the 2x limit is reached. assert_eq!( - Staking::electing_voters(bounds_builder.voters_count(2.into()).build().voters) - .unwrap() - .iter() - .map(|(stash, _, _)| stash) - .copied() - .collect::>(), + Staking::electing_voters( + bounds_builder.voters_count(2.into()).build().voters, + 0 + ) + .unwrap() + .iter() + .map(|(stash, _, _)| stash) + .copied() + .collect::>(), vec![11], ); }); @@ -5338,32 +5354,42 @@ mod election_data_provider { // if voter count limit is less.. assert_eq!( - Staking::electing_voters(bounds_builder.voters_count(1.into()).build().voters) - .unwrap() - .len(), + Staking::electing_voters( + bounds_builder.voters_count(1.into()).build().voters, + 0 + ) + .unwrap() + .len(), 1 ); // if voter count limit is equal.. assert_eq!( - Staking::electing_voters(bounds_builder.voters_count(5.into()).build().voters) - .unwrap() - .len(), + Staking::electing_voters( + bounds_builder.voters_count(5.into()).build().voters, + 0 + ) + .unwrap() + .len(), 5 ); // if voter count limit is more. assert_eq!( - Staking::electing_voters(bounds_builder.voters_count(55.into()).build().voters) - .unwrap() - .len(), + Staking::electing_voters( + bounds_builder.voters_count(55.into()).build().voters, + 0 + ) + .unwrap() + .len(), 5 ); // if target count limit is more.. assert_eq!( Staking::electable_targets( - bounds_builder.targets_count(6.into()).build().targets + bounds_builder.targets_count(6.into()).build().targets, + 0, ) .unwrap() .len(), @@ -5373,7 +5399,8 @@ mod election_data_provider { // if target count limit is equal.. assert_eq!( Staking::electable_targets( - bounds_builder.targets_count(4.into()).build().targets + bounds_builder.targets_count(4.into()).build().targets, + 0, ) .unwrap() .len(), @@ -5383,10 +5410,12 @@ mod election_data_provider { // if target limit count is less, then we return an error. assert_eq!( Staking::electable_targets( - bounds_builder.targets_count(1.into()).build().targets + bounds_builder.targets_count(1.into()).build().targets, + 0 ) - .unwrap_err(), - "Target snapshot too big" + .unwrap() + .len(), + 1, ); }); } @@ -5396,25 +5425,25 @@ mod election_data_provider { ExtBuilder::default().build_and_execute(|| { // voters: set size bounds that allows only for 1 voter. let bounds = ElectionBoundsBuilder::default().voters_size(26.into()).build(); - let elected = Staking::electing_voters(bounds.voters).unwrap(); + let elected = Staking::electing_voters(bounds.voters, 0).unwrap(); assert!(elected.encoded_size() == 26 as usize); let prev_len = elected.len(); // larger size bounds means more quota for voters. let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build(); - let elected = Staking::electing_voters(bounds.voters).unwrap(); + let elected = Staking::electing_voters(bounds.voters, 0).unwrap(); assert!(elected.encoded_size() <= 100 as usize); assert!(elected.len() > 1 && elected.len() > prev_len); // targets: set size bounds that allows for only one target to fit in the snapshot. let bounds = ElectionBoundsBuilder::default().targets_size(10.into()).build(); - let elected = Staking::electable_targets(bounds.targets).unwrap(); + let elected = Staking::electable_targets(bounds.targets, 0).unwrap(); assert!(elected.encoded_size() == 9 as usize); let prev_len = elected.len(); // larger size bounds means more space for targets. let bounds = ElectionBoundsBuilder::default().targets_size(100.into()).build(); - let elected = Staking::electable_targets(bounds.targets).unwrap(); + let elected = Staking::electable_targets(bounds.targets, 0).unwrap(); assert!(elected.encoded_size() <= 100 as usize); assert!(elected.len() > 1 && elected.len() > prev_len); }); @@ -5458,7 +5487,7 @@ mod election_data_provider { // even through 61 has nomination quota of 2 at the time of the election, all the // nominations (5) will be used. assert_eq!( - Staking::electing_voters(DataProviderBounds::default()) + Staking::electing_voters(DataProviderBounds::default(), 0) .unwrap() .iter() .map(|(stash, _, targets)| (*stash, targets.len())) @@ -5482,7 +5511,7 @@ mod election_data_provider { // nominations of controller 70 won't be added due to voter size limit exceeded. let bounds = ElectionBoundsBuilder::default().voters_size(100.into()).build(); assert_eq!( - Staking::electing_voters(bounds.voters) + Staking::electing_voters(bounds.voters, 0) .unwrap() .iter() .map(|(stash, _, targets)| (*stash, targets.len())) @@ -5499,7 +5528,7 @@ mod election_data_provider { // include the electing voters of 70. let bounds = ElectionBoundsBuilder::default().voters_size(1_000.into()).build(); assert_eq!( - Staking::electing_voters(bounds.voters) + Staking::electing_voters(bounds.voters, 0) .unwrap() .iter() .map(|(stash, _, targets)| (*stash, targets.len())) @@ -5985,7 +6014,7 @@ fn change_of_absolute_max_nominations() { let bounds = DataProviderBounds::default(); // 3 validators and 3 nominators - assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(bounds, 0).unwrap().len(), 3 + 3); // abrupt change from 16 to 4, everyone should be fine. AbsoluteMaxNominations::set(4); @@ -5996,7 +6025,7 @@ fn change_of_absolute_max_nominations() { .collect::>(), vec![(101, 2), (71, 3), (61, 1)] ); - assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(bounds, 0).unwrap().len(), 3 + 3); // abrupt change from 4 to 3, everyone should be fine. AbsoluteMaxNominations::set(3); @@ -6007,7 +6036,7 @@ fn change_of_absolute_max_nominations() { .collect::>(), vec![(101, 2), (71, 3), (61, 1)] ); - assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 3); + assert_eq!(Staking::electing_voters(bounds, 0).unwrap().len(), 3 + 3); // abrupt change from 3 to 2, this should cause some nominators to be non-decodable, and // thus non-existent unless if they update. @@ -6024,7 +6053,7 @@ fn change_of_absolute_max_nominations() { // but its value cannot be decoded and default is returned. assert!(Nominators::::get(71).is_none()); - assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 2); + assert_eq!(Staking::electing_voters(bounds, 0).unwrap().len(), 3 + 2); assert!(Nominators::::contains_key(101)); // abrupt change from 2 to 1, this should cause some nominators to be non-decodable, and @@ -6041,7 +6070,7 @@ fn change_of_absolute_max_nominations() { assert!(Nominators::::contains_key(61)); assert!(Nominators::::get(71).is_none()); assert!(Nominators::::get(61).is_some()); - assert_eq!(Staking::electing_voters(bounds).unwrap().len(), 3 + 1); + assert_eq!(Staking::electing_voters(bounds, 0).unwrap().len(), 3 + 1); // now one of them can revive themselves by re-nominating to a proper value. assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1])); @@ -6083,7 +6112,7 @@ fn nomination_quota_max_changes_decoding() { vec![(70, 3), (101, 2), (50, 4), (30, 4), (60, 1)] ); // 4 validators and 4 nominators - assert_eq!(Staking::electing_voters(unbonded_election).unwrap().len(), 4 + 4); + assert_eq!(Staking::electing_voters(unbonded_election, 0).unwrap().len(), 4 + 4); }); } @@ -6476,7 +6505,7 @@ fn reducing_max_unlocking_chunks_abrupt() { #[test] fn cannot_set_unsupported_validator_count() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorSet::set(50); // set validator count works assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 30)); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 50)); @@ -6491,7 +6520,7 @@ fn cannot_set_unsupported_validator_count() { #[test] fn increase_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorSet::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 40)); // increase works @@ -6509,7 +6538,7 @@ fn increase_validator_count_errors() { #[test] fn scale_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { - MaxWinners::set(50); + MaxValidatorSet::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 20)); // scale value works @@ -8335,3 +8364,197 @@ mod byzantine_threshold_disabling_strategy { }); } } + +pub mod multi_page_staking { + use super::*; + use frame_election_provider_support::ElectionDataProvider; + + #[test] + fn multi_page_target_snapshot_works() { + ExtBuilder::default().nominate(true).build_and_execute(|| { + let bounds = ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; + + // fetch from page 3 to 0. + assert_eq!( + ::electable_targets(bounds, 3).unwrap(), + vec![31, 21] + ); + assert_eq!( + ::electable_targets(bounds, 2).unwrap(), + vec![11] + ); + // all targets consumed now, thus remaining calls are empty vecs. + assert!(::electable_targets(bounds, 1) + .unwrap() + .is_empty()); + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); + + assert!(::electable_targets(bounds, 0) + .unwrap() + .is_empty()); + + // once we reach page 0, the status reset. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); + // and requesting a nsew snapshot can restart + assert_eq!( + ::electable_targets(bounds, 1).unwrap(), + vec![31, 21] + ); + }) + } + + #[test] + fn multi_page_voter_snapshot_works() { + ExtBuilder::default().nominate(true).build_and_execute(|| { + let bounds = ElectionBoundsBuilder::default().voters_count(3.into()).build().voters; + + // fetch from page 3 to 0. + assert_eq!( + ::electing_voters(bounds, 3) + .unwrap() + .iter() + .map(|(x, _, _)| *x) + .collect::>(), + vec![11, 21, 31] + ); + assert_eq!( + ::electing_voters(bounds, 2) + .unwrap() + .iter() + .map(|(x, _, _)| *x) + .collect::>(), + vec![101] + ); + // all voters consumed now, thus remaining calls are empty vecs. + assert!(::electing_voters(bounds, 1) + .unwrap() + .is_empty()); + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Consumed); + + assert!(::electing_voters(bounds, 0) + .unwrap() + .is_empty()); + + // once we reach page 0, the status reset. + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); + // and requesting a nsew snapshot can restart + assert_eq!( + ::electing_voters(bounds, 1) + .unwrap() + .iter() + .map(|(x, _, _)| *x) + .collect::>(), + vec![11, 21, 31] + ); + }) + } + + #[test] + fn collect_exposures_multi_page_elect_works() { + ExtBuilder::default().exposures_page_size(2).build_and_execute(|| { + assert_eq!(MaxExposurePageSize::get(), 2); + + let exposure_one = Exposure { + total: 1000 + 700, + own: 1000, + others: vec![ + IndividualExposure { who: 101, value: 500 }, + IndividualExposure { who: 102, value: 100 }, + IndividualExposure { who: 103, value: 100 }, + ], + }; + + let exposure_two = Exposure { + total: 1000 + 1000, + own: 1000, + others: vec![ + IndividualExposure { who: 104, value: 500 }, + IndividualExposure { who: 105, value: 500 }, + ], + }; + + let exposure_three = Exposure { + total: 1000 + 500, + own: 1000, + others: vec![ + IndividualExposure { who: 110, value: 250 }, + IndividualExposure { who: 111, value: 250 }, + ], + }; + + let exposures_page_one = bounded_vec![(1, exposure_one), (2, exposure_two),]; + let exposures_page_two = bounded_vec![(1, exposure_three),]; + + assert_eq!( + Pallet::::store_stakers_info_paged(exposures_page_one, current_era()) + .to_vec(), + vec![1, 2] + ); + assert_eq!( + Pallet::::store_stakers_info_paged(exposures_page_two, current_era()) + .to_vec(), + vec![1] + ); + + // Stakers overview OK for validator 1. + assert_eq!( + ErasStakersOverview::::get(0, &1).unwrap(), + PagedExposureMetadata { total: 2200, own: 1000, nominator_count: 5, page_count: 3 }, + ); + // Stakers overview OK for validator 2. + assert_eq!( + ErasStakersOverview::::get(0, &2).unwrap(), + PagedExposureMetadata { total: 2000, own: 1000, nominator_count: 2, page_count: 1 }, + ); + + // validator 1 has 3 paged exposures. + assert!(ErasStakersPaged::::get((0, &1, 0)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 1)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 2)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 3)).is_none()); + assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &1)).count(), 3); + + // validator 2 has 1 paged exposures. + assert!(ErasStakersPaged::::get((0, &2, 0)).is_some()); + assert!(ErasStakersPaged::::get((0, &2, 1)).is_none()); + assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &2)).count(), 1); + + // exposures of validator 1. + assert_eq!( + ErasStakersPaged::::iter_prefix_values((0, &1)).collect::>(), + vec![ + ExposurePage { + page_total: 100, + others: vec![IndividualExposure { who: 103, value: 100 }] + }, + ExposurePage { + page_total: 500, + others: vec![ + IndividualExposure { who: 110, value: 250 }, + IndividualExposure { who: 111, value: 250 } + ] + }, + ExposurePage { + page_total: 600, + others: vec![ + IndividualExposure { who: 101, value: 500 }, + IndividualExposure { who: 102, value: 100 } + ] + }, + ], + ); + + // exposures of validator 2. + assert_eq!( + ErasStakersPaged::::iter_prefix_values((0, &2)).collect::>(), + vec![ExposurePage { + page_total: 1000, + others: vec![ + IndividualExposure { who: 104, value: 500 }, + IndividualExposure { who: 105, value: 500 } + ] + }], + ); + }) + } +} diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 8dd29bb835de6..87c92e351e232 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -514,7 +514,8 @@ where + Copy, { pub fn merge(self, other: Self) -> Self { - debug_assert!(self.own == other.own); + // TODO hm check this + //debug_assert!(self.own == other.own); Self { total: self.total + other.total - self.own, From 94ff07368d647887f5233eb01b4b8131a658fd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 14 Oct 2024 01:06:10 +0200 Subject: [PATCH 03/95] refactors election-multiphase pallet with new paginated types --- .../src/benchmarking.rs | 6 +- .../election-provider-multi-phase/src/lib.rs | 156 ++++++++++-------- .../election-provider-multi-phase/src/mock.rs | 43 +++-- .../src/signed.rs | 4 +- .../src/unsigned.rs | 26 ++- 5 files changed, 143 insertions(+), 92 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs index 2a3994ff2aa65..32a381ccab793 100644 --- a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs @@ -272,8 +272,8 @@ frame_benchmarking::benchmarks! { // we don't directly need the data-provider to be populated, but it is just easy to use it. set_up_data_provider::(v, t); // default bounds are unbounded. - let targets = T::DataProvider::electable_targets(DataProviderBounds::default())?; - let voters = T::DataProvider::electing_voters(DataProviderBounds::default())?; + let targets = T::DataProvider::electable_targets(DataProviderBounds::default(), Zero::zero())?; + let voters = T::DataProvider::electing_voters(DataProviderBounds::default(), Zero::zero())?; let desired_targets = T::DataProvider::desired_targets()?; assert!(Snapshot::::get().is_none()); }: { @@ -311,7 +311,7 @@ frame_benchmarking::benchmarks! { assert!(Snapshot::::get().is_some()); assert!(SnapshotMetadata::::get().is_some()); }: { - assert_ok!( as ElectionProvider>::elect()); + assert_ok!( as ElectionProvider>::elect(Zero::zero())); } verify { assert!(QueuedSolution::::get().is_none()); assert!(DesiredTargets::::get().is_none()); diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 072cfe176b619..cf5bba280d8c4 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -235,13 +235,14 @@ use alloc::{boxed::Box, vec::Vec}; use codec::{Decode, Encode}; use frame_election_provider_support::{ bounds::{CountBound, ElectionBounds, ElectionBoundsBuilder, SizeBound}, - BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, - ElectionProviderBase, InstantElectionProvider, NposSolution, + BoundedSupports, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, + InstantElectionProvider, NposSolution, PageIndex, TryIntoBoundedSupports, }; use frame_support::{ + defensive_assert, dispatch::DispatchClass, ensure, - traits::{Currency, DefensiveResult, Get, OnUnbalanced, ReservableCurrency}, + traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, weights::Weight, DefaultNoBound, EqNoBound, PartialEqNoBound, }; @@ -251,7 +252,7 @@ use sp_arithmetic::{ traits::{CheckedAdd, Zero}, UpperOf, }; -use sp_npos_elections::{BoundedSupports, ElectionScore, IdentifierT, Supports, VoteWeight}; +use sp_npos_elections::{ElectionScore, IdentifierT, Supports, VoteWeight}; use sp_runtime::{ transaction_validity::{ InvalidTransaction, TransactionPriority, TransactionSource, TransactionValidity, @@ -270,6 +271,7 @@ mod mock; #[macro_use] pub mod helpers; +pub(crate) const SINGLE_PAGE: u32 = 0; const LOG_TARGET: &str = "runtime::election-provider"; pub mod migrations; @@ -287,7 +289,6 @@ pub use weights::WeightInfo; /// The solution type used by this crate. pub type SolutionOf = ::Solution; - /// The voter index. Derived from [`SolutionOf`]. pub type SolutionVoterIndexOf = as NposSolution>::VoterIndex; /// The target index. Derived from [`SolutionOf`]. @@ -296,7 +297,7 @@ pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex pub type SolutionAccuracyOf = ::MinerConfig> as NposSolution>::Accuracy; /// The fallback election type. -pub type FallbackErrorOf = <::Fallback as ElectionProviderBase>::Error; +pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; /// Configuration for the benchmarks of the pallet. pub trait BenchmarkingConfig { @@ -433,17 +434,18 @@ impl Default for RawSolution { DefaultNoBound, scale_info::TypeInfo, )] -#[scale_info(skip_type_params(AccountId, MaxWinners))] -pub struct ReadySolution +#[scale_info(skip_type_params(AccountId, MaxWinnersPerPage, MaxBackersPerWinner))] +pub struct ReadySolution where AccountId: IdentifierT, - MaxWinners: Get, + MaxWinnersPerPage: Get, + MaxBackersPerWinner: Get, { /// The final supports of the solution. /// /// This is target-major vector, storing each winners, total backing, and each individual /// backer. - pub supports: BoundedSupports, + pub supports: BoundedSupports, /// The score of the solution. /// /// This is needed to potentially challenge the solution. @@ -500,7 +502,6 @@ pub enum ElectionError { // NOTE: we have to do this manually because of the additional where clause needed on // `FallbackErrorOf`. -#[cfg(test)] impl PartialEq for ElectionError where FallbackErrorOf: PartialEq, @@ -615,7 +616,8 @@ pub mod pallet { type MinerConfig: crate::unsigned::MinerConfig< AccountId = Self::AccountId, MaxVotesPerVoter = ::MaxVotesPerVoter, - MaxWinners = Self::MaxWinners, + MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxBackersPerWinner = Self::MaxBackersPerWinner, >; /// Maximum number of signed submissions that can be queued. @@ -652,12 +654,20 @@ pub mod pallet { #[pallet::constant] type SignedDepositWeight: Get>; - /// The maximum number of winners that can be elected by this `ElectionProvider` - /// implementation. + /// Maximum number of winners that a page supports. /// /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. - #[pallet::constant] - type MaxWinners: Get; + type MaxWinnersPerPage: Get; + + /// Maximum number of voters that can support a single target, across ALL the solution + /// pages. Thus, this can only be verified when processing the last solution page. + /// + /// This limit must be set so that the memory limits of the rest of the system are + /// respected. + type MaxBackersPerWinner: Get; + + /// Number of pages. + type Pages: Get; /// Something that calculates the signed deposit base based on the signed submissions queue /// size. @@ -685,7 +695,8 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = BlockNumberFor, DataProvider = Self::DataProvider, - MaxWinners = Self::MaxWinners, + MaxBackersPerWinner = Self::MaxBackersPerWinner, + MaxWinnersPerPage = Self::MaxWinnersPerPage, >; /// Configuration of the governance-only fallback. @@ -696,7 +707,8 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = BlockNumberFor, DataProvider = Self::DataProvider, - MaxWinners = Self::MaxWinners, + MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxBackersPerWinner = Self::MaxBackersPerWinner, >; /// OCW election solution miner algorithm implementation. @@ -733,7 +745,7 @@ pub mod pallet { #[pallet::constant_name(MinerMaxWinners)] fn max_winners() -> u32 { - ::MaxWinners::get() + ::MaxWinnersPerPage::get() } } @@ -978,8 +990,9 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; ensure!(CurrentPhase::::get().is_emergency(), Error::::CallNotAllowed); - // bound supports with T::MaxWinners - let supports = supports.try_into().map_err(|_| Error::::TooManyWinners)?; + // bound supports with T::MaxWinnersPerPage. + let supports: BoundedSupports<_, _, _> = + supports.try_into_bounded_supports().map_err(|_| Error::::TooManyWinners)?; // Note: we don't `rotate_round` at this point; the next call to // `ElectionProvider::elect` will succeed and take care of that. @@ -1104,13 +1117,6 @@ pub mod pallet { Error::::FallbackFailed })?; - // transform BoundedVec<_, T::GovernanceFallback::MaxWinners> into - // `BoundedVec<_, T::MaxWinners>` - let supports: BoundedVec<_, T::MaxWinners> = supports - .into_inner() - .try_into() - .defensive_map_err(|_| Error::::BoundNotMet)?; - let solution = ReadySolution { supports, score: Default::default(), @@ -1266,7 +1272,7 @@ pub mod pallet { /// Always sorted by score. #[pallet::storage] pub type QueuedSolution = - StorageValue<_, ReadySolution>; + StorageValue<_, ReadySolution>; /// Snapshot data of the round. /// @@ -1398,7 +1404,8 @@ impl Pallet { /// Current best solution, signed or unsigned, queued to be returned upon `elect`. /// /// Always sorted by score. - pub fn queued_solution() -> Option> { + pub fn queued_solution( + ) -> Option> { QueuedSolution::::get() } @@ -1504,11 +1511,12 @@ impl Pallet { /// Parts of [`create_snapshot`] that happen outside of this pallet. /// /// Extracted for easier weight calculation. + /// + /// Note: this pallet only supports one page of voter and target snapshots. fn create_snapshot_external( ) -> Result<(Vec, Vec>, u32), ElectionError> { let election_bounds = T::ElectionBounds::get(); - - let targets = T::DataProvider::electable_targets(election_bounds.targets) + let targets = T::DataProvider::electable_targets(election_bounds.targets, SINGLE_PAGE) .and_then(|t| { election_bounds.ensure_targets_limits( CountBound(t.len() as u32), @@ -1518,7 +1526,7 @@ impl Pallet { }) .map_err(ElectionError::DataProvider)?; - let voters = T::DataProvider::electing_voters(election_bounds.voters) + let voters = T::DataProvider::electing_voters(election_bounds.voters, SINGLE_PAGE) .and_then(|v| { election_bounds.ensure_voters_limits( CountBound(v.len() as u32), @@ -1528,7 +1536,7 @@ impl Pallet { }) .map_err(ElectionError::DataProvider)?; - let mut desired_targets = as ElectionProviderBase>::desired_targets_checked() + let mut desired_targets = as ElectionProvider>::desired_targets_checked() .map_err(|e| ElectionError::DataProvider(e))?; // If `desired_targets` > `targets.len()`, cap `desired_targets` to that level and emit a @@ -1583,7 +1591,10 @@ impl Pallet { pub fn feasibility_check( raw_solution: RawSolution>, compute: ElectionCompute, - ) -> Result, FeasibilityError> { + ) -> Result< + ReadySolution, + FeasibilityError, + > { let desired_targets = DesiredTargets::::get().ok_or(FeasibilityError::SnapshotUnavailable)?; @@ -1755,29 +1766,29 @@ impl Pallet { } } -impl ElectionProviderBase for Pallet { +impl ElectionProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; type Error = ElectionError; - type MaxWinners = T::MaxWinners; + type MaxWinnersPerPage = T::MaxWinnersPerPage; + type MaxBackersPerWinner = T::MaxBackersPerWinner; + type Pages = T::Pages; type DataProvider = T::DataProvider; -} -impl ElectionProvider for Pallet { - fn ongoing() -> bool { - match CurrentPhase::::get() { - Phase::Off => false, - _ => true, - } - } + fn elect(remaining: PageIndex) -> Result, Self::Error> { + defensive_assert!(remaining.is_zero()); - fn elect() -> Result, Self::Error> { match Self::do_elect() { - Ok(supports) => { + Ok(bounded_supports) => { + // TODO:remove the bounded_supports.clone() + use frame_election_provider_support::TryIntoSupports; + let supports: Supports = + bounded_supports.clone().try_into_supports().unwrap(); + // All went okay, record the weight, put sign to be Off, clean snapshot, etc. Self::weigh_supports(&supports); Self::rotate_round(); - Ok(supports) + Ok(bounded_supports) }, Err(why) => { log!(error, "Entering emergency mode: {:?}", why); @@ -2068,7 +2079,7 @@ mod tests { assert_eq!(CurrentPhase::::get(), Phase::Unsigned((true, 25))); assert!(Snapshot::::get().is_some()); - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert!(CurrentPhase::::get().is_off()); assert!(Snapshot::::get().is_none()); @@ -2132,7 +2143,7 @@ mod tests { roll_to(30); assert!(CurrentPhase::::get().is_unsigned_open_at(20)); - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert!(CurrentPhase::::get().is_off()); assert!(Snapshot::::get().is_none()); @@ -2179,7 +2190,7 @@ mod tests { roll_to(30); assert!(CurrentPhase::::get().is_signed()); - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert!(CurrentPhase::::get().is_off()); assert!(Snapshot::::get().is_none()); @@ -2218,7 +2229,7 @@ mod tests { assert!(CurrentPhase::::get().is_off()); // This module is now only capable of doing on-chain backup. - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert!(CurrentPhase::::get().is_off()); @@ -2254,7 +2265,7 @@ mod tests { assert_eq!(Round::::get(), 1); // An unexpected call to elect. - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); // We surely can't have any feasible solutions. This will cause an on-chain election. assert_eq!( @@ -2305,7 +2316,7 @@ mod tests { } // an unexpected call to elect. - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); // all storage items must be cleared. assert_eq!(Round::::get(), 2); @@ -2376,7 +2387,7 @@ mod tests { )); roll_to(30); - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert_eq!( multi_phase_events(), @@ -2433,7 +2444,7 @@ mod tests { )); assert!(QueuedSolution::::get().is_some()); - assert_ok!(MultiPhase::elect()); + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); assert_eq!( multi_phase_events(), @@ -2475,15 +2486,16 @@ mod tests { // Zilch solutions thus far, but we get a result. assert!(QueuedSolution::::get().is_none()); - let supports = MultiPhase::elect().unwrap(); + let supports = MultiPhase::elect(SINGLE_PAGE).unwrap(); - assert_eq!( - supports, - vec![ - (30, Support { total: 40, voters: vec![(2, 5), (4, 5), (30, 30)] }), - (40, Support { total: 60, voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] }) - ] - ); + let expected_supports = vec![ + (30, Support { total: 40, voters: vec![(2, 5), (4, 5), (30, 30)] }), + (40, Support { total: 60, voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] }), + ] + .try_into_bounded_supports() + .unwrap(); + + assert_eq!(supports, expected_supports); assert_eq!( multi_phase_events(), @@ -2517,7 +2529,10 @@ mod tests { // Zilch solutions thus far. assert!(QueuedSolution::::get().is_none()); - assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); + assert_eq!( + MultiPhase::elect(SINGLE_PAGE).unwrap_err(), + ElectionError::Fallback("NoFallback.") + ); // phase is now emergency. assert_eq!(CurrentPhase::::get(), Phase::Emergency); // snapshot is still there until election finalizes. @@ -2551,7 +2566,10 @@ mod tests { // Zilch solutions thus far. assert!(QueuedSolution::::get().is_none()); - assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); + assert_eq!( + MultiPhase::elect(SINGLE_PAGE).unwrap_err(), + ElectionError::Fallback("NoFallback.") + ); // phase is now emergency. assert_eq!(CurrentPhase::::get(), Phase::Emergency); @@ -2569,7 +2587,7 @@ mod tests { // something is queued now assert!(QueuedSolution::::get().is_some()); // next election call with fix everything.; - assert!(MultiPhase::elect().is_ok()); + assert!(MultiPhase::elect(SINGLE_PAGE).is_ok()); assert_eq!(CurrentPhase::::get(), Phase::Off); assert_eq!( @@ -2621,7 +2639,7 @@ mod tests { assert_eq!(CurrentPhase::::get(), Phase::Off); // On-chain backup works though. - let supports = MultiPhase::elect().unwrap(); + let supports = MultiPhase::elect(SINGLE_PAGE).unwrap(); assert!(supports.len() > 0); assert_eq!( @@ -2660,7 +2678,7 @@ mod tests { assert_eq!(CurrentPhase::::get(), Phase::Off); roll_to(29); - let err = MultiPhase::elect().unwrap_err(); + let err = MultiPhase::elect(SINGLE_PAGE).unwrap_err(); assert_eq!(err, ElectionError::Fallback("NoFallback.")); assert_eq!(CurrentPhase::::get(), Phase::Emergency); diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 32a099e1a26f4..7792362286d0f 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -116,7 +116,7 @@ pub fn roll_to_round(n: u32) { while Round::::get() != n { roll_to_signed(); - frame_support::assert_ok!(MultiPhase::elect()); + frame_support::assert_ok!(MultiPhase::elect(Zero::zero())); } } @@ -295,7 +295,10 @@ parameter_types! { pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); #[derive(Debug)] - pub static MaxWinners: u32 = 200; + pub static MaxWinnersPerPage: u32 = 200; + #[derive(Debug)] + pub static MaxBackersPerWinner: u32 = 200; + pub static Pages: u32 = 1; // `ElectionBounds` and `OnChainElectionsBounds` are defined separately to set them independently in the tests. pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static OnChainElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); @@ -309,17 +312,24 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; type WeightInfo = (); - type MaxWinners = MaxWinners; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type Bounds = OnChainElectionsBounds; } pub struct MockFallback; -impl ElectionProviderBase for MockFallback { - type BlockNumber = BlockNumber; +impl ElectionProvider for MockFallback { type AccountId = AccountId; + type BlockNumber = BlockNumber; type Error = &'static str; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; + type Pages = Pages; type DataProvider = StakingMock; - type MaxWinners = MaxWinners; + + fn elect(_remaining: PageIndex) -> Result, Self::Error> { + unimplemented!() + } } impl InstantElectionProvider for MockFallback { @@ -361,7 +371,8 @@ impl MinerConfig for Runtime { type MaxLength = MinerMaxLength; type MaxWeight = MinerMaxWeight; type MaxVotesPerVoter = ::MaxVotesPerVoter; - type MaxWinners = MaxWinners; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type Solution = TestNposSolution; fn solution_weight(v: u32, t: u32, a: u32, d: u32) -> Weight { @@ -403,7 +414,9 @@ impl crate::Config for Runtime { type GovernanceFallback = frame_election_provider_support::onchain::OnChainExecution; type ForceOrigin = frame_system::EnsureRoot; - type MaxWinners = MaxWinners; + type Pages = Pages; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type MinerConfig = Self; type Solver = SequentialPhragmen, Balancing>; type ElectionBounds = ElectionsBounds; @@ -446,7 +459,12 @@ impl ElectionDataProvider for StakingMock { type AccountId = AccountId; type MaxVotesPerVoter = MaxNominations; - fn electable_targets(bounds: DataProviderBounds) -> data_provider::Result> { + fn electable_targets( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> data_provider::Result> { + assert!(remaining_pages.is_zero()); + let targets = Targets::get(); if !DataProviderAllowBadData::get() && @@ -458,7 +476,12 @@ impl ElectionDataProvider for StakingMock { Ok(targets) } - fn electing_voters(bounds: DataProviderBounds) -> data_provider::Result>> { + fn electing_voters( + bounds: DataProviderBounds, + remaining_pages: PageIndex, + ) -> data_provider::Result>> { + assert!(remaining_pages.is_zero()); + let mut voters = Voters::get(); if !DataProviderAllowBadData::get() { diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index c685791bbdd9d..ef1538b1e4d39 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -490,7 +490,7 @@ impl Pallet { /// /// Infallible pub fn finalize_signed_phase_accept_solution( - ready_solution: ReadySolution, + ready_solution: ReadySolution, who: &T::AccountId, deposit: BalanceOf, call_fee: BalanceOf, @@ -665,7 +665,7 @@ mod tests { ExtBuilder::default().build_and_execute(|| { // given desired_targets bigger than MaxWinners DesiredTargets::set(4); - MaxWinners::set(3); + MaxWinnersPerPage::set(3); // snapshot not created because data provider returned an unexpected number of // desired_targets diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 4c56f02db526b..bf0f555273db4 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -24,7 +24,9 @@ use crate::{ }; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; -use frame_election_provider_support::{NposSolution, NposSolver, PerThing128, VoteWeight}; +use frame_election_provider_support::{ + NposSolution, NposSolver, PerThing128, TryIntoBoundedSupports, VoteWeight, +}; use frame_support::{ dispatch::DispatchResult, ensure, @@ -389,7 +391,7 @@ impl Pallet { // ensure score is being improved. Panic henceforth. ensure!( QueuedSolution::::get() - .map_or(true, |q: ReadySolution<_, _>| raw_solution.score > q.score), + .map_or(true, |q: ReadySolution<_, _, _>| raw_solution.score > q.score), Error::::PreDispatchWeakSubmission, ); @@ -423,8 +425,10 @@ pub trait MinerConfig { /// /// The weight is computed using `solution_weight`. type MaxWeight: Get; - /// The maximum number of winners that can be elected. - type MaxWinners: Get; + /// The maximum number of winners that can be elected per page (and overall). + type MaxWinnersPerPage: Get; + /// The maximum number of backers (edges) per winner in the last solution. + type MaxBackersPerWinner: Get; /// Something that can compute the weight of a solution. /// /// This weight estimate is then used to trim the solution, based on [`MinerConfig::MaxWeight`]. @@ -743,7 +747,10 @@ impl Miner { snapshot: RoundSnapshot>, current_round: u32, minimum_untrusted_score: Option, - ) -> Result, FeasibilityError> { + ) -> Result< + ReadySolution, + FeasibilityError, + > { let RawSolution { solution, score, round } = raw_solution; let RoundSnapshot { voters: snapshot_voters, targets: snapshot_targets } = snapshot; @@ -755,7 +762,10 @@ impl Miner { ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); // Fail early if targets requested by data provider exceed maximum winners supported. - ensure!(desired_targets <= T::MaxWinners::get(), FeasibilityError::TooManyDesiredTargets); + ensure!( + desired_targets <= T::MaxWinnersPerPage::get(), + FeasibilityError::TooManyDesiredTargets + ); // Ensure that the solution's score can pass absolute min-score. let submitted_score = raw_solution.score; @@ -812,9 +822,9 @@ impl Miner { let known_score = supports.evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); - // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. + // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinnersPerPage`. let supports = supports - .try_into() + .try_into_bounded_supports() .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; Ok(ReadySolution { supports, compute, score }) From 1527bd682e6c1340067e204cd22c5795d1017d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 14 Oct 2024 01:44:04 +0200 Subject: [PATCH 04/95] nits for dependent pallets and runtimes --- polkadot/runtime/westend/src/lib.rs | 19 ++++++++++++----- substrate/frame/delegated-staking/src/mock.rs | 4 +++- substrate/frame/fast-unstake/src/mock.rs | 21 ++++++++++--------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index fe1777bc94eef..45823e51f2322 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -575,7 +575,10 @@ parameter_types! { ElectionBoundsBuilder::default().voters_count(MaxElectingVoters::get().into()).build(); // Maximum winners that can be chosen as active validators pub const MaxActiveValidators: u32 = 1000; - + // One page only, fill the whole page with the `MaxActiveValidators`. + pub const MaxWinnersPerPage: u32 = MaxActiveValidators::get(); + // Unbonded, thus the max backers per winner maps to the max electing voters limit. + pub const MaxBackersPerWinner: u32 = MaxElectingVoters::get(); } frame_election_provider_support::generate_solution_type!( @@ -594,8 +597,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = weights::frame_election_provider_support::WeightInfo; - type MaxWinners = MaxActiveValidators; type Bounds = ElectionBounds; + type MaxBackersPerWinner = MaxBackersPerWinner; + type MaxWinnersPerPage = MaxWinnersPerPage; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -608,7 +612,8 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { as frame_election_provider_support::ElectionDataProvider >::MaxVotesPerVoter; - type MaxWinners = MaxActiveValidators; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their // weight estimate function is wired to this call's weight. @@ -642,6 +647,9 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BetterSignedThreshold = (); type OffchainRepeat = OffchainRepeat; type MinerTxPriority = NposSolutionPriority; + type Pages = ConstU32<1>; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = MaxBackersPerWinner; type DataProvider = Staking; #[cfg(any(feature = "fast-runtime", feature = "runtime-benchmarks"))] type Fallback = onchain::OnChainExecution; @@ -650,7 +658,8 @@ impl pallet_election_provider_multi_phase::Config for Runtime { AccountId, BlockNumber, Staking, - MaxActiveValidators, + MaxWinnersPerPage, + MaxBackersPerWinner, )>; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen< @@ -661,7 +670,6 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type BenchmarkingConfig = polkadot_runtime_common::elections::BenchmarkConfig; type ForceOrigin = EnsureRoot; type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo; - type MaxWinners = MaxActiveValidators; type ElectionBounds = ElectionBounds; } @@ -748,6 +756,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; type TargetList = UseValidatorsMap; + type MaxValidatorSet = MaxActiveValidators; type NominationsQuota = pallet_staking::FixedNominationsQuota<{ MaxNominations::get() }>; type MaxUnlockingChunks = frame_support::traits::ConstU32<32>; type HistoryDepth = frame_support::traits::ConstU32<84>; diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 811d5739f4e98..396c8bf053dbb 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -96,7 +96,8 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; type Bounds = ElectionsBoundsOnChain; } @@ -110,6 +111,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; + type MaxValidatorSet = ConstU32<100>; type EventListeners = (Pools, DelegatedStaking); } diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 757052e230a18..b5112f0cf4886 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::{self as fast_unstake}; +use frame_election_provider_support::PageIndex; use frame_support::{ assert_ok, derive_impl, pallet_prelude::*, @@ -82,23 +83,22 @@ parameter_types! { pub static BondingDuration: u32 = 3; pub static CurrentEra: u32 = 0; pub static Ongoing: bool = false; - pub static MaxWinners: u32 = 100; } pub struct MockElection; -impl frame_election_provider_support::ElectionProviderBase for MockElection { - type AccountId = AccountId; + +impl frame_election_provider_support::ElectionProvider for MockElection { type BlockNumber = BlockNumber; - type MaxWinners = MaxWinners; + type AccountId = AccountId; type DataProvider = Staking; + type MaxBackersPerWinner = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type Pages = ConstU32<1>; type Error = (); -} -impl frame_election_provider_support::ElectionProvider for MockElection { - fn ongoing() -> bool { - Ongoing::get() - } - fn elect() -> Result, Self::Error> { + fn elect( + _remaining_pages: PageIndex, + ) -> Result, Self::Error> { Err(()) } } @@ -114,6 +114,7 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; + type MaxValidatorSet = ConstU32<100>; } parameter_types! { From 5cb1de1a9ae1a30626ea0096ad8e5f54ec19eb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 14 Oct 2024 15:55:01 +0200 Subject: [PATCH 05/95] adds ElectionProvider::ongoing to trait and impls --- substrate/frame/election-provider-multi-block/src/lib.rs | 7 +++++++ .../frame/election-provider-multi-block/src/mock/mod.rs | 4 ++++ substrate/frame/election-provider-multi-phase/src/lib.rs | 7 +++++++ substrate/frame/election-provider-multi-phase/src/mock.rs | 4 ++++ substrate/frame/election-provider-support/src/lib.rs | 7 +++++++ substrate/frame/election-provider-support/src/onchain.rs | 4 ++++ substrate/frame/fast-unstake/src/mock.rs | 4 ++++ substrate/frame/staking/src/pallet/impls.rs | 4 +--- 8 files changed, 38 insertions(+), 3 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs index fd1b7cc05f0ac..5b813b39cd33e 100644 --- a/substrate/frame/election-provider-multi-block/src/lib.rs +++ b/substrate/frame/election-provider-multi-block/src/lib.rs @@ -764,6 +764,13 @@ impl ElectionProvider for Pallet { err }) } + + fn ongoing() -> bool { + match CurrentPhase::::get() { + Phase::Off => false, + _ => true, + } + } } #[cfg(test)] diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index e094bac3f6919..eaf5797a5215e 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -255,6 +255,10 @@ impl ElectionProvider for MockFallback { Err("fallback election failed (forced in mock)") } } + + fn ongoing() -> bool { + false + } } #[derive(Default)] diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index cf5bba280d8c4..d92a8bfc4b61e 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1797,6 +1797,13 @@ impl ElectionProvider for Pallet { }, } } + + fn ongoing() -> bool { + match CurrentPhase::::get() { + Phase::Off => false, + _ => true, + } + } } /// convert a DispatchError to a custom InvalidTransaction with the inner code being the error diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 7792362286d0f..d6a34fca46166 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -330,6 +330,10 @@ impl ElectionProvider for MockFallback { fn elect(_remaining: PageIndex) -> Result, Self::Error> { unimplemented!() } + + fn ongoing() -> bool { + false + } } impl InstantElectionProvider for MockFallback { diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 09b0d65b3e6fb..d360ad4c16e39 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -448,6 +448,9 @@ pub trait ElectionProvider { } }) } + + /// Indicate if this election provider is currently ongoing an asynchronous election or not. + fn ongoing() -> bool; } /// A (almost) marker trait that signifies an election provider as working synchronously. i.e. being @@ -484,6 +487,10 @@ where fn elect(_remaining_pages: PageIndex) -> Result, Self::Error> { Err("`NoElection` cannot do anything.") } + + fn ongoing() -> bool { + false + } } impl diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index f7349d5fd0cda..b7519d2dc5a9a 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -187,6 +187,10 @@ impl ElectionProvider for OnChainExecution { let election_bounds = ElectionBoundsBuilder::from(T::Bounds::get()).build(); Self::elect_with(election_bounds, Zero::zero()) } + + fn ongoing() -> bool { + false + } } #[cfg(test)] diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index b5112f0cf4886..c0c23af51fb53 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -101,6 +101,10 @@ impl frame_election_provider_support::ElectionProvider for MockElection { ) -> Result, Self::Error> { Err(()) } + + fn ongoing() -> bool { + Ongoing::get() + } } #[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b6892c5676801..ea6fd4915d00a 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2016,9 +2016,7 @@ impl StakingInterface for Pallet { } fn election_ongoing() -> bool { - // TODO(gpestana) - //T::ElectionProvider::ongoing() - false + ::ongoing() } fn force_unstake(who: Self::AccountId) -> sp_runtime::DispatchResult { From 43eec4b403f9eb5ccc2b332742f14c82c502fc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 12:44:08 +0200 Subject: [PATCH 06/95] clean up sp-staking --- substrate/primitives/staking/src/lib.rs | 75 +++++++++++++------------ 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 87c92e351e232..191c1c3d8a312 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -346,7 +346,7 @@ pub trait StakingUnchecked: StakingInterface { } /// The amount of exposure for an era that an individual nominator has (susceptible to slashing). -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Copy)] pub struct IndividualExposure { /// The stash account of the nominator in question. pub who: AccountId, @@ -434,41 +434,16 @@ impl Default for ExposurePage { } } +/// Returns an exposure page from a set of individual exposures. impl From>> for ExposurePage { fn from(exposures: Vec>) -> Self { - let mut page: Self = Default::default(); - - let _ = exposures - .into_iter() - .map(|e| { - page.page_total += e.value.clone(); - page.others.push(e) - }) - .collect::>(); - - page - } -} - -impl< - A, - B: Default - + HasCompact - + core::fmt::Debug - + sp_std::ops::AddAssign - + sp_std::ops::SubAssign - + Clone, - > ExposurePage -{ - /// Split the current exposure page into two pages where the new page takes up to `num` - /// individual exposures. The remaining individual exposures are left in `self`. - pub fn from_split_others(&mut self, num: usize) -> Self { - let new: ExposurePage<_, _> = self.others.split_off(num).into(); - self.page_total -= new.page_total.clone(); - - new + exposures.into_iter().fold(ExposurePage::default(), |mut page, e| { + page.page_total += e.value.clone(); + page.others.push(e); + page + }) } } @@ -511,17 +486,20 @@ where + sp_std::ops::Add + sp_std::ops::Sub + PartialEq - + Copy, + + Copy + + sp_runtime::traits::Debug, { + /// Merge a paged exposure metadata page into self and return the result. pub fn merge(self, other: Self) -> Self { - // TODO hm check this + // TODO(gpestana): re-enable assert. //debug_assert!(self.own == other.own); Self { total: self.total + other.total - self.own, own: self.own, nominator_count: self.nominator_count + other.nominator_count, - // TODO: merge the pages correctly. + // TODO(gpestana): merge the pages efficiently so that we make sure all the slots in the + // page are filled. page_count: self.page_count + other.page_count, } } @@ -687,3 +665,30 @@ pub trait DelegationMigrator { } sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = "runtime-benchmarks", $); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn individual_exposures_to_exposure_works() { + let exposure_1 = IndividualExposure { who: 1, value: 10u32 }; + let exposure_2 = IndividualExposure { who: 2, value: 20 }; + let exposure_3 = IndividualExposure { who: 3, value: 30 }; + + let exposure_page: ExposurePage = vec![exposure_1, exposure_2, exposure_3].into(); + + assert_eq!( + exposure_page, + ExposurePage { page_total: 60, others: vec![exposure_1, exposure_2, exposure_3] }, + ); + } + + #[test] + fn empty_individual_exposures_to_exposure_works() { + let empty_exposures: Vec> = vec![]; + + let exposure_page: ExposurePage = empty_exposures.into(); + assert_eq!(exposure_page, ExposurePage { page_total: 0, others: vec![] }); + } +} From 11dd78554b2e5c07a75eef69817a2f5a72cd0320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 14:03:15 +0200 Subject: [PATCH 07/95] clean up and rustdoc for epm-support --- .../election-provider-multi-phase/src/lib.rs | 11 +-- .../election-provider-support/src/lib.rs | 93 ++++++++++++------- 2 files changed, 66 insertions(+), 38 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index d92a8bfc4b61e..9de43a746d3a0 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1674,7 +1674,9 @@ impl Pallet { } /// record the weight of the given `supports`. - fn weigh_supports(supports: &Supports) { + fn weigh_supports( + supports: &BoundedSupports, + ) { let active_voters = supports .iter() .map(|(_, x)| x) @@ -1780,13 +1782,8 @@ impl ElectionProvider for Pallet { match Self::do_elect() { Ok(bounded_supports) => { - // TODO:remove the bounded_supports.clone() - use frame_election_provider_support::TryIntoSupports; - let supports: Supports = - bounded_supports.clone().try_into_supports().unwrap(); - // All went okay, record the weight, put sign to be Off, clean snapshot, etc. - Self::weigh_supports(&supports); + Self::weigh_supports(&bounded_supports); Self::rotate_round(); Ok(bounded_supports) }, diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index d360ad4c16e39..56217c3d3052c 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -55,8 +55,22 @@ //! //! To accommodate both type of elections in one trait, the traits lean toward **stateful //! election**, as it is more general than the stateless. This is why [`ElectionProvider::elect`] -//! has no parameters. All value and type parameter must be provided by the [`ElectionDataProvider`] -//! trait, even if the election happens immediately. +//! does not receive election data as an input. All value and type parameter must be provided by the +//! [`ElectionDataProvider`] trait, even if the election happens immediately. +//! +//! ## Multi-page election +//! +//! Both [`ElectionDataProvider`] and [`ElectionProvider`] traits are parameterized by page, +//! supporting an election to be performed over multiple pages. This enables the +//! [`ElectionDataProvider`] implementor to provide all the election data over multiple pages. +//! Similarly [`ElectionProvider::elect`] is parameterized by page index. +//! +//! ## [`LockableElectionDataProvider`] for multi-page election +//! +//! The [`LockableElectionDataProvider`] trait exposes a way for election data providers to lock +//! and unlock election data mutations. This is an useful trait to ensure that the results of +//! calling [`ElectionDataProvider::electing_voters`] and +//! [`ElectionDataProvider::electable_targets`] remain consistent over multiple pages. //! //! ## Election Data //! @@ -103,17 +117,17 @@ //! impl ElectionDataProvider for Pallet { //! type AccountId = AccountId; //! type BlockNumber = BlockNumber; -//! type MaxVotesPerVoter = ConstU32<1>; +//! type MaxVotesPerVoter = ConstU32<100>; //! //! fn desired_targets() -> data_provider::Result { //! Ok(1) //! } -//! fn electing_voters(bounds: DataProviderBounds, _remaining_pages: PageIndex) +//! fn electing_voters(bounds: DataProviderBounds, _page: PageIndex) //! -> data_provider::Result>> //! { //! Ok(Default::default()) //! } -//! fn electable_targets(bounds: DataProviderBounds, _remaining_pages: PageIndex) -> data_provider::Result> { +//! fn electable_targets(bounds: DataProviderBounds, _page: PageIndex) -> data_provider::Result> { //! Ok(vec![10, 20, 30]) //! } //! fn next_election_prediction(now: BlockNumber) -> BlockNumber { @@ -145,7 +159,11 @@ //! type Pages = T::Pages; //! type DataProvider = T::DataProvider; //! -//! fn elect(remaining_pages: PageIndex) -> Result, Self::Error> { +//! fn elect(page: PageIndex) -> Result, Self::Error> { +//! unimplemented!() +//! } +//! +//! fn ongoing() -> bool { //! unimplemented!() //! } //! } @@ -245,6 +263,9 @@ mod mock; #[cfg(test)] mod tests; +/// A page index for the multi-block elections pagination. +pub type PageIndex = u32; + /// The [`IndexAssignment`] type is an intermediate between the assignments list /// ([`&[Assignment]`][Assignment]) and `SolutionOf`. /// @@ -306,29 +327,33 @@ pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. type MaxVotesPerVoter: Get; - /// All possible targets for the election, i.e. the targets that could become elected, thus - /// "electable". + /// Returns the possible targets for the election associated with page `page`, i.e. the targets + /// that could become elected, thus "electable". /// + /// TODO(gpestana): remove self-weighing and return the weight. /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. fn electable_targets( bounds: DataProviderBounds, - remaining_pages: PageIndex, + page: PageIndex, ) -> data_provider::Result>; - /// All the voters that participate in the election, thus "electing". + /// All the voters that participate in the election associated with page `page`, thus + /// "electing". /// /// Note that if a notion of self-vote exists, it should be represented here. /// + /// TODO(gpestana): remove self-weighing and return the weight. /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. fn electing_voters( bounds: DataProviderBounds, - remaining_pages: PageIndex, + page: PageIndex, ) -> data_provider::Result>>; /// The number of targets to elect. /// + /// TODO(gpestana): remove self-weighting ?? /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. /// @@ -384,10 +409,16 @@ pub trait ElectionDataProvider { fn set_desired_targets(_count: u32) {} } -/// An [`ElectionDataProvider`] that exposes for an external entity to request a lock/unlock on +/// An [`ElectionDataProvider`] that exposes for an external entity to request lock/unlock on /// updates in the election data. +/// +/// This functionality is useful when requesting multi-pages of election data, so that the data +/// provided across pages (and potentially across blocks) is consistent. pub trait LockableElectionDataProvider: ElectionDataProvider { + /// Lock mutations in the election data provider. fn set_lock() -> data_provider::Result<()>; + + /// Unlocks mutations in the election data provider. fn unlock(); } @@ -404,10 +435,16 @@ pub trait ElectionProvider { type Error: Debug + PartialEq; /// The maximum number of winners per page in results returned by this election provider. + /// + /// A winner is an `AccountId` that is part of the final election result. type MaxWinnersPerPage: Get; /// The maximum number of backers that a single page may have in results returned by this /// election provider. + /// + /// A backer is an `AccountId` that "backs" one or more winners. For example, in the context of + /// nominated proof of stake, a backer is a voter that nominates a winner validator in the + /// election result. type MaxBackersPerWinner: Get; /// The number of pages that this election provider supports. @@ -421,11 +458,15 @@ pub trait ElectionProvider { /// Elect a new set of winners. /// + /// A complete election may require multiple calls to [`ElectionProvider::elect`] if + /// [`ElectionProvider::Pages`] is higher than one. + /// /// The result is returned in a target major format, namely as vector of supports. /// + /// TODO(gpestana): remove self-weighing? /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. - fn elect(remaining: PageIndex) -> Result, Self::Error>; + fn elect(page: PageIndex) -> Result, Self::Error>; /// The index of the *most* significant page that this election provider supports. fn msp() -> PageIndex { @@ -449,7 +490,7 @@ pub trait ElectionProvider { }) } - /// Indicate if this election provider is currently ongoing an asynchronous election or not. + /// Indicate whether this election provider is currently ongoing an asynchronous election. fn ongoing() -> bool; } @@ -484,7 +525,7 @@ where type MaxWinnersPerPage = MaxWinnersPerPage; type MaxBackersPerWinner = MaxBackersPerWinner; - fn elect(_remaining_pages: PageIndex) -> Result, Self::Error> { + fn elect(_page: PageIndex) -> Result, Self::Error> { Err("`NoElection` cannot do anything.") } @@ -751,6 +792,12 @@ impl> TryFrom> } /// A bounded vector of [`BoundedSupport`]. +/// +/// A [`BoundedSupports`] is a set of [`sp_npos_elections::Supports`] which are bounded in two +/// dimensions. `BInner` corresponds to the bound of the maximum backers per voter and `BOuter` +/// corresponds to the bound of the maximum winners that the bounded supports may contain. +/// +/// With the bounds, we control the maximum size of a bounded supports instance. #[derive(Encode, Decode, TypeInfo, DefaultNoBound, MaxEncodedLen)] #[codec(mel_bound(AccountId: MaxEncodedLen, BOuter: Get, BInner: Get))] #[scale_info(skip_type_params(BOuter, BInner))] @@ -837,19 +884,6 @@ impl, BInner: Get> } } -pub trait TryIntoSupports, BInner: Get> { - fn try_into_supports(self) -> Result, ()>; -} - -impl, BInner: Get> TryIntoSupports - for BoundedSupports -{ - fn try_into_supports(self) -> Result, ()> { - // TODO - Ok(Default::default()) - } -} - /// Same as `BoundedSupports` but parameterized by an `ElectionProvider`. pub type BoundedSupportsOf = BoundedSupports< ::AccountId, @@ -857,9 +891,6 @@ pub type BoundedSupportsOf = BoundedSupports< ::MaxBackersPerWinner, >; -/// A page index for the multi-block elections pagination. -pub type PageIndex = u32; - sp_core::generate_feature_enabled_macro!( runtime_benchmarks_enabled, feature = "runtime-benchmarks", From 5c1757342579757192d0db58ddf52c160b87c5e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 14:08:49 +0200 Subject: [PATCH 08/95] nits onchain election provider --- .../frame/election-provider-support/src/onchain.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index b7519d2dc5a9a..95f74ba298277 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -103,11 +103,11 @@ pub trait Config { impl OnChainExecution { fn elect_with( bounds: ElectionBounds, - remaining: PageIndex, + page: PageIndex, ) -> Result, Error> { - let (voters, targets) = T::DataProvider::electing_voters(bounds.voters, remaining) + let (voters, targets) = T::DataProvider::electing_voters(bounds.voters, page) .and_then(|voters| { - Ok((voters, T::DataProvider::electable_targets(bounds.targets, remaining)?)) + Ok((voters, T::DataProvider::electable_targets(bounds.targets, page)?)) }) .map_err(Error::DataProvider)?; @@ -179,8 +179,8 @@ impl ElectionProvider for OnChainExecution { type Pages = sp_core::ConstU32<1>; type DataProvider = T::DataProvider; - fn elect(remaining_pages: PageIndex) -> Result, Self::Error> { - if remaining_pages > 0 { + fn elect(page: PageIndex) -> Result, Self::Error> { + if page > 0 { return Err(Error::SinglePageExpected) } @@ -285,7 +285,7 @@ mod tests { type MaxVotesPerVoter = ConstU32<2>; fn electing_voters( _: DataProviderBounds, - _remaining_pages: PageIndex, + _page: PageIndex, ) -> data_provider::Result>> { Ok(vec![ (1, 10, bounded_vec![10, 20]), @@ -296,7 +296,7 @@ mod tests { fn electable_targets( _: DataProviderBounds, - _remaining_pages: PageIndex, + _page: PageIndex, ) -> data_provider::Result> { Ok(vec![10, 20, 30]) } From ee7bdd49cac91defd3aa059658809bd55419e6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 16:36:39 +0200 Subject: [PATCH 09/95] EPM nits and rustdoc improvements --- .../election-provider-multi-phase/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 9de43a746d3a0..c7f9e657e546c 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -189,6 +189,13 @@ //! Note that there could be an overlap between these sub-errors. For example, A //! `SnapshotUnavailable` can happen in both miner and feasibility check phase. //! +//! ## Multi-page election support +//! +//! Even though the [`frame_election_provider_support::ElectionDataProvider`] and +//! [`frame_election_provider_support::ElectionProvider`] traits support multi-paged election, this +//! pallet only supports a single page election flow. Thus, [`Config::Pages`] must be always set to +//! one, which is asserted by the [`frame_support::traits::Hooks::integrity_test`]. +//! //! ## Future Plans //! //! **Emergency-phase recovery script**: This script should be taken out of staking-miner in @@ -271,6 +278,7 @@ mod mock; #[macro_use] pub mod helpers; +/// This pallet only supports a single page election flow. pub(crate) const SINGLE_PAGE: u32 = 0; const LOG_TARGET: &str = "runtime::election-provider"; @@ -887,6 +895,9 @@ pub mod pallet { // `SignedMaxSubmissions` is a red flag that the developer does not understand how to // configure this pallet. assert!(T::SignedMaxSubmissions::get() >= T::SignedMaxRefunds::get()); + + // This pallet only supports single-page elections. + assert!(T::Pages::get() == 1u32); } #[cfg(feature = "try-runtime")] @@ -1777,8 +1788,9 @@ impl ElectionProvider for Pallet { type Pages = T::Pages; type DataProvider = T::DataProvider; - fn elect(remaining: PageIndex) -> Result, Self::Error> { - defensive_assert!(remaining.is_zero()); + fn elect(page: PageIndex) -> Result, Self::Error> { + // this pallet **MUST** only by used in the single-block mode. + defensive_assert!(page.is_zero()); match Self::do_elect() { Ok(bounded_supports) => { From f30b548b566f72da139949f6ac19f4326ed576d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 18:24:23 +0200 Subject: [PATCH 10/95] clean up and rustdocs for EPM core and sub pallets --- Cargo.lock | 27 +++ Cargo.toml | 1 + .../integration-tests/Cargo.toml | 2 +- .../integration-tests/src/mock.rs | 12 +- .../election-provider-multi-block/src/lib.rs | 219 +++++++++++------- .../src/mock/mod.rs | 10 +- .../src/types.rs | 2 + .../src/unsigned/miner.rs | 1 + .../src/unsigned/tests.rs | 20 +- .../src/verifier/impls.rs | 92 +------- 10 files changed, 191 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6aae9a6398c92..785dec8e9ef48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11544,6 +11544,33 @@ dependencies = [ "substrate-test-utils", ] +[[package]] +name = "pallet-epm-mb-integrity-tests" +version = "1.0.0" +dependencies = [ + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-bags-list", + "pallet-balances", + "pallet-election-provider-multi-block", + "pallet-nomination-pools", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "parity-scale-codec", + "parking_lot 0.12.3", + "scale-info", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-npos-elections", + "sp-runtime 31.0.1", + "sp-staking", + "sp-std 14.0.0", + "sp-tracing 16.0.0", +] + [[package]] name = "pallet-example-basic" version = "27.0.0" diff --git a/Cargo.toml b/Cargo.toml index 308603b09d478..b21c7c1015231 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -341,6 +341,7 @@ members = [ "substrate/frame/democracy", "substrate/frame/election-provider-multi-block", "substrate/frame/election-provider-multi-phase", + "substrate/frame/election-provider-multi-block/integration-tests", "substrate/frame/election-provider-multi-phase/test-staking-e2e", "substrate/frame/election-provider-support", "substrate/frame/election-provider-support/benchmarking", diff --git a/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml b/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml index 15aa841666209..195e001026000 100644 --- a/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml +++ b/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pallet-election-tests" +name = "pallet-epm-mb-integrity-tests" version = "1.0.0" authors.workspace = true edition.workspace = true diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs index 29dd2733250e3..61ab42251d7c3 100644 --- a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs +++ b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs @@ -45,7 +45,6 @@ use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, onchain, ElectionDataProvider, ExtendedBalance, PageIndex, SequentialPhragmen, Weight, }; -use sp_npos_elections::ElectionScore; use pallet_election_provider_multi_block::{ self as epm_core_pallet, @@ -869,10 +868,15 @@ parameter_types! { pub(crate) fn try_submit_paged_solution() -> Result<(), ()> { let submit = || { // TODO: to finish. + let voters_snapshot = Default::default(); + let targets_snapshot = Default::default(); + let round = Default::default(); + let desired_targets = Default::default(); + let (paged_solution, _) = miner::Miner::<::MinerConfig>::mine_paged_solution_with_snapshot( - voters_snapshot, - targets_snapshot, + &voters_snapshot, + &targets_snapshot, Pages::get(), round, desired_targets, @@ -882,7 +886,7 @@ pub(crate) fn try_submit_paged_solution() -> Result<(), ()> { let _ = SignedPallet::register(RuntimeOrigin::signed(10), paged_solution.score).unwrap(); - for (idx, page) in paged_solution.solution_pages.into_iter().enumerate() {} + for (_idx, _page) in paged_solution.solution_pages.into_iter().enumerate() {} log!( info, "submitter: successfully submitted {} pages with {:?} score in round {}.", diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs index 5b813b39cd33e..3308c3c261706 100644 --- a/substrate/frame/election-provider-multi-block/src/lib.rs +++ b/substrate/frame/election-provider-multi-block/src/lib.rs @@ -19,7 +19,7 @@ //! //! This pallet manages the NPoS election across its different phases, with the ability to accept //! both on-chain and off-chain solutions. The off-chain solutions may be submitted as a signed or -//! unsigned transaction. Crucially, supports paginated, multi-block elections. The goal of +//! unsigned transaction. Crucially, it supports paginated, multi-block elections. The goal of //! supporting paged elections is to scale the elections linearly with the number of blocks //! allocated to the election. //! @@ -54,8 +54,8 @@ //! - The [`signed`] pallet implements the signed phase, where off-chain entities commit to and //! submit their election solutions. This pallet implements the //! [`verifier::SolutionDataProvider`], which is used by the [`verifier`] pallet to fetch solution -//! data. -//! - The [`unsigned`] pallet implements the unsigned phase, where block authors can calculate and +//! data to perform the solution verification. +//! - The [`unsigned`] pallet implements the unsigned phase, where block authors can compute and //! submit through inherent paged solutions. This pallet also implements the //! [`verifier::SolutionDataProvider`] interface. //! @@ -77,6 +77,8 @@ //! This pallet manages the election phases which signal to the other sub-pallets which actions to //! take at a given block. The election phases are the following: //! +//! +//! // TODO(gpestana): use a diagram instead of text diagram. //! ```text //! // ----------- ----------- -------------- ------------ -------- //! // | | | | | | | @@ -86,22 +88,20 @@ //! Each phase duration depends on the estimate block number election, which can be fetched from //! [`pallet::Config::DataProvider`]. //! -//! > to-finish +//! TODO(gpestana): finish, add all info related to EPM-MB #![cfg_attr(not(feature = "std"), no_std)] -// TODO: remove -#![allow(dead_code)] use frame_election_provider_support::{ bounds::ElectionBoundsBuilder, BoundedSupportsOf, ElectionDataProvider, ElectionProvider, - LockableElectionDataProvider, PageIndex, VoterOf, Weight, + LockableElectionDataProvider, PageIndex, Weight, }; use frame_support::{ defensive, ensure, traits::{Defensive, DefensiveSaturating, Get}, BoundedVec, }; -use sp_runtime::traits::Zero; +use sp_runtime::traits::{One, Zero}; use frame_system::pallet_prelude::BlockNumberFor; @@ -129,6 +129,7 @@ pub use crate::{unsigned::miner, verifier::Verifier, weights::WeightInfo}; #[cfg(any(test, feature = "runtime-benchmarks"))] use crate::verifier::Pallet as PalletVerifier; +/// Log target for this the core EPM-MB pallet. const LOG_TARGET: &'static str = "runtime::multiblock-election"; /// Page configured for the election. @@ -146,7 +147,7 @@ pub trait BenchmarkingConfig { const TARGETS_PER_PAGE: [u32; 2]; } -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub mod pallet { use super::*; @@ -155,7 +156,6 @@ pub mod pallet { sp_runtime::Saturating, Twox64Concat, }; - use frame_system::pallet_prelude::BlockNumberFor; #[pallet::config] pub trait Config: frame_system::Config { @@ -164,20 +164,39 @@ pub mod pallet { + TryInto>; /// Duration of the signed phase; + /// + /// During the signed phase, staking miners may register their solutions and submit + /// paginated solutions. #[pallet::constant] type SignedPhase: Get>; /// Duration of the unsigned phase; + /// + /// During the unsigned phase, offchain workers of block producing validators compute and + /// submit paginated solutions. #[pallet::constant] type UnsignedPhase: Get>; /// Duration of the signed validation phase. /// - /// The duration of this phase SHOULD NOT be less than `T::Pages` and there is no point in - /// it being more than the maximum number of pages per submission. + /// During the signed validation phase, the async verifier verifies one or all the queued + /// solution submitions during the signed phase. Once one solution is accepted, this phase + /// terminates. + /// + /// The duration of this phase **SHOULD NOT** be less than `T::Pages` and there is no point + /// in it being more than the maximum number of pages per submission. #[pallet::constant] type SignedValidationPhase: Get>; + /// The limit number of blocks that the `Phase::Export` will be open for. + /// + /// During the export phase, this pallet is open to return paginated, verified solution + /// pages if at least one solution has been verified and accepted in the current era. + /// + /// The export phase will terminate if it has been open for `T::ExportPhaseLimit` blocks or + /// the `EPM::call(0)` is called. + type ExportPhaseLimit: Get>; + /// The number of blocks that the election should be ready before the election deadline. #[pallet::constant] type Lookhaead: Get>; @@ -194,7 +213,7 @@ pub mod pallet { /// in one page of a solution. type MaxWinnersPerPage: Get; - /// Maximum number of voters that can support a single target, across ALL the solution + /// Maximum number of voters that can support a single target, across **ALL(()) the solution /// pages. Thus, this can only be verified when processing the last solution page. /// /// This limit must be set so that the memory limits of the rest of the system are @@ -203,16 +222,10 @@ pub mod pallet { /// The number of pages. /// - /// A solution may contain at MOST this many pages. + /// A solution may contain at **MOST** this many pages. #[pallet::constant] type Pages: Get; - /// The limit number of blocks that the `Phase::Export` will be open for. - /// - /// The export phase will terminate if it has been open for `T::ExportPhaseLimit` blocks or - /// the `EPM::call(0)` is called. - type ExportPhaseLimit: Get>; - /// Something that will provide the election data. type DataProvider: LockableElectionDataProvider< AccountId = Self::AccountId, @@ -275,6 +288,8 @@ pub mod pallet { } /// Election failure strategy. + /// + /// This strategy defines the actions of this pallet once an election fails. #[pallet::storage] pub(crate) type ElectionFailure = StorageValue<_, ElectionFailureStrategy, ValueQuery>; @@ -283,14 +298,15 @@ pub mod pallet { #[pallet::storage] pub(crate) type CurrentPhase = StorageValue<_, Phase>, ValueQuery>; - /// Current round + /// Current round. #[pallet::storage] pub(crate) type Round = StorageValue<_, u32, ValueQuery>; - /// Paginated target snapshot. + /// Target snapshot. + /// + /// Note: The target snapshot is single-paged. #[pallet::storage] - pub(crate) type PagedTargetSnapshot = - StorageMap<_, Twox64Concat, PageIndex, BoundedVec>; + pub(crate) type TargetSnapshot = StorageValue<_, TargetPageOf, OptionQuery>; /// Paginated voter snapshot. #[pallet::storage] @@ -321,8 +337,6 @@ pub mod pallet { // | | | | | | | // Off Snapshot (Signed SigValid) Unsigned Export elect() - use sp_runtime::traits::One; - let export_deadline = T::ExportPhaseLimit::get().saturating_add(T::Lookhaead::get()); let unsigned_deadline = export_deadline.saturating_add(T::UnsignedPhase::get()); let signed_validation_deadline = @@ -364,9 +378,9 @@ pub mod pallet { match current_phase { // start snapshot. Phase::Off + // allocate one extra block for the (single-page) target snapshot. if remaining_blocks <= snapshot_deadline && remaining_blocks > signed_deadline => - // allocate one extra block for the target snapshot. Self::try_progress_snapshot(T::Pages::get() + 1), // continue snapshot. @@ -378,13 +392,13 @@ pub mod pallet { T::WeightInfo::on_phase_transition() }, - // start signed phase. The `signed` pallet will take further actions now. + // start signed phase. The `signed` sub-pallet will take further actions now. Phase::Snapshot(0) if remaining_blocks <= signed_deadline && remaining_blocks > signed_validation_deadline => Self::start_signed_phase(), - // start signed validation. The `signed` pallet will take further actions now. + // start signed validation. The `signed` sub-pallet will take further actions now. Phase::Signed if remaining_blocks <= signed_validation_deadline && remaining_blocks > unsigned_deadline => @@ -393,7 +407,7 @@ pub mod pallet { T::WeightInfo::on_phase_transition() }, - // start unsigned phase. The `unsigned` pallet will take further actions now. + // start unsigned phase. The `unsigned` sub-pallet will take further actions now. Phase::Signed | Phase::SignedValidation(_) | Phase::Snapshot(0) if remaining_blocks <= unsigned_deadline && remaining_blocks > Zero::zero() => { @@ -401,7 +415,14 @@ pub mod pallet { T::WeightInfo::on_phase_transition() }, - // EPM is "serving" the staking pallet with the election results. + // start export phase. + Phase::Unsigned(_) if now == next_election.saturating_sub(export_deadline) => { + Self::phase_transition(Phase::Export(now)); + T::WeightInfo::on_phase_transition() + }, + + // election solution **MAY** be ready, start export phase to allow external pallets + // to request paged election solutions. Phase::Export(started_at) => Self::do_export_phase(now, started_at), _ => T::WeightInfo::on_initialize_do_nothing(), @@ -429,7 +450,7 @@ pub mod pallet { /// It manages the following storage items: /// /// - [`PagedVoterSnapshot`]: Paginated map of voters. -/// - [`PagedTargetSnapshot`]: Paginated map of targets. +/// - [`TargetSnapshot`]: Single page, bounded list of targets. /// /// To ensure correctness and data consistency, all the reads and writes to storage items related /// to the snapshot and "wrapped" by this struct must be performed through the methods exposed by @@ -438,24 +459,24 @@ pub(crate) struct Snapshot(sp_std::marker::PhantomData); impl Snapshot { /// Returns the targets snapshot. /// - /// TODO(gpestana): consider paginating targets (update: a lot of shenenigans on the assignments - /// converstion and target/voter index. Hard to ensure that no more than 1 snapshot page is - /// fetched when both voter and target snapshots are paged.) - fn targets() -> Option> { - PagedTargetSnapshot::::get(Pallet::::lsp()) + /// The target snapshot is single paged. + fn targets() -> Option> { + TargetSnapshot::::get() } /// Sets a page of targets in the snapshot's storage. - fn set_targets(targets: BoundedVec) { - PagedTargetSnapshot::::insert(Pallet::::lsp(), targets); + /// + /// The target snapshot is single paged. + fn set_targets(targets: TargetPageOf) { + TargetSnapshot::::set(Some(targets)); } /// Returns whether the target snapshot exists in storage. fn targets_snapshot_exists() -> bool { - !PagedTargetSnapshot::::iter_keys().count().is_zero() + TargetSnapshot::::get().is_some() } - /// Return the number of desired targets, which is defined by [`T::DataProvider`]. + /// Returns the number of desired targets, as defined by [`T::DataProvider`]. fn desired_targets() -> Option { match T::DataProvider::desired_targets() { Ok(desired) => Some(desired), @@ -469,32 +490,29 @@ impl Snapshot { } } - /// Returns the voters of a specific `page` index in the current snapshot. + /// Returns the voters of a specific `page` index of the current snapshot, if any. fn voters(page: PageIndex) -> Option> { PagedVoterSnapshot::::get(page) } /// Sets a single page of voters in the snapshot's storage. - fn set_voters( - page: PageIndex, - voters: BoundedVec, T::VoterSnapshotPerBlock>, - ) { + fn set_voters(page: PageIndex, voters: VoterPageOf) { PagedVoterSnapshot::::insert(page, voters); } /// Clears all data related to a snapshot. /// - /// At the end of a round, all the snapshot related data must be cleared and the election phase - /// has transitioned to `Phase::Off`. + /// At the end of a round, all the snapshot related data must be cleared. Clearing the + /// snapshot data **MUST* only be performed only during `Phase::Off`. fn kill() { let _ = PagedVoterSnapshot::::clear(u32::MAX, None); - let _ = PagedTargetSnapshot::::clear(u32::MAX, None); + let _ = TargetSnapshot::::kill(); debug_assert_eq!(>::get(), Phase::Off); } - #[allow(dead_code)] #[cfg(any(test, debug_assertions))] + #[allow(dead_code)] pub(crate) fn ensure() -> Result<(), &'static str> { let pages = T::Pages::get(); ensure!(pages > 0, "number pages must be higer than 0."); @@ -537,24 +555,26 @@ impl Pallet { /// Return the most significant page of the snapshot. /// - /// Based on the contract with `ElectionDataProvider`, tis is the first page to be filled. + /// Based on the contract with `ElectionDataProvider`, this is the first page to be requested + /// and filled. pub fn msp() -> PageIndex { T::Pages::get().checked_sub(1).defensive_unwrap_or_default() } /// Return the least significant page of the snapshot. /// - /// Based on the contract with `ElectionDataProvider`, tis is the last page to be filled. + /// Based on the contract with `ElectionDataProvider`, this is the last page to be requested + /// and filled. pub fn lsp() -> PageIndex { Zero::zero() } /// Creates and stores the target snapshot. /// - /// Note: currently, the pallet uses single page target page only. + /// Note: the target snapshot is single paged. fn create_targets_snapshot() -> Result> { let stored_count = Self::create_targets_snapshot_inner(T::TargetSnapshotPerBlock::get())?; - log!(info, "created target snapshot with {} targets.", stored_count); + log!(trace, "created target snapshot with {} targets.", stored_count); Ok(stored_count) } @@ -569,13 +589,10 @@ impl Pallet { let targets: BoundedVec<_, T::TargetSnapshotPerBlock> = T::DataProvider::electable_targets(bounds, Zero::zero()) .and_then(|t| { - t.try_into().map_err(|e| { - log!(error, "too many targets? err: {:?}", e); - "too many targets returned by the data provider." - }) + t.try_into().map_err(|_| "too many targets returned by the data provider.") }) .map_err(|e| { - log!(info, "error fetching electable targets from data provider: {:?}", e); + log!(error, "error fetching electable targets from data provider: {:?}", e); ElectionError::::DataProvider })?; @@ -591,7 +608,7 @@ impl Pallet { let paged_voters_count = Self::create_voters_snapshot_inner(remaining_pages, T::VoterSnapshotPerBlock::get())?; - log!(info, "created voter snapshot with {} voters.", paged_voters_count); + log!(trace, "created voter snapshot with {} voters.", paged_voters_count); Ok(paged_voters_count) } @@ -621,8 +638,9 @@ impl Pallet { /// Tries to progress the snapshot. /// - /// The first (and only) target page is fetched from the [`DataProvider`] at the same block when - /// the msp of the voter snaphot. + /// The first call to this method will calculate and store the (single-paged) target snapshot. + /// The subsequent calls will fetch the voter pages. Thus, the caller must call this method + /// `T::Pages`..0 times. fn try_progress_snapshot(remaining_pages: PageIndex) -> Weight { let _ = ::set_lock(); @@ -636,7 +654,7 @@ impl Pallet { // first block for single target snapshot. match Self::create_targets_snapshot() { Ok(target_count) => { - log!(info, "target snapshot created with {} targets", target_count); + log!(trace, "target snapshot created with {} targets", target_count); Self::phase_transition(Phase::Snapshot(remaining_pages.saturating_sub(1))); T::WeightInfo::create_targets_snapshot_paged(T::TargetSnapshotPerBlock::get()) }, @@ -647,11 +665,11 @@ impl Pallet { }, } } else { - // progress voter snapshot. + // try progress voter snapshot. match Self::create_voters_snapshot(remaining_pages) { Ok(voter_count) => { log!( - info, + trace, "voter snapshot progressed: page {} with {} voters", remaining_pages, voter_count, @@ -668,15 +686,28 @@ impl Pallet { } } + /// Start the signed phase. + /// We expect the snapshot to be ready by now. Thus the the data provider lock should be + /// released and transition to the signed phase. pub(crate) fn start_signed_phase() -> Weight { - // done with the snapshot, release the data provider lock. + debug_assert!(Snapshot::::ensure().is_ok()); + ::unlock(); Self::phase_transition(Phase::Signed); T::WeightInfo::on_initialize_start_signed() } + /// Export phase. + /// + /// In practice, we just need to ensure the export phase does not remain open for too long. + /// During this phase, we expect the external entities to call [`ElectionProvider::elect`] for + /// all the solution pages. Once the least significant page is called, the phase should + /// transition to `Phase::Off`. Thus, if the export phase remains open for too long, it means + /// that the election failed. pub(crate) fn do_export_phase(now: BlockNumberFor, started_at: BlockNumberFor) -> Weight { + debug_assert!(Pallet::::current_phase().is_export()); + if now > started_at + T::ExportPhaseLimit::get() { log!( error, @@ -685,7 +716,7 @@ impl Pallet { ); match ElectionFailure::::get() { - ElectionFailureStrategy::Restart => Self::reset_round(), + ElectionFailureStrategy::Restart => Self::reset_round_restart(), ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), } } @@ -698,6 +729,7 @@ impl Pallet { /// 1. Increment round. /// 2. Change phase to [`Phase::Off`]. /// 3. Clear all snapshot data. + /// 4. Resets verifier. fn rotate_round() { >::mutate(|r| r.defensive_saturating_accrue(1)); Self::phase_transition(Phase::Off); @@ -706,14 +738,18 @@ impl Pallet { ::kill(); } - /// Performs all tasks required after an unsuccessful election: + /// Performs all tasks required after an unsuccessful election which should be self-healing + /// (i.e. the election should restart without entering in emergency phase). + /// + /// Note: the round should not restart as the previous election failed. /// /// 1. Change phase to [`Phase::Off`]. /// 2. Clear all snapshot data. - fn reset_round() { + /// 3. Resets verifier. + fn reset_round_restart() { Self::phase_transition(Phase::Off); - Snapshot::::kill(); + Snapshot::::kill(); ::kill(); } } @@ -727,8 +763,12 @@ impl ElectionProvider for Pallet { type Pages = T::Pages; type DataProvider = T::DataProvider; - /// Important note: we do exect the caller of `elect` to reach page 0. + /// Important note: we do exect the caller of `elect` to call pages down to `lsp == 0`. + /// Otherwise the export phase will not explicitly finish which will result in a failed + /// election. fn elect(remaining: PageIndex) -> Result, Self::Error> { + ensure!(Pallet::::current_phase().is_export(), ElectionError::ElectionNotReady); + T::Verifier::get_queued_solution(remaining) .ok_or(ElectionError::::SupportPageNotAvailable(remaining)) .or_else(|err| { @@ -742,7 +782,7 @@ impl ElectionProvider for Pallet { }) .map(|supports| { if remaining.is_zero() { - log!(info, "elect(): provided the last supports page, rotating round."); + log!(trace, "elect(): provided the last supports page, rotating round."); Self::rotate_round(); } else { // Phase::Export is on while the election is calling all pages of `elect`. @@ -758,7 +798,7 @@ impl ElectionProvider for Pallet { match ElectionFailure::::get() { // force emergency phase for testing. - ElectionFailureStrategy::Restart => Self::reset_round(), + ElectionFailureStrategy::Restart => Self::reset_round_restart(), ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), } err @@ -782,9 +822,6 @@ mod phase_transition { #[test] fn single_page() { - // ---------- ---------- -------------- ----------- - // | | | | | - // Snapshot Signed SignedValidation Unsigned elect() let (mut ext, _) = ExtBuilder::default() .pages(1) .signed_phase(3) @@ -825,16 +862,13 @@ mod phase_transition { let start_unsigned = System::block_number(); assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); - roll_to(next_election + 1); - assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); - - // unsigned phase until elect() is called. - roll_to(next_election + 3); - assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); + // roll to export phase to call elect(). + roll_to_export(); + // elect() should work. assert_ok!(MultiPhase::elect(0)); - // election done, go to off phase. + // one page only -- election done, go to off phase. assert_eq!(>::get(), Phase::Off); }) } @@ -873,6 +907,9 @@ mod phase_transition { roll_to(expected_snapshot + 1); assert_eq!(>::get(), Phase::Snapshot(0)); + // ensure snapshot is sound by end of snapshot phase. + assert_ok!(Snapshot::::ensure()); + roll_to(expected_signed); assert_eq!(>::get(), Phase::Signed); @@ -944,16 +981,26 @@ mod snapshot { #[test] fn setters_getters_work() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().pages(2).build_and_execute(|| { + let t = BoundedVec::<_, _>::try_from(vec![]).unwrap(); let v = BoundedVec::<_, _>::try_from(vec![]).unwrap(); assert!(Snapshot::::targets().is_none()); assert!(Snapshot::::voters(0).is_none()); assert!(Snapshot::::voters(1).is_none()); - Snapshot::::set_targets(v.clone()); + Snapshot::::set_targets(t.clone()); assert!(Snapshot::::targets().is_some()); + Snapshot::::set_voters(0, v.clone()); + Snapshot::::set_voters(1, v.clone()); + + assert!(Snapshot::::voters(0).is_some()); + assert!(Snapshot::::voters(1).is_some()); + + // ensure snapshot is sound. + assert_ok!(Snapshot::::ensure()); + Snapshot::::kill(); assert!(Snapshot::::targets().is_none()); assert!(Snapshot::::voters(0).is_none()); @@ -1088,7 +1135,7 @@ mod election_provider { bounded_vec![10, 20, 30, 40]; let all_voter_pages: BoundedVec< - BoundedVec, VotersPerPage>, + BoundedVec, VotersPerPage>, Pages, > = bounded_vec![ bounded_vec![ diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index eaf5797a5215e..d1b82d3a18877 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -451,7 +451,7 @@ pub(crate) fn roll_to(n: BlockNumber) { // TODO: add try-checks for all pallets here too, as we progress the blocks. log!( - info, + trace, "Block: {}, Phase: {:?}, Round: {:?}, Election at {:?}", bn, >::get(), @@ -468,6 +468,12 @@ pub fn roll_to_phase(phase: Phase) { } } +pub fn roll_to_export() { + while !MultiPhase::current_phase().is_export() { + roll_to(System::block_number() + 1); + } +} + pub fn roll_one_with_ocw(maybe_pool: Option>>) { use sp_runtime::traits::Dispatchable; let bn = System::block_number() + 1; @@ -530,7 +536,7 @@ pub fn assert_snapshots() -> Result<(), &'static str> { pub fn clear_snapshot() { let _ = crate::PagedVoterSnapshot::::clear(u32::MAX, None); - let _ = crate::PagedTargetSnapshot::::clear(u32::MAX, None); + let _ = crate::TargetSnapshot::::kill(); } pub fn balances(who: AccountId) -> (Balance, Balance) { diff --git a/substrate/frame/election-provider-multi-block/src/types.rs b/substrate/frame/election-provider-multi-block/src/types.rs index e903db68e2d77..8f8e95d2a46e4 100644 --- a/substrate/frame/election-provider-multi-block/src/types.rs +++ b/substrate/frame/election-provider-multi-block/src/types.rs @@ -194,6 +194,8 @@ pub enum ElectionError { /// The requested page exceeds the number of election pages defined of the current election /// config. RequestedPageExceeded, + /// Election not ready yet. + ElectionNotReady, /// The fallback election error'ed. Fallback(FallbackErrorOf), } diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs index a83cbdafb09c8..2d5ce0b27d409 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs @@ -607,6 +607,7 @@ impl OffchainWorkerMiner { /// /// Mines a new solution with [`crate::Pallet::Pages`] pages and computes the partial score /// of the page with `page` index. + #[allow(dead_code)] pub fn mine( page: PageIndex, ) -> Result< diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs b/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs index b37cc6bf43459..3464eb0be4536 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs @@ -16,10 +16,7 @@ // limitations under the License. use super::*; -use crate::{ - mock::*, unsigned::miner::Config, PagedTargetSnapshot, PagedVoterSnapshot, Phase, Snapshot, - Verifier, -}; +use crate::{mock::*, PagedVoterSnapshot, Phase, Snapshot, TargetSnapshot, Verifier}; use frame_election_provider_support::ElectionProvider; use frame_support::assert_ok; @@ -59,11 +56,10 @@ mod calls { // roll to election prediction bn. roll_to_with_ocw(election_prediction(), Some(pool.clone())); - // still in unsigned phase (after unsigned submissions have been submitted and before - // the election happened). - assert!(current_phase().is_unsigned()); + // now in the export phase. + assert!(current_phase().is_export()); - // elect() works as expected. + // thus, elect() works as expected. assert!(call_elect().is_ok()); assert_eq!(current_phase(), Phase::Off); @@ -85,11 +81,11 @@ mod calls { // but snapshot exists. assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); - assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_some()); + assert!(TargetSnapshot::::get().is_some()); // so let's clear it. clear_snapshot(); assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_none()); - assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_none()); + assert!(TargetSnapshot::::get().is_none()); // progress through unsigned phase just before the election. roll_to_with_ocw(29, Some(pool.clone())); @@ -108,7 +104,7 @@ mod calls { // snapshot exists now. assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); - assert!(PagedTargetSnapshot::::get(crate::Pallet::::lsp()).is_some()); + assert!(TargetSnapshot::::get().is_some()); roll_to_with_ocw(election_prediction() - 1, Some(pool.clone())); @@ -140,8 +136,6 @@ mod calls { mod miner { use super::*; - type OffchainSolver = ::Solver; - #[test] fn snapshot_idx_based_works() { ExtBuilder::default().build_and_execute(|| { diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs index dc108ec3cdc06..dfcb74cb675e0 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -16,7 +16,7 @@ // limitations under the License. // TODO(gpestana): clean up imports. -use frame_election_provider_support::{NposSolution, PageIndex, TryIntoBoundedSupports}; +use frame_election_provider_support::PageIndex; use frame_support::{ ensure, pallet_prelude::Weight, @@ -29,7 +29,7 @@ use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; use super::*; use pallet::*; -use crate::{helpers, unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; +use crate::{unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; #[frame_support::pallet(dev_mode)] pub(crate) mod pallet { @@ -651,95 +651,9 @@ impl Pallet { Ok(()) } - pub(crate) fn feasibility_check_old( - partial_solution: SolutionOf, - page: PageIndex, - ) -> Result, FeasibilityError> { - // Read the corresponding snapshots. - let snapshot_targets = - crate::Snapshot::::targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - let snapshot_voters = - crate::Snapshot::::voters(page).ok_or(FeasibilityError::SnapshotUnavailable)?; - - let voter_cache = helpers::generate_voter_cache::(&snapshot_voters); - let voter_at = helpers::voter_at_fn::(&snapshot_voters); - let target_at = helpers::target_at_fn::(&snapshot_targets); - let voter_index = helpers::voter_index_fn_usize::(&voter_cache); - - // Then convert solution -> assignment. This will fail if any of the indices are - // gibberish. - let assignments = partial_solution - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - - // Ensure that assignments are all correct. - let _ = assignments - .iter() - .map(|ref assignment| { - // Check that assignment.who is actually a voter (defensive-only). NOTE: while - // using the index map from `voter_index` is better than a blind linear search, - // this *still* has room for optimization. Note that we had the index when we - // did `solution -> assignment` and we lost it. Ideal is to keep the index - // around. - - // Defensive-only: must exist in the snapshot. - let snapshot_index = - voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; - // Defensive-only: index comes from the snapshot, must exist. - let (_voter, _stake, targets) = - snapshot_voters.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; - debug_assert!(*_voter == assignment.who); - - // Check that all of the targets are valid based on the snapshot. - if assignment.distribution.iter().any(|(t, _)| !targets.contains(t)) { - return Err(FeasibilityError::InvalidVote) - } - Ok(()) - }) - .collect::>()?; - - // ----- Start building support. First, we need one more closure. - let stake_of = helpers::stake_of_fn::(&snapshot_voters, &voter_cache); - - // This might fail if the normalization fails. Very unlikely. See `integrity_test`. - let staked_assignments = - sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - - let supports = sp_npos_elections::to_supports(&staked_assignments); - - // Check the maximum number of backers per winner. If this is a single-page solution, this - // is enough to check `MaxBackersPerWinner`. Else, this is just a heuristic, and needs to be - // checked again at the end (via `QueuedSolutionBackings`). - ensure!( - supports - .iter() - .all(|(_, s)| (s.voters.len() as u32) <= T::MaxBackersPerWinner::get()), - FeasibilityError::TooManyBackings - ); - - // Ensure some heuristics. These conditions must hold in the **entire** support, this is - // just a single page. But, they must hold in a single page as well. - let desired_targets = - crate::Snapshot::::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - - // supports per page must not be higher than the desired targets, otherwise final solution - // will also be higher than desired_targets. - ensure!((supports.len() as u32) <= desired_targets, FeasibilityError::WrongWinnerCount); - - // almost-defensive-only: `MaxBackersPerWinner` is already checked. A sane value of - // `MaxWinnersPerPage` should be more than any possible value of `desired_targets()`, which - // is ALSO checked, so this conversion can almost never fail. - let bounded_supports = supports.try_into_bounded_supports().map_err(|e| { - log!(info, "ERR: {:?}", e); - FeasibilityError::WrongWinnerCount - })?; - - Ok(bounded_supports) - } - /// Returns the number backings/pages verified and stored. #[cfg(any(test, feature = "runtime-benchmarks"))] + #[allow(dead_code)] pub(crate) fn pages_backed() -> usize { QueuedSolutionBackings::::iter_keys().count() } From e7bf7dc4ad5c3c0e48c9a5970544e25bd5821940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 18:37:11 +0200 Subject: [PATCH 11/95] rustdocs and nits --- .../src/unsigned/miner.rs | 1 - .../src/unsigned/mod.rs | 7 ++----- .../src/verifier/impls.rs | 15 ++++++--------- .../src/verifier/mod.rs | 7 +++++-- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs index 2d5ce0b27d409..b1ad4f6a2d798 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs @@ -317,7 +317,6 @@ impl Miner { desired_targets: u32, page: PageIndex, ) -> Result, FeasibilityError> { - // TODO: double check page index if tests ERR. let voters_page: BoundedVec, ::VoterSnapshotPerBlock> = voters .get(page as usize) .ok_or(FeasibilityError::Incomplete) diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs index a675907e13e49..55479cfadbedc 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs @@ -78,7 +78,7 @@ use frame_support::{ pallet_prelude::{TransactionValidity, ValidTransaction}, traits::Get, }; -use frame_system::{offchain::SendTransactionTypes, pallet_prelude::BlockNumberFor}; +use frame_system::{ensure_none, offchain::SendTransactionTypes, pallet_prelude::BlockNumberFor}; use sp_npos_elections::ElectionScore; use sp_runtime::SaturatedConversion; @@ -93,10 +93,7 @@ pub(crate) mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::{ - ensure_none, - pallet_prelude::{BlockNumberFor, OriginFor}, - }; + use frame_system::pallet_prelude::OriginFor; #[pallet::config] #[pallet::disable_frame_system_supertrait_check] diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs index dfcb74cb675e0..e2d0085dedbee 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -15,7 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// TODO(gpestana): clean up imports. +use super::*; +use crate::{unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; +use pallet::*; + use frame_election_provider_support::PageIndex; use frame_support::{ ensure, @@ -26,11 +29,6 @@ use frame_support::{ use sp_runtime::{traits::Zero, Perbill}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; -use super::*; -use pallet::*; - -use crate::{unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; - #[frame_support::pallet(dev_mode)] pub(crate) mod pallet { use super::*; @@ -354,7 +352,7 @@ impl Verifier for Pallet { match Self::do_verify_sync(partial_solution, partial_score, page) { Ok(supports) => { sublog!( - info, + trace, "verifier", "queued sync solution with score {:?} (page {:?})", partial_score, @@ -366,7 +364,7 @@ impl Verifier for Pallet { }, Err(err) => { sublog!( - info, + trace, "verifier", "sync verification failed with {:?} (page: {:?})", err, @@ -446,7 +444,6 @@ impl AsyncVerifier for Pallet { fn stop() { sublog!(warn, "verifier", "stop signal received. clearing everything."); - // TODO(gpestana): debug asserts QueuedSolution::::clear_invalid_and_backings(); // if a verification is ongoing, signal the solution rejection to the solution data diff --git a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs index 8b7e095ac6371..04d631af68d8c 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs @@ -71,6 +71,7 @@ pub mod benchmarking; #[cfg(test)] mod tests; +use crate::{PageIndex, SupportsOf}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::traits::Get; use sp_npos_elections::{ElectionScore, ExtendedBalance}; @@ -82,8 +83,6 @@ pub use impls::pallet::{ tt_default_parts_v2, tt_error_token, }; -use crate::{PageIndex, SupportsOf}; - /// Errors related to the solution feasibility checks. #[derive(Debug, Eq, PartialEq, codec::Encode, codec::Decode, scale_info::TypeInfo, Clone)] pub enum FeasibilityError { @@ -136,7 +135,9 @@ impl Default for Status { /// Pointer to the current valid solution of `QueuedSolution`. #[derive(Encode, Decode, scale_info::TypeInfo, Clone, Copy, MaxEncodedLen, Debug, PartialEq)] pub enum SolutionPointer { + /// Solution pointer variant `X`. X, + /// Solution pointer variant `Y`. Y, } @@ -147,6 +148,7 @@ impl Default for SolutionPointer { } impl SolutionPointer { + /// Returns the other variant of the current solution pointer in storage. pub fn other(&self) -> SolutionPointer { match *self { SolutionPointer::X => SolutionPointer::Y, @@ -166,6 +168,7 @@ pub struct PartialBackings { } impl sp_npos_elections::Backings for PartialBackings { + /// Returns the total backings of the winner. fn total(&self) -> ExtendedBalance { self.total } From bf67a3ea112ef9c0bd2e4455965f00450c1d6824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 18:57:18 +0200 Subject: [PATCH 12/95] adds prdoc --- Cargo.lock | 2 +- prdoc/pr_6034.prdoc | 27 +++++++++++++++++++ .../election-provider-multi-block/Cargo.toml | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 prdoc/pr_6034.prdoc diff --git a/Cargo.lock b/Cargo.lock index 6453bdd43feb5..230adcc51494e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11477,7 +11477,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-block" -version = "4.0.0-dev" +version = "1.0.0" dependencies = [ "frame-benchmarking", "frame-election-provider-support", diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc new file mode 100644 index 0000000000000..68ddea76f330c --- /dev/null +++ b/prdoc/pr_6034.prdoc @@ -0,0 +1,27 @@ +title: Adds multi-block election pallet and multi-block types + +doc: + - audience: Runtime Dev + description: | + This PR adds the `election-provider-multi-block` (EPM-MB) pallet, which is the multi-block + variant of the `election-provider-multi-phase` (EPM) pallet. In addition, it refactors the + types and structs required to run an election and updates the EPM, staking pallet and all + dependent pallets to use the multi-block types. + +crates: + - name: frame-election-provider-support + bump: major + - name: pallet-election-provider-multi-phase + bump: major + - name: pallet-election-provider-multi-block + bump: major + - name: pallet-staking + bump: major + - name: pallet-fast-unstake + bump: minor + - name: pallet-delegated-staking + bump: minor + - name: sp-npos-election + bump: major + - name: sp-staking + bump: major diff --git a/substrate/frame/election-provider-multi-block/Cargo.toml b/substrate/frame/election-provider-multi-block/Cargo.toml index e665a714008b5..705161b77ba0f 100644 --- a/substrate/frame/election-provider-multi-block/Cargo.toml +++ b/substrate/frame/election-provider-multi-block/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-election-provider-multi-block" -version = "4.0.0-dev" +version = "1.0.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" From 345840d14617426dca93529fd866a072ae1154b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 18 Oct 2024 19:00:03 +0200 Subject: [PATCH 13/95] fixes prdoc --- prdoc/pr_6034.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index 68ddea76f330c..0b7ea15dc2597 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -21,7 +21,7 @@ crates: bump: minor - name: pallet-delegated-staking bump: minor - - name: sp-npos-election + - name: sp-npos-elections bump: major - name: sp-staking bump: major From 52dcee9652b6874264aa335a622c3ec282b9d92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 19 Oct 2024 00:16:35 +0200 Subject: [PATCH 14/95] removes from all pallets --- .../src/signed/mod.rs | 6 ++- .../src/unsigned/mod.rs | 2 +- .../src/unsigned/weights.rs | 37 +++++++------------ .../src/verifier/impls.rs | 14 ++++--- .../src/weights.rs | 37 +++++++------------ 5 files changed, 43 insertions(+), 53 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs index 3ec1c824597d0..8246511b107da 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -99,7 +99,7 @@ pub struct SubmissionMetadata { deposit: BalanceOf, } -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub mod pallet { use core::marker::PhantomData; @@ -479,6 +479,7 @@ pub mod pallet { /// /// The scores must be kept sorted in the `SortedScores` storage map. #[pallet::call_index(1)] + #[pallet::weight(Weight::default())] pub fn register(origin: OriginFor, claimed_score: ElectionScore) -> DispatchResult { let who = ensure_signed(origin)?; @@ -507,6 +508,7 @@ pub mod pallet { /// TODO: for security reasons, we have to ensure that ALL submitters "space" to /// submit their pages and be verified. #[pallet::call_index(2)] + #[pallet::weight(Weight::default())] pub fn submit_page( origin: OriginFor, page: PageIndex, @@ -541,6 +543,7 @@ pub mod pallet { /// before the signed phase ends. This may end up depriving other honest miners from /// registering their solution. #[pallet::call_index(3)] + #[pallet::weight(Weight::default())] pub fn bail(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -570,6 +573,7 @@ pub mod pallet { /// A successfull call will result in a reward that is taken from the cleared submission /// deposit and the return of the call fees. #[pallet::call_index(4)] + #[pallet::weight(Weight::default())] pub fn force_clear_submission( origin: OriginFor, submitter: T::AccountId, diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs index 55479cfadbedc..ef1180018b311 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs @@ -88,7 +88,7 @@ pub use pallet::{ __substrate_validate_unsigned_check, tt_default_parts, tt_default_parts_v2, tt_error_token, }; -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub(crate) mod pallet { use super::*; diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs b/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs index fc15d96bbae4e..a593dfc8c7d9c 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs @@ -1,28 +1,19 @@ +// This file is part of Substrate. -//! Autogenerated weights for `pallet_epm_unsigned` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-02, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gpestanas-MBP.lan`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 -// Executed Command: -// /Users/gpestana/cargo_target/debug/staking-node -// benchmark -// pallet -// --chain -// dev -// --pallet -// pallet-epm-unsigned -// --extrinsic -// * -// --steps -// 2 -// --repeat -// 1 -// --output -// unsigned_weights.rs +// 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. #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs index e2d0085dedbee..48491cdacae5e 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -29,7 +29,7 @@ use frame_support::{ use sp_runtime::{traits::Zero, Perbill}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; -#[frame_support::pallet(dev_mode)] +#[frame_support::pallet] pub(crate) mod pallet { use super::*; use frame_support::pallet_prelude::{ValueQuery, *}; @@ -282,7 +282,8 @@ pub(crate) mod pallet { // For unsigned page solutions only. #[pallet::storage] - pub(crate) type RemainingUnsignedPages = StorageValue<_, Vec, ValueQuery>; + pub(crate) type RemainingUnsignedPages = + StorageValue<_, BoundedVec, ValueQuery>; #[pallet::pallet] pub struct Pallet(PhantomData); @@ -471,9 +472,12 @@ impl Pallet { match crate::Pallet::::current_phase() { // reset remaining unsigned pages after snapshot is created. crate::Phase::Snapshot(page) if page == crate::Pallet::::lsp() => { - RemainingUnsignedPages::::put( - (crate::Pallet::::lsp()..crate::Pallet::::msp() + 1).collect::>(), - ); + RemainingUnsignedPages::::mutate(|remaining| { + *remaining = BoundedVec::truncate_from( + (crate::Pallet::::lsp()..crate::Pallet::::msp() + 1) + .collect::>(), + ); + }); sublog!( debug, diff --git a/substrate/frame/election-provider-multi-block/src/weights.rs b/substrate/frame/election-provider-multi-block/src/weights.rs index ce764ca6f80b8..f11e82e578b3f 100644 --- a/substrate/frame/election-provider-multi-block/src/weights.rs +++ b/substrate/frame/election-provider-multi-block/src/weights.rs @@ -1,28 +1,19 @@ +// This file is part of Substrate. -//! Autogenerated weights for `pallet_epm_core` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-02, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gpestanas-MBP.lan`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 -// Executed Command: -// /Users/gpestana/cargo_target/debug/staking-node -// benchmark -// pallet -// --chain -// dev -// --pallet -// pallet-epm-core -// --extrinsic -// * -// --steps -// 2 -// --repeat -// 1 -// --output -// core_weights.rs +// 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. #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] From 6d506e2f6c40bbe6f3ea019a357d26b5b26c1016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 19 Oct 2024 01:06:35 +0200 Subject: [PATCH 15/95] Adds new tests for verifier pallet --- .../src/mock/mod.rs | 5 +++ .../src/signed/mod.rs | 5 +-- .../src/unsigned/mod.rs | 4 +- .../src/verifier/impls.rs | 7 +-- .../src/verifier/mod.rs | 5 ++- .../src/verifier/tests.rs | 43 ++++++++++++++++++- 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index d1b82d3a18877..06cfc42e50190 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -323,6 +323,11 @@ impl ExtBuilder { self } + pub(crate) fn solution_improvements_threshold(self, threshold: Perbill) -> Self { + SolutionImprovementThreshold::set(threshold); + self + } + pub(crate) fn verifier() -> Self { ExtBuilder { with_verifier: true } } diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs index 8246511b107da..6426d0cab21e5 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -292,10 +292,9 @@ pub mod pallet { debug_assert!(!SubmissionMetadataStorage::::contains_key(round, who)); // the submission score must be higher than the minimum trusted score. Note that since - // there is no queued solution yet, the check is performed against the minimum score - // only. TODO: consider rename `ensure_score_improves`. + // there is no queued solution yet, the check is performed against the minimum score. ensure!( - ::ensure_score_improves(metadata.claimed_score), + ::ensure_score_quality(metadata.claimed_score), Error::::SubmissionScoreTooLow, ); diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs index ef1180018b311..bd28330000853 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs @@ -313,7 +313,7 @@ impl Pallet { })?; // submit page only if full score improves the current queued score. - if ::ensure_score_improves(full_score) { + if ::ensure_score_quality(full_score) { OffchainWorkerMiner::::submit_paged_call( page, partial_solution, @@ -350,7 +350,7 @@ impl Pallet { ensure!(page <= crate::Pallet::::msp(), ()); // full solution score check. - ensure!(::ensure_score_improves(*claimed_full_score), ()); + ensure!(::ensure_score_quality(*claimed_full_score), ()); Ok(()) } diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs index 48491cdacae5e..c118debfd9074 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs @@ -146,7 +146,6 @@ pub(crate) mod pallet { Self::mutate_checked(|| { QueuedValidVariant::::mutate(|v| *v = v.other()); QueuedSolutionScore::::put(score); - // TODO: should clear the invalid backings too? }) } @@ -324,7 +323,7 @@ impl Verifier for Pallet { QueuedSolution::::queued_score() } - fn ensure_score_improves(claimed_score: ElectionScore) -> bool { + fn ensure_score_quality(claimed_score: ElectionScore) -> bool { Self::ensure_score_quality(claimed_score).is_ok() } @@ -639,6 +638,8 @@ impl Pallet { outcome } + /// Checks if `score` improves the current queued score by `T::SolutionImprovementThreshold` and + /// that it is higher than `MinimumScore`. pub fn ensure_score_quality(score: ElectionScore) -> Result<(), FeasibilityError> { let is_improvement = ::queued_score().map_or(true, |best_score| { score.strict_threshold_better(best_score, T::SolutionImprovementThreshold::get()) @@ -647,8 +648,8 @@ impl Pallet { let is_greater_than_min_trusted = MinimumScore::::get() .map_or(true, |min_score| score.strict_threshold_better(min_score, Perbill::zero())); - ensure!(is_greater_than_min_trusted, FeasibilityError::ScoreTooLow); + ensure!(is_greater_than_min_trusted, FeasibilityError::ScoreTooLow); Ok(()) } diff --git a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs index 04d631af68d8c..47f73bbed861b 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs @@ -198,8 +198,9 @@ pub trait Verifier { /// Returns `None` if not score is queued. fn queued_score() -> Option; - /// Check if a claimed score improves the current queued score. - fn ensure_score_improves(claimed_score: ElectionScore) -> bool; + /// Check if a claimed score improves the current queued score or if it is higher than a + /// potential minimum score. + fn ensure_score_quality(claimed_score: ElectionScore) -> bool; /// Returns the next missing solution page. fn next_missing_solution_page() -> Option; diff --git a/substrate/frame/election-provider-multi-block/src/verifier/tests.rs b/substrate/frame/election-provider-multi-block/src/verifier/tests.rs index 66b4696edf4a7..f0e3663883271 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/tests.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/tests.rs @@ -20,8 +20,49 @@ use crate::{ verifier::{impls::pallet::*, *}, Phase, }; -use frame_support::assert_noop; +use frame_support::{assert_err, assert_noop, assert_ok}; use sp_npos_elections::ElectionScore; +use sp_runtime::Perbill; + +#[test] +fn ensure_score_quality_works() { + ExtBuilder::default() + .solution_improvements_threshold(Perbill::from_percent(10)) + .build_and_execute(|| { + assert_eq!(MinimumScore::::get(), Default::default()); + assert!( as Verifier>::queued_score().is_none()); + + // if minimum score is not set and there's no queued score, any score has quality. + assert_ok!(Pallet::::ensure_score_quality(ElectionScore { + minimal_stake: 1, + sum_stake: 1, + sum_stake_squared: 1 + })); + + // if minimum score is set, the score being evaluated must be higher than the minimum + // score. + MinimumScore::::set( + ElectionScore { minimal_stake: 10, sum_stake: 20, sum_stake_squared: 300 }.into(), + ); + + // score is not higher than minimum score. + assert_err!( + Pallet::::ensure_score_quality(ElectionScore { + minimal_stake: 1, + sum_stake: 1, + sum_stake_squared: 1, + }), + FeasibilityError::ScoreTooLow + ); + + // if score improves the current one by the minimum solution improvement, we're gold. + assert_ok!(Pallet::::ensure_score_quality(ElectionScore { + minimal_stake: 11, + sum_stake: 22, + sum_stake_squared: 300 + })); + }) +} mod solution { use super::*; From 430532a4945519997a33ce20888b69ade9bda993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Sat, 19 Oct 2024 14:42:19 +0200 Subject: [PATCH 16/95] implements hold logic in signed pallet; finishes implementing bail call --- .../src/mock/mod.rs | 10 +- .../src/signed/mod.rs | 165 ++++++++++++------ .../src/signed/tests.rs | 84 ++++++++- 3 files changed, 199 insertions(+), 60 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index 06cfc42e50190..e4c5462e8debc 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -25,7 +25,7 @@ pub use staking::*; use crate::{ self as epm, - signed::{self as signed_pallet}, + signed::{self as signed_pallet, HoldReason}, unsigned::{ self as unsigned_pallet, miner::{self, Miner, MinerError, OffchainWorkerMiner}, @@ -33,7 +33,7 @@ use crate::{ verifier::{self as verifier_pallet}, Config, *, }; -use frame_support::{derive_impl, pallet_prelude::*, parameter_types}; +use frame_support::{derive_impl, pallet_prelude::*, parameter_types, traits::fungible::InspectHold}; use parking_lot::RwLock; use sp_runtime::{ offchain::{ @@ -544,8 +544,12 @@ pub fn clear_snapshot() { let _ = crate::TargetSnapshot::::kill(); } +/// Returns the free balance, and the total on-hold for the election submissions. pub fn balances(who: AccountId) -> (Balance, Balance) { - (Balances::free_balance(who), Balances::reserved_balance(who)) + ( + Balances::free_balance(who), + Balances::balance_on_hold(&HoldReason::ElectionSolutionSubmission.into(), &who), + ) } pub fn mine_full(pages: PageIndex) -> Result, MinerError> { diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs index 6426d0cab21e5..f1eda029f97d0 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -62,10 +62,11 @@ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ traits::{ fungible::{ - hold::Balanced as FnBalanced, Credit, Inspect as FnInspect, MutateHold as FnMutateHold, + hold::Balanced as FnBalanced, Credit, Inspect as FnInspect, + InspectHold as FnInspectHold, MutateHold as FnMutateHold, }, tokens::Precision, - Defensive, + Defensive, DefensiveSaturating, }, RuntimeDebugNoBound, }; @@ -85,6 +86,16 @@ type BalanceOf = <::Currency as FnInspect>>::Bala /// Alias for the pallet's hold credit type. pub type CreditOf = Credit, ::Currency>; +/// Release strategy for currency held by this pallet. +pub(crate) enum ReleaseStrategy { + /// Releases all currency. + All, + /// Releases only the base deposit, + BaseDeposit, + /// Releases only the pages deposit. + PageDeposit, +} + /// Metadata of a registered submission. #[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Default, RuntimeDebugNoBound)] #[cfg_attr(test, derive(frame_support::PartialEqNoBound, frame_support::EqNoBound))] @@ -108,7 +119,7 @@ pub mod pallet { use super::*; use frame_support::{ pallet_prelude::{ValueQuery, *}, - traits::{Defensive, EstimateCallFee, OnUnbalanced}, + traits::{tokens::Fortitude, Defensive, EstimateCallFee, OnUnbalanced}, Twox64Concat, }; use frame_system::{ @@ -127,7 +138,8 @@ pub mod pallet { /// The currency type. type Currency: FnMutateHold - + FnBalanced; + + FnBalanced + + FnInspectHold; /// Something that can predict the fee of a call. Used to sensibly distribute rewards. type EstimateCallFee: EstimateCallFee, BalanceOf>; @@ -137,7 +149,6 @@ pub mod pallet { /// Something that calculates the signed base deposit based on the size of the current /// queued solution proposals. - /// TODO: rename to `Deposit` or other? type DepositBase: Convert>; /// Per-page deposit for a signed solution. @@ -229,6 +240,8 @@ pub mod pallet { SubmissionScoreTooLow, /// Bad timing for force clearing a stored submission. CannotClear, + /// Error releasing held funds. + CannotReleaseFunds, } /// Wrapper for signed submissions. @@ -243,7 +256,12 @@ pub mod pallet { /// ID and round. /// /// Invariants: - /// - TODO + /// - [`SortedScores`] must be strictly sorted or empty. + /// - All registered scores in [`SortedScores`] must be higher than the minimum score. + /// - An entry in [`SortedScores`] for a given round must have an associated entry in + /// [`SubmissionMetadataStorage`]. + /// - For all registered submissions, there is a held deposit that matches that of the + /// submission metadata and the number of submitted pages. pub(crate) struct Submissions(core::marker::PhantomData); impl Submissions { /// Generic mutation helper with checks. @@ -282,7 +300,7 @@ pub mod pallet { round: u32, metadata: SubmissionMetadata, ) -> DispatchResult { - let mut scores = SortedScores::::get(round); + let mut scores = Submissions::::scores_for(round); scores.iter().try_for_each(|(account, _)| -> DispatchResult { ensure!(account != who, Error::::DuplicateRegister); Ok(()) @@ -292,7 +310,8 @@ pub mod pallet { debug_assert!(!SubmissionMetadataStorage::::contains_key(round, who)); // the submission score must be higher than the minimum trusted score. Note that since - // there is no queued solution yet, the check is performed against the minimum score. + // there is no queued solution yet, the check is only performed against the minimum + // score. ensure!( ::ensure_score_quality(metadata.claimed_score), Error::::SubmissionScoreTooLow, @@ -314,7 +333,7 @@ pub mod pallet { Ok(Some((discarded, _s))) => { let _ = SubmissionStorage::::clear_prefix((round, &discarded), u32::MAX, None); - // unreserve deposit + // unreserve full deposit let _ = T::Currency::release_all( &HoldReason::ElectionSolutionSubmission.into(), &who, @@ -327,6 +346,13 @@ pub mod pallet { Err(_) => Err(Error::::SubmissionsQueueFull), }?; + // hold deposit for this submission. + T::Currency::hold( + &HoldReason::ElectionSolutionSubmission.into(), + &who, + metadata.deposit, + )?; + SortedScores::::insert(round, scores); SubmissionMetadataStorage::::insert(round, who, metadata); @@ -355,22 +381,26 @@ pub mod pallet { page: PageIndex, maybe_solution: Option>, ) -> DispatchResult { - ensure!( - crate::Pallet::::current_phase().is_signed(), - Error::::NotAcceptingSubmissions - ); ensure!(page < T::Pages::get(), Error::::BadPageIndex); - ensure!( - SubmissionMetadataStorage::::contains_key(round, who), - Error::::SubmissionNotRegistered - ); + ensure!(Self::metadata_for(round, &who).is_some(), Error::::SubmissionNotRegistered); - // TODO: update the held deposit to account for the paged submission deposit. + let should_hold_extra = + SubmissionStorage::::mutate_exists((round, who, page), |maybe_old_solution| { + let exists = maybe_old_solution.is_some(); + *maybe_old_solution = maybe_solution; - SubmissionStorage::::mutate_exists((round, who, page), |maybe_old_solution| { - *maybe_old_solution = maybe_solution - }); + !exists + }); + + // the deposit per page is held IFF it is a new page being stored. + if should_hold_extra { + T::Currency::hold( + &HoldReason::ElectionSolutionSubmission.into(), + &who, + T::DepositPerPage::get(), + )?; + }; Ok(()) } @@ -388,7 +418,7 @@ pub mod pallet { (round, &submitter), u32::MAX, None, - ); // TODO: handle error. + ); SubmissionMetadataStorage::::take(round, &submitter) .map(|metadata| (submitter, metadata)) @@ -397,23 +427,57 @@ pub mod pallet { }) } - /// Returns the leader submitter for the current round and corresponding claimed score. - pub(crate) fn leader(round: u32) -> Option<(T::AccountId, ElectionScore)> { - SortedScores::::get(round).last().cloned() - } - - /// Returns a submission page for a given round, submitter and page index. - pub(crate) fn get_page( + /// Clear the submission of a registered submission and its correponding pages and release + /// the held deposit based on the `release_strategy`. + /// + /// The held deposit that is not released is burned as a penalty. + pub(crate) fn clear_submission_of( who: &T::AccountId, round: u32, - page: PageIndex, - ) -> Option> { - SubmissionStorage::::get((round, who, page)) + release_strategy: ReleaseStrategy, + ) -> DispatchResult { + let reason = HoldReason::ElectionSolutionSubmission; + + let base_deposit = if let Some(metadata) = Self::metadata_for(round, &who) { + metadata.deposit + } else { + return Err(Error::::SubmissionNotRegistered.into()); + }; + + Self::mutate_checked(round, || { + SubmissionMetadataStorage::::remove(round, who); + let _ = SubmissionStorage::::clear_prefix((round, &who), u32::MAX, None); + }); + + let burn_deposit = match release_strategy { + ReleaseStrategy::All => Zero::zero(), + ReleaseStrategy::BaseDeposit => { + let burn = T::Currency::balance_on_hold(&reason.into(), &who) + .defensive_saturating_sub(base_deposit); + burn + }, + ReleaseStrategy::PageDeposit => base_deposit, + }; + + T::Currency::burn_held( + &reason.into(), + &who, + burn_deposit, + Precision::Exact, + Fortitude::Force, + )?; + + // release remaining. + T::Currency::release_all(&reason.into(), &who, Precision::Exact)?; + + Ok(()) + } + + /// Returns the leader submitter for the current round and corresponding claimed score. + pub(crate) fn leader(round: u32) -> Option<(T::AccountId, ElectionScore)> { + Submissions::::scores_for(round).last().cloned() } - } - #[allow(dead_code)] - impl Submissions { /// Returns the metadata of a submitter for a given account. pub(crate) fn metadata_for( round: u32, @@ -430,17 +494,15 @@ pub mod pallet { } /// Returns the submission of a submitter for a given round and page. - pub(crate) fn submission_for( + pub(crate) fn page_submission_for( who: T::AccountId, round: u32, page: PageIndex, ) -> Option> { SubmissionStorage::::get((round, who, page)) } - } - #[cfg(debug_assertions)] - impl Submissions { + #[cfg(debug_assertions)] fn sanity_check_round(_round: u32) -> Result<(), &'static str> { // TODO Ok(()) @@ -453,12 +515,11 @@ pub mod pallet { claimed_score: ElectionScore, round: u32, ) -> DispatchResult { + // base deposit depends on the number of submissions for the current `round`. let deposit = T::DepositBase::convert( SubmissionMetadataStorage::::iter_key_prefix(round).count(), ); - T::Currency::hold(&HoldReason::ElectionSolutionSubmission.into(), &who, deposit)?; - let pages: BoundedVec<_, T::Pages> = (0..T::Pages::get()) .map(|_| false) .collect::>() @@ -489,7 +550,7 @@ pub mod pallet { let round = crate::Pallet::::current_round(); ensure!( - !SubmissionMetadataStorage::::contains_key(round, who.clone()), + Submissions::::metadata_for(round, &who).is_none(), Error::::DuplicateRegister ); @@ -535,12 +596,10 @@ pub mod pallet { /// Unregister a submission. /// /// This will fully remove the solution and corresponding metadata from storage and refund - /// the submission deposit. + /// the page submissions deposit only. /// - /// NOTE: should we refund the deposit? there's an attack vector where an attacker can - /// register with a set of very high elections core and then retract all submission just - /// before the signed phase ends. This may end up depriving other honest miners from - /// registering their solution. + /// Note: the base deposit will be burned to prevent the attack where rogue submitters + /// deprive honest submitters submitting a solution. #[pallet::call_index(3)] #[pallet::weight(Weight::default())] pub fn bail(origin: OriginFor) -> DispatchResult { @@ -551,14 +610,10 @@ pub mod pallet { Error::::NotAcceptingSubmissions ); - // TODO - // 1. clear all storage items related to `who` - // 2. return deposit + let round = crate::Pallet::::current_round(); + Submissions::::clear_submission_of(&who, round, ReleaseStrategy::PageDeposit)?; - Self::deposit_event(Event::::Bailed { - round: crate::Pallet::::current_round(), - who, - }); + Self::deposit_event(Event::::Bailed { round, who }); Ok(()) } @@ -644,7 +699,7 @@ impl SolutionDataProvider for Pallet { Submissions::::leader(round).map(|(who, _score)| { sublog!(info, "signed", "returning page {} of leader's {:?} solution", page, who); - Submissions::::get_page(&who, round, page).unwrap_or_default() + Submissions::::page_submission_for(who, round, page).unwrap_or_default() }) } diff --git a/substrate/frame/election-provider-multi-block/src/signed/tests.rs b/substrate/frame/election-provider-multi-block/src/signed/tests.rs index 864a94eb1a8c4..665a45d1c73e7 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/tests.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/tests.rs @@ -19,6 +19,7 @@ use super::*; use crate::{mock::*, verifier::SolutionDataProvider, Phase, Verifier}; use frame_support::{assert_noop, assert_ok, testing_prelude::*}; use sp_npos_elections::ElectionScore; +use sp_runtime::traits::Convert; mod calls { use super::*; @@ -179,7 +180,7 @@ mod calls { )); assert_eq!( - Submissions::::submission_for(10, current_round(), 0), + Submissions::::page_submission_for(10, current_round(), 0), Some(Default::default()), ); @@ -206,6 +207,85 @@ mod calls { ); }) } + + #[test] + fn bail_works() { + ExtBuilder::default().build_and_execute(|| { + // TODO + }) + } + + #[test] + fn force_clear_submission_works() { + ExtBuilder::default().build_and_execute(|| { + // TODO + }) + } +} + +mod deposit { + use super::*; + + #[test] + fn register_submit_bail_deposit_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(::Pages::get(), 3); + + roll_to_phase(Phase::Signed); + assert_ok!(assert_snapshots()); + + // expected base deposit with 0 submissions in the queue. + let base_deposit = ::DepositBase::convert(0); + let page_deposit = ::DepositPerPage::get(); + assert!(base_deposit != 0 && page_deposit != 0 && base_deposit != page_deposit); + + // 99 has 100 free balance and 0 held balance for elections. + assert_eq!(balances(99), (100, 0)); + + assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), Default::default())); + + // free balance and held deposit updated as expected. + assert_eq!(balances(99), (100 - base_deposit, base_deposit)); + + // submit page 2. + assert_ok!(SignedPallet::submit_page( + RuntimeOrigin::signed(99), + 2, + Some(Default::default()) + )); + + // free balance and held deposit updated as expected. + assert_eq!( + balances(99), + (100 - base_deposit - page_deposit, base_deposit + page_deposit) + ); + + // submit remaining pages. + assert_ok!(SignedPallet::submit_page( + RuntimeOrigin::signed(99), + 1, + Some(Default::default()) + )); + assert_ok!(SignedPallet::submit_page( + RuntimeOrigin::signed(99), + 0, + Some(Default::default()) + )); + + // free balance and held deposit updated as expected (ie. base_deposit + Pages * + // page_deposit) + assert_eq!( + balances(99), + (100 - base_deposit - (3 * page_deposit), base_deposit + (3 * page_deposit)) + ); + + // now if 99 bails, all the deposits are released. + assert_ok!(SignedPallet::bail(RuntimeOrigin::signed(99))); + + // the base deposit was burned after bail and all the pages deposit were released. + assert_eq!(balances(99), (100 - base_deposit, 0)); + }) + } } mod solution_data_provider { @@ -281,7 +361,7 @@ mod e2e { )); assert_eq!( - Submissions::::submission_for(10, current_round, page), + Submissions::::page_submission_for(10, current_round, page), Some(solution.clone()) ); } From 068e0fd4a23161df2caa2b4bc88ab53f7e12b12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 21 Oct 2024 09:54:00 +0200 Subject: [PATCH 17/95] finishes signed pallet --- .../src/signed/mod.rs | 360 ++++++++++++------ .../src/signed/tests.rs | 20 +- .../src/types.rs | 4 + 3 files changed, 263 insertions(+), 121 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs index f1eda029f97d0..a13c2a105aedc 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/mod.rs @@ -17,33 +17,91 @@ //! # Signed sub-pallet //! -//! The main goal of the signed sub-pallet is to keep and manage a list of sorted score commitments -//! and correponding paged solutions during the [`crate::Phase::Signed`]. +//! The main goal of the signed sub-pallet is to manage a solution submissions from list of sorted +//! score commitments and correponding paged solutions during the [`crate::Phase::Signed`] and to +//! implement the [`SolutionDataProvider`] trait which exposes an interface for external entities to +//! fetch data related to signed submissions for the active round. +//! +//! ## Overview +//! +//! The core logic of this pallet is only active during [`Phase::Signed`]. During the signed phase, +//! accounts can register a solution for the current round and submit the solution's pages, one per +//! extrindic call. The main flow is the following: +//! +//! 1. [`Phase::Signed`] is enacted in the parent EPM pallet; +//! 2. Submitters call [`Call::register`] to register a solution with a given claimed score. This +//! pallet ensures that accepted submission registrations (encapsulated as +//! [`SubmissionMetadata`]) are kept sorted by claimed score in the [`SubmissionMetadata`] +//! storage map. This pallet accepts up to [`Config::MaxSubmissions`] active registrations per +//! round. +//! 3. Submitters that have successfully registered, may submit the solution pages through +//! [`Call::submit_page`], one page per call. +//! 4. Submitters may bail from a registered solution by calling [`Call::bail`]. Bailing from a +//! solution registration will result in a partial slash. +//! 5. This pallet implements the trait [`SolutionDataProvider`] which exposes methods for external +//! entities (e.g. verifier pallet) to query the data and metadata of the current best submitted +//! solution. +//! 6. Upon solution verification (performed by an external entity e.g. the verifier pallet), +//! [`SolutionDataProvider::report_result`] can be called to report the verification result of +//! the current best solution. Depending on the result, the corresponding submitter's deposit may +//! be fully slashed or the submitter may be rewarded with [`Config::Reward`]. //! //! Accounts may submit up to [`Config::MaxSubmissions`] score commitments per election round and //! this pallet ensures that the scores are stored under the map `SortedScores` are sorted and keyed //! by the correct round number. //! -//! Each submitter must hold a deposit per submission that is calculated based on the number of -//! pages required for a full submission and the number of submissions in the queue. The deposit is -//! returned in case the claimed score is correct after the solution verification. Note that if a -//! commitment and corresponding solution are not verified during the verification phase, the -//! submitter is not slashed and the deposits returned. +//! ## Reporting the verification result //! //! When the time to evaluate the signed submission comes, the solutions are checked from best to -//! worse, which may result in one of three scenarios: +//! worse. The [`SolutionDataProvider`] trait exposes the submission data and metadata to an +//! external entity that verifies the queued solutions until it accepts one solution (or none). The +//! verifier entity reports the result of the solution verification which may result in one of three +//! scenarios: +//! +//! 1. If the *best* committed score and page submissions are correct, the submitter is rewarded. +//! 2. Any queued score that was not evaluated, the held deposit is fully returned. +//! 3. Any invalid solution results in a 100% slash of the held deposit. +//! +//! ## Submission deposit +//! +//! Each submitter must hold a "base deposit" per submission that is calculated based on the number +//! of the number of submissions in the queue. In addition, for each solution page submitted there +//! is a fixed [`Config::PageDeposit`] deposit held. The held deposit may be returned or slashed at +//! by the end of the round, depending on the following: +//! +//! 1. If a submission is verified and accepted, the deposit is returned. +//! 2. If a submission is verified and not accepted, the whole deposit is slashed. +//! 3. If a submission is not verified, the deposit is returned. +//! 4. Bailing a registration will return the page deposit and burn the base balance. +//! +//! The deposit is burned when all the data from the submitter is cleared through the +//! [`Call::force_clear_submission`]. +//! +//! ## Submission reward //! -//! 1. If the committed score and page submissions are correct, the submitter is rewarded. -//! 2. Any queued score that was not evaluated, the hold deposit is returned. -//! 3. Any invalid solution results in a 100% slash of the hold submission deposit. +//! Exposing [`SolutionDataProvider::report_result`] allows an external verifier to signal whether +//! the current best solution is correct or not. If the solution is correct, the submitter is +//! rewarded and the pallet can start clearing up the state of the current round. //! -//! Once the [`crate::Phase::SignedValidation`] phase starts, the async verifier is notified to -//! start verifying the best queued solution. +//! ## Storage management //! -//! TODO: -//! - Be more efficient with cleaning up the submission storage by e.g. expose an extrinsic that -//! allows anyone to clean up the submissions storage with a small reward from the submission -//! deposit (clean up storage submissions and all corresponding metadata). +//! ### Storage mutations +//! +//! The [`Submissions`] wraps all the mutation and getters related to the sorted scores, metadata +//! and submissions storage types. All the mutations to those storage items *MUST* be performed +//! through [`Submissions`] to leverage the mutate checks and ensure the data consistency of the +//! submissions data. +//! +//! ### Clearing up the storage +//! +//! The [`SortedScores`] of the *active* submissions in a +//! given round. Each of the registered submissions may have one or more associated paged solution +//! stored in [`SubmissionsStorage`] and its corresponding [`SubmissionMetadata`]. +//! +//! This pallet never implicitly clears either the metadata or the paged submissions storage data. +//! The data is kept in storage until [`Call::force_clear_submission`] extrinsic is called. At that +//! time, the hold deposit may be slashed depending on the state of the `release_strategy` +//! associated with the metadata. #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; @@ -60,13 +118,14 @@ use crate::{ use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + defensive, traits::{ fungible::{ hold::Balanced as FnBalanced, Credit, Inspect as FnInspect, - InspectHold as FnInspectHold, MutateHold as FnMutateHold, + InspectHold as FnInspectHold, Mutate as FnMutate, MutateHold as FnMutateHold, }, tokens::Precision, - Defensive, DefensiveSaturating, + Defensive, DefensiveSaturating, Get, }, RuntimeDebugNoBound, }; @@ -87,13 +146,22 @@ type BalanceOf = <::Currency as FnInspect>>::Bala pub type CreditOf = Credit, ::Currency>; /// Release strategy for currency held by this pallet. +#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, PartialEq)] pub(crate) enum ReleaseStrategy { - /// Releases all currency. + /// Releases all held deposit. All, /// Releases only the base deposit, BaseDeposit, /// Releases only the pages deposit. PageDeposit, + /// Burn all held deposit. + BurnAll, +} + +impl Default for ReleaseStrategy { + fn default() -> Self { + Self::All + } } /// Metadata of a registered submission. @@ -108,6 +176,8 @@ pub struct SubmissionMetadata { pages: BoundedVec>, /// The amount held for this submission. deposit: BalanceOf, + /// Current release strategy for this metadata entry. + release_strategy: ReleaseStrategy, } #[frame_support::pallet] @@ -139,7 +209,8 @@ pub mod pallet { /// The currency type. type Currency: FnMutateHold + FnBalanced - + FnInspectHold; + + FnInspectHold + + FnMutate; /// Something that can predict the fee of a call. Used to sensibly distribute rewards. type EstimateCallFee: EstimateCallFee, BalanceOf>; @@ -182,6 +253,12 @@ pub mod pallet { ValueQuery, >; + /// A double-map from (`round`, `account_id`) to a submission metadata of a registered + /// solution commitment. + #[pallet::storage] + type SubmissionMetadataStorage = + StorageDoubleMap<_, Twox64Concat, u32, Twox64Concat, T::AccountId, SubmissionMetadata>; + /// A triple-map from (round, account, page) to a submitted solution. #[pallet::storage] type SubmissionStorage = StorageNMap< @@ -195,12 +272,6 @@ pub mod pallet { OptionQuery, >; - /// A double-map from (`round`, `account_id`) to a submission metadata of a registered - /// solution commitment. - #[pallet::storage] - type SubmissionMetadataStorage = - StorageDoubleMap<_, Twox64Concat, u32, Twox64Concat, T::AccountId, SubmissionMetadata>; - #[pallet::pallet] pub struct Pallet(PhantomData); @@ -331,8 +402,11 @@ pub mod pallet { Ok(None) => Ok(()), // entry inserted but queue was full, clear the discarded submission. Ok(Some((discarded, _s))) => { - let _ = - SubmissionStorage::::clear_prefix((round, &discarded), u32::MAX, None); + let _ = SubmissionStorage::::clear_prefix( + (round, &discarded), + u32::max_value(), + None, + ); // unreserve full deposit let _ = T::Currency::release_all( &HoldReason::ElectionSolutionSubmission.into(), @@ -405,30 +479,45 @@ pub mod pallet { Ok(()) } - /// Clears all the stored data from the leader. + /// Set metadata for submitter. + pub(crate) fn set_metadata( + round: u32, + who: &T::AccountId, + metadata: SubmissionMetadata, + ) { + debug_assert!(SortedScores::::get(round).iter().any(|(account, _)| who == account)); + + Self::mutate_checked(round, || { + SubmissionMetadataStorage::::insert(round, who, metadata); + }); + } + + /// Clears the leader's score data, effectively disabling the submittion. /// - /// Returns the submission metadata of the cleared submission, if any. - pub(crate) fn take_leader_data( + /// Returns the submission metadata of the disabled. + pub(crate) fn take_leader_score( round: u32, - ) -> Option<(T::AccountId, SubmissionMetadata)> { + ) -> Option<(T::AccountId, Option>)> { Self::mutate_checked(round, || { SortedScores::::mutate(round, |scores| scores.pop()).and_then( - |(submitter, _score)| { - let _ = SubmissionStorage::::clear_prefix( - (round, &submitter), - u32::MAX, - None, - ); - - SubmissionMetadataStorage::::take(round, &submitter) - .map(|metadata| (submitter, metadata)) + |(submitter, _)| { + Some((submitter.clone(), Self::metadata_for(round, &submitter))) }, ) }) } - /// Clear the submission of a registered submission and its correponding pages and release - /// the held deposit based on the `release_strategy`. + /// Clear the registed metadata of a submission and its score and release the held deposit + /// based on the `release_strategy`. + /// + /// Clearing a submission only clears the metadata and stored score of a solution. The + /// paged submissions must be cleared by explicitly calling + /// [`Call::force_clear_submission`]. + /// + /// Note: the deposit can never be released completely or burned completely since + /// an account may have lingering held deposit from previous or subsequent rounds. Thus, the + /// amount to release and burn must always be calculated explicitly based on the round's + /// metadata and release strategy. /// /// The held deposit that is not released is burned as a penalty. pub(crate) fn clear_submission_of( @@ -438,37 +527,41 @@ pub mod pallet { ) -> DispatchResult { let reason = HoldReason::ElectionSolutionSubmission; + // calculates current base held deposit for this round, if any. let base_deposit = if let Some(metadata) = Self::metadata_for(round, &who) { metadata.deposit } else { return Err(Error::::SubmissionNotRegistered.into()); }; + // calculates current held page deposit for this round. + let page_deposit = T::DepositPerPage::get().defensive_saturating_mul( + Submissions::::page_count_submission_for(round, who).into(), + ); + Self::mutate_checked(round, || { SubmissionMetadataStorage::::remove(round, who); - let _ = SubmissionStorage::::clear_prefix((round, &who), u32::MAX, None); + SortedScores::::get(round).retain(|(submitter, _)| submitter != who); }); - let burn_deposit = match release_strategy { - ReleaseStrategy::All => Zero::zero(), - ReleaseStrategy::BaseDeposit => { - let burn = T::Currency::balance_on_hold(&reason.into(), &who) - .defensive_saturating_sub(base_deposit); - burn - }, - ReleaseStrategy::PageDeposit => base_deposit, + let (burn, release) = match release_strategy { + ReleaseStrategy::All => + (Zero::zero(), base_deposit.defensive_saturating_add(page_deposit)), + ReleaseStrategy::BurnAll => + (base_deposit.defensive_saturating_add(page_deposit), Zero::zero()), + ReleaseStrategy::BaseDeposit => (page_deposit, base_deposit), + ReleaseStrategy::PageDeposit => (base_deposit, page_deposit), }; - T::Currency::burn_held( - &reason.into(), - &who, - burn_deposit, - Precision::Exact, - Fortitude::Force, - )?; + T::Currency::burn_held(&reason.into(), who, burn, Precision::Exact, Fortitude::Force)?; - // release remaining. - T::Currency::release_all(&reason.into(), &who, Precision::Exact)?; + T::Currency::release(&reason.into(), who, release, Precision::Exact)?; + + // clear the submission metadata for `who` in `round`. May be a noop. + Self::mutate_checked(round, || { + let _ = SubmissionMetadataStorage::::remove(round, who); + SortedScores::::get(round).retain(|(submitter, _)| submitter != who); + }); Ok(()) } @@ -495,13 +588,17 @@ pub mod pallet { /// Returns the submission of a submitter for a given round and page. pub(crate) fn page_submission_for( - who: T::AccountId, round: u32, + who: T::AccountId, page: PageIndex, ) -> Option> { SubmissionStorage::::get((round, who, page)) } + pub(crate) fn page_count_submission_for(round: u32, who: &T::AccountId) -> u32 { + SubmissionStorage::::iter_key_prefix((round, who)).count() as u32 + } + #[cfg(debug_assertions)] fn sanity_check_round(_round: u32) -> Result<(), &'static str> { // TODO @@ -526,7 +623,13 @@ pub mod pallet { .try_into() .expect("bounded vec constructed from bound; qed."); - let metadata = SubmissionMetadata { pages, claimed_score, deposit }; + let metadata = SubmissionMetadata { + pages, + claimed_score, + deposit, + // new submissions should receive back all held deposit. + release_strategy: ReleaseStrategy::All, + }; let _ = Submissions::::try_register(&who, round, metadata)?; Ok(()) @@ -564,9 +667,6 @@ pub mod pallet { /// /// To submit a solution page successfull, the submitter must have registered the /// commitment before. - /// - /// TODO: for security reasons, we have to ensure that ALL submitters "space" to - /// submit their pages and be verified. #[pallet::call_index(2)] #[pallet::weight(Weight::default())] pub fn submit_page( @@ -618,74 +718,74 @@ pub mod pallet { Ok(()) } - /// Force clean submissions storage. + /// Force clean submissions storage for a given (`sumitter`, `round`) tuple. /// - /// Allows any account to receive a reward for requesting the submission storage and - /// corresponding metadata to be cleaned. This extrinsic will fail if the signed or signed - /// validated phases are active to prevent disruption in the election progress. - /// - /// A successfull call will result in a reward that is taken from the cleared submission - /// deposit and the return of the call fees. + /// This pallet expects that submitted pages for `round` may exist IFF a corresponding + /// metadata exists. #[pallet::call_index(4)] #[pallet::weight(Weight::default())] pub fn force_clear_submission( origin: OriginFor, + round: u32, submitter: T::AccountId, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let _who = ensure_signed(origin); - // prevent cleaning up submissions storage during the signed and signed validation - // phase. - ensure!( - !crate::Pallet::::current_phase().is_signed() && - !crate::Pallet::::current_phase().is_signed_validation_open_at(None), - Error::::CannotClear, - ); + // force clearing submissions may happen only during phase off. + ensure!(crate::Pallet::::current_phase().is_off(), Error::::CannotClear); + + if let Some(metadata) = Submissions::::metadata_for(round, &submitter) { + Submissions::::mutate_checked(round, || { + // clear submission metadata from submitter for `round`. + let _ = Submissions::::clear_submission_of( + &submitter, + round, + metadata.release_strategy, + ); + + // clear all pages from submitter in `round`. + let _ = SubmissionStorage::::clear_prefix( + (round, &submitter), + u32::max_value(), + None, + ); + }); + } else { + debug_assert!( + Submissions::::page_count_submission_for(round, &submitter).is_zero() + ); - // TODO: - // 1. clear the submission, if it exists - // 2. clear the submission metadata - // 3. reward caller as a portions of the submittion's deposit - let reward = Default::default(); - // 4. return fees. + return Err(Error::::CannotClear.into()) + } Self::deposit_event(Event::::SubmissionCleared { round: crate::Pallet::::current_round(), submitter, - reward, + reward: None, }); - Ok(()) + Ok(Pays::No.into()) } } #[pallet::hooks] impl Hooks> for Pallet { /// The `on_initialize` signals the [`AsyncVerifier`] whenever it should start or stop the - /// asynchronous verification of the stored submissions. + /// asynchronous verification of stored submissions. /// /// - Start async verification at the beginning of the [`crate::Phase::SignedValidation`]. - /// - Stopns async verification at the beginning of the [`crate::Phase::Unsigned`]. + /// - Stops async verification at the beginning of the [`crate::Phase::Unsigned`]. fn on_initialize(now: BlockNumberFor) -> Weight { - // TODO: match if crate::Pallet::::current_phase().is_signed_validation_open_at(Some(now)) { + sublog!(debug, "signed", "signed validation phase started, signaling the verifier to start async verifiacton."); let _ = ::start().defensive(); }; if crate::Pallet::::current_phase().is_unsigned_open_at(now) { - sublog!(info, "signed", "signed validation phase ended, signaling the verifier."); + sublog!(debug, "signed", "signed validation phase ended, signaling the verifier to stop async verifiacton."); ::stop(); } - if crate::Pallet::::current_phase() == crate::Phase::Off { - sublog!(info, "signed", "clear up storage for pallets."); - - // TODO: optimize. - let _ = SubmissionMetadataStorage::::clear(u32::MAX, None); - let _ = SubmissionStorage::::clear(u32::MAX, None); - let _ = SortedScores::::clear(u32::MAX, None); - } - Weight::default() } } @@ -694,40 +794,62 @@ pub mod pallet { impl SolutionDataProvider for Pallet { type Solution = SolutionOf; + /// Returns a paged solution of the *best* solution in the queue. fn get_paged_solution(page: PageIndex) -> Option { let round = crate::Pallet::::current_round(); Submissions::::leader(round).map(|(who, _score)| { sublog!(info, "signed", "returning page {} of leader's {:?} solution", page, who); - Submissions::::page_submission_for(who, round, page).unwrap_or_default() + Submissions::::page_submission_for(round, who, page).unwrap_or_default() }) } + /// Returns the score of the *best* solution in the queueu. fn get_score() -> Option { let round = crate::Pallet::::current_round(); Submissions::::leader(round).map(|(_who, score)| score) } + /// Called by an external entity to report a verification result of the current *best* + /// solution. + /// + /// If the verification is rejected, update the leader's metadata to be slashed (i.e. set + /// release strategy to [`ReleaseStrategy::BurnAll`] in the leader's metadata). If successful + /// (represented by the variant [``VerificationResult::Queued]), reward the submitter and + /// signal the verifier to stop the async election verification. fn report_result(result: VerificationResult) { let round = crate::Pallet::::current_round(); - match result { - VerificationResult::Queued => {}, - VerificationResult::Rejected => { - if let Some((_offender, _metadata)) = Submissions::::take_leader_data(round) { - // TODO: slash offender - } else { - // no signed submission in storage, signal async verifier to stop and move on. - let _ = ::stop(); + + let (leader, mut metadata) = + if let Some((leader, maybe_metadata)) = Submissions::::take_leader_score(round) { + let metadata = match maybe_metadata { + Some(m) => m, + None => { + defensive!("unexpected: leader with inconsistent data (no metadata)."); + return; + }, }; + (leader, metadata) + } else { + // TODO(gpestana): turn into defensive. + sublog!(error, "signed", "unexpected: leader called without active submissions."); + return + }; - if crate::Pallet::::current_phase().is_signed_validation_open_at(None) && - Submissions::::leader(round).is_some() - { - let _ = ::start().defensive(); - } + match result { + VerificationResult::Queued => { + // solution was accepted by the verifier, reward leader and stop async + // verification. + // TODO(gpestana): think better about the reward minting process -- should we keep + // a pot for rewards instead of minting it in staking? + let _ = T::Currency::mint_into(&leader, T::Reward::get()).defensive(); + let _ = ::stop(); }, - VerificationResult::DataUnavailable => { - // signed pallet did not have the required data. + VerificationResult::Rejected | VerificationResult::DataUnavailable => { + // updates metadata release strategy so that all the deposit is burned when the + // leader's data is cleared. + metadata.release_strategy = ReleaseStrategy::BurnAll; + Submissions::::set_metadata(round, &leader, metadata); }, } } diff --git a/substrate/frame/election-provider-multi-block/src/signed/tests.rs b/substrate/frame/election-provider-multi-block/src/signed/tests.rs index 665a45d1c73e7..3346c84cc7dcf 100644 --- a/substrate/frame/election-provider-multi-block/src/signed/tests.rs +++ b/substrate/frame/election-provider-multi-block/src/signed/tests.rs @@ -21,6 +21,11 @@ use frame_support::{assert_noop, assert_ok, testing_prelude::*}; use sp_npos_elections::ElectionScore; use sp_runtime::traits::Convert; +#[test] +fn clear_submission_of_works() { + ExtBuilder::default().build_and_execute(|| {}); +} + mod calls { use super::*; use sp_core::bounded_vec; @@ -43,6 +48,7 @@ mod calls { claimed_score: score, deposit: 10, pages: bounded_vec![false, false, false], + release_strategy: Default::default(), } ); @@ -172,6 +178,9 @@ mod calls { let score = ElectionScore { minimal_stake: 10, ..Default::default() }; assert_ok!(SignedPallet::register(RuntimeOrigin::signed(10), score)); + // 0 pages submitted so far. + assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 0); + // now submission works since there is a registered commitment. assert_ok!(SignedPallet::submit_page( RuntimeOrigin::signed(10), @@ -180,16 +189,22 @@ mod calls { )); assert_eq!( - Submissions::::page_submission_for(10, current_round(), 0), + Submissions::::page_submission_for(current_round(), 10, 0), Some(Default::default()), ); + // 1 page submitted so far. + assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 1); + // tries to submit a page out of bounds. assert_noop!( SignedPallet::submit_page(RuntimeOrigin::signed(10), 10, Some(Default::default())), Error::::BadPageIndex, ); + // 1 successful page submitted so far. + assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 1); + assert_eq!( signed_events(), vec![ @@ -345,6 +360,7 @@ mod e2e { claimed_score, deposit: 10, pages: bounded_vec![false, false, false], + release_strategy: Default::default(), }) ); let expected_scores: BoundedVec<(AccountId, ElectionScore), MaxSubmissions> = @@ -361,7 +377,7 @@ mod e2e { )); assert_eq!( - Submissions::::page_submission_for(10, current_round, page), + Submissions::::page_submission_for(current_round, 10, page), Some(solution.clone()) ); } diff --git a/substrate/frame/election-provider-multi-block/src/types.rs b/substrate/frame/election-provider-multi-block/src/types.rs index 8f8e95d2a46e4..7f4c1d2cefdd2 100644 --- a/substrate/frame/election-provider-multi-block/src/types.rs +++ b/substrate/frame/election-provider-multi-block/src/types.rs @@ -153,6 +153,10 @@ impl Default for Phase { } impl Phase { + pub(crate) fn is_off(&self) -> bool { + matches!(self, Phase::Off) + } + pub(crate) fn is_signed(&self) -> bool { matches!(self, Phase::Signed) } From 385500d0904b7009c899905e33b7fbc634e72d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 22 Oct 2024 09:29:36 +0200 Subject: [PATCH 18/95] updates inherent call in unsigned phase to new interfaces --- .../integration-tests/src/mock.rs | 13 ++++++++-- .../src/mock/mod.rs | 19 +++++++++++---- .../src/unsigned/miner.rs | 24 +++++++++---------- .../src/unsigned/mod.rs | 4 ++-- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs index 61ab42251d7c3..66f79c612489f 100644 --- a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs +++ b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs @@ -387,14 +387,23 @@ impl pallet_staking::Config for Runtime { type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + pub struct OnChainSeqPhragmen; parameter_types! { diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs index e4c5462e8debc..3a564adaa515c 100644 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/mock/mod.rs @@ -33,7 +33,9 @@ use crate::{ verifier::{self as verifier_pallet}, Config, *, }; -use frame_support::{derive_impl, pallet_prelude::*, parameter_types, traits::fungible::InspectHold}; +use frame_support::{ + derive_impl, pallet_prelude::*, parameter_types, traits::fungible::InspectHold, +}; use parking_lot::RwLock; use sp_runtime::{ offchain::{ @@ -206,14 +208,23 @@ impl miner::Config for Runtime { pub type Extrinsic = sp_runtime::testing::TestXt; -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = Extrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + Extrinsic::new_bare(call) + } +} + pub struct ConstDepositBase; impl sp_runtime::traits::Convert for ConstDepositBase { fn convert(_a: usize) -> Balance { @@ -490,7 +501,7 @@ pub fn roll_one_with_ocw(maybe_pool: Option>>) { .into_iter() .map(|uxt| ::decode(&mut &*uxt).unwrap()) .for_each(|xt| { - xt.call.dispatch(frame_system::RawOrigin::None.into()).unwrap(); + xt.function.dispatch(frame_system::RawOrigin::None.into()).unwrap(); }); pool.try_write().unwrap().transactions.clear(); } diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs index b1ad4f6a2d798..1a1145b280336 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs @@ -795,17 +795,17 @@ impl OffchainWorkerMiner { ); let call = Call::submit_page_unsigned { page, solution, partial_score, claimed_full_score }; - frame_system::offchain::SubmitTransaction::>::submit_unsigned_transaction( - call.into(), - ) - .map(|_| { - sublog!( - debug, - "unsigned::ocw-miner", - "miner submitted a solution as an unsigned transaction, page {:?}", - page - ); - }) - .map_err(|_| OffchainMinerError::PoolSubmissionFailed) + let xt = T::create_inherent(call.into()); + + frame_system::offchain::SubmitTransaction::>::submit_transaction(xt) + .map(|_| { + sublog!( + debug, + "unsigned::ocw-miner", + "miner submitted a solution as an unsigned transaction, page {:?}", + page + ); + }) + .map_err(|_| OffchainMinerError::PoolSubmissionFailed) } } diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs index bd28330000853..8d3b244b588a0 100644 --- a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs +++ b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs @@ -78,7 +78,7 @@ use frame_support::{ pallet_prelude::{TransactionValidity, ValidTransaction}, traits::Get, }; -use frame_system::{ensure_none, offchain::SendTransactionTypes, pallet_prelude::BlockNumberFor}; +use frame_system::{ensure_none, offchain::CreateInherent, pallet_prelude::BlockNumberFor}; use sp_npos_elections::ElectionScore; use sp_runtime::SaturatedConversion; @@ -97,7 +97,7 @@ pub(crate) mod pallet { #[pallet::config] #[pallet::disable_frame_system_supertrait_check] - pub trait Config: crate::Config + SendTransactionTypes> { + pub trait Config: crate::Config + CreateInherent> { /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; From b4019bb9012f6f14befca10c345f76e77b530b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 22 Oct 2024 09:56:09 +0200 Subject: [PATCH 19/95] licence header nit --- .../src/verifier/weights.rs | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/substrate/frame/election-provider-multi-block/src/verifier/weights.rs b/substrate/frame/election-provider-multi-block/src/verifier/weights.rs index 1fd78c0df43c4..ba9968ec1407b 100644 --- a/substrate/frame/election-provider-multi-block/src/verifier/weights.rs +++ b/substrate/frame/election-provider-multi-block/src/verifier/weights.rs @@ -1,28 +1,19 @@ +// This file is part of Substrate. -//! Autogenerated weights for `pallet_epm_verifier` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-08-06, STEPS: `3`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `gpestanas-MBP.Home`, CPU: `` -//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 -// Executed Command: -// /Users/gpestana/cargo_target/debug/staking-node -// benchmark -// pallet -// --wasm-execution -// compiled -// --pallet -// pallet-epm-verifier -// --extrinsic -// * -// --steps -// 3 -// --repeat -// 1 -// --output -// epm_verifier_weights.rs +// 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. #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] From 82abba1b285c0084af2ead96896836956870f41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 24 Oct 2024 11:12:37 +0200 Subject: [PATCH 20/95] removes epm-mb --- Cargo.lock | 48 - Cargo.toml | 3 - prdoc/pr_6034.prdoc | 10 +- .../election-provider-multi-block/Cargo.toml | 72 - .../election-provider-multi-block/README.md | 1 - .../integration-tests/Cargo.toml | 54 - .../integration-tests/src/lib.rs | 125 -- .../integration-tests/src/mock.rs | 1011 -------------- .../src/benchmarking.rs | 318 ----- .../src/helpers.rs | 331 ----- .../election-provider-multi-block/src/lib.rs | 1193 ----------------- .../src/mock/mod.rs | 624 --------- .../src/mock/staking.rs | 235 ---- .../src/signed/benchmarking.rs | 66 - .../src/signed/mod.rs | 856 ------------ .../src/signed/tests.rs | 405 ------ .../src/types.rs | 261 ---- .../src/unsigned/benchmarking.rs | 88 -- .../src/unsigned/miner.rs | 811 ----------- .../src/unsigned/mod.rs | 357 ----- .../src/unsigned/tests.rs | 210 --- .../src/unsigned/weights.rs | 76 -- .../src/verifier/benchmarking.rs | 315 ----- .../src/verifier/impls.rs | 680 ---------- .../src/verifier/mod.rs | 291 ---- .../src/verifier/tests.rs | 162 --- .../src/verifier/weights.rs | 240 ---- .../src/weights.rs | 179 --- 28 files changed, 3 insertions(+), 9019 deletions(-) delete mode 100644 substrate/frame/election-provider-multi-block/Cargo.toml delete mode 100644 substrate/frame/election-provider-multi-block/README.md delete mode 100644 substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml delete mode 100644 substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs delete mode 100644 substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/benchmarking.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/helpers.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/lib.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/mock/mod.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/mock/staking.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/signed/mod.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/signed/tests.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/types.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/miner.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/mod.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/tests.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/unsigned/weights.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/verifier/impls.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/verifier/mod.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/verifier/tests.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/verifier/weights.rs delete mode 100644 substrate/frame/election-provider-multi-block/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index c94f5df861df4..207fa75e6b8de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11594,27 +11594,6 @@ dependencies = [ "sp-tracing 16.0.0", ] -[[package]] -name = "pallet-election-provider-multi-block" -version = "1.0.0" -dependencies = [ - "frame-benchmarking", - "frame-election-provider-support", - "frame-support", - "frame-system", - "log", - "pallet-balances", - "parity-scale-codec", - "parking_lot 0.12.3", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-npos-elections", - "sp-runtime 31.0.1", - "sp-std 14.0.0", - "sp-tracing 16.0.0", -] - [[package]] name = "pallet-election-provider-multi-phase" version = "27.0.0" @@ -11671,33 +11650,6 @@ dependencies = [ "substrate-test-utils", ] -[[package]] -name = "pallet-epm-mb-integrity-tests" -version = "1.0.0" -dependencies = [ - "frame-election-provider-support", - "frame-support", - "frame-system", - "log", - "pallet-bags-list", - "pallet-balances", - "pallet-election-provider-multi-block", - "pallet-nomination-pools", - "pallet-session", - "pallet-staking", - "pallet-timestamp", - "parity-scale-codec", - "parking_lot 0.12.3", - "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-npos-elections", - "sp-runtime 31.0.1", - "sp-staking", - "sp-std 14.0.0", - "sp-tracing 16.0.0", -] - [[package]] name = "pallet-example-authorization-tx-extension" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 37ccfdf7f56f5..049de32b54cfc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -339,9 +339,7 @@ members = [ "substrate/frame/core-fellowship", "substrate/frame/delegated-staking", "substrate/frame/democracy", - "substrate/frame/election-provider-multi-block", "substrate/frame/election-provider-multi-phase", - "substrate/frame/election-provider-multi-block/integration-tests", "substrate/frame/election-provider-multi-phase/test-staking-e2e", "substrate/frame/election-provider-support", "substrate/frame/election-provider-support/benchmarking", @@ -917,7 +915,6 @@ pallet-default-config-example = { path = "substrate/frame/examples/default-confi pallet-delegated-staking = { path = "substrate/frame/delegated-staking", default-features = false } pallet-democracy = { path = "substrate/frame/democracy", default-features = false } pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features = false } -pallet-election-provider-multi-block = { path = "substrate/frame/election-provider-multi-block", default-features = false } pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index 0b7ea15dc2597..ba3d14326509f 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -1,20 +1,16 @@ -title: Adds multi-block election pallet and multi-block types +title: Adds multi-block election types and refactors current single logic to support it doc: - audience: Runtime Dev description: | - This PR adds the `election-provider-multi-block` (EPM-MB) pallet, which is the multi-block - variant of the `election-provider-multi-phase` (EPM) pallet. In addition, it refactors the - types and structs required to run an election and updates the EPM, staking pallet and all - dependent pallets to use the multi-block types. + This PR adds election types and structs required to run a multi-block election. In additoin, + it EPM, staking pallet and all dependent pallets and logic to use the multi-block types. crates: - name: frame-election-provider-support bump: major - name: pallet-election-provider-multi-phase bump: major - - name: pallet-election-provider-multi-block - bump: major - name: pallet-staking bump: major - name: pallet-fast-unstake diff --git a/substrate/frame/election-provider-multi-block/Cargo.toml b/substrate/frame/election-provider-multi-block/Cargo.toml deleted file mode 100644 index 705161b77ba0f..0000000000000 --- a/substrate/frame/election-provider-multi-block/Cargo.toml +++ /dev/null @@ -1,72 +0,0 @@ -[package] -name = "pallet-election-provider-multi-block" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage = "https://substrate.dev" -repository.workspace = true -description = "FRAME pallet election provider multi-block" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ - "derive", -] } -scale-info = { version = "2.10.0", default-features = false, features = [ - "derive", -] } -log = { version = "0.4.17", default-features = false } - -frame-support = { path = "../support", default-features = false } -frame-system = { path = "../system", default-features = false } -frame-benchmarking = { path = "../benchmarking", default-features = false } - -sp-io = { path = "../../primitives/io", default-features = false } -sp-std = { path = "../../primitives/std", default-features = false } -sp-core = { path = "../../primitives/core", default-features = false } -sp-runtime = { path = "../../primitives/runtime", default-features = false } - -frame-election-provider-support = { default-features = false, path = "../election-provider-support" } -sp-npos-elections = { default-features = false, path = "../../primitives/npos-elections" } - -[dev-dependencies] -sp-tracing = { path = "../../primitives/tracing" } -pallet-balances = { path = "../balances", default-features = false } -parking_lot = "0.12.1" - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-benchmarking/std", - "frame-election-provider-support/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-balances/std", - "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-npos-elections/std", - "sp-runtime/std", - "sp-std/std", -] - -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-election-provider-support/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] - -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-balances/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/substrate/frame/election-provider-multi-block/README.md b/substrate/frame/election-provider-multi-block/README.md deleted file mode 100644 index 9aff2b4bb152a..0000000000000 --- a/substrate/frame/election-provider-multi-block/README.md +++ /dev/null @@ -1 +0,0 @@ -# Election Provider multi-block diff --git a/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml b/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml deleted file mode 100644 index 195e001026000..0000000000000 --- a/substrate/frame/election-provider-multi-block/integration-tests/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "pallet-epm-mb-integrity-tests" -version = "1.0.0" -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" -homepage.workspace = true -repository.workspace = true -description = "FRAME election provider multi block pallet tests with staking pallet, bags-list and session pallets" -publish = false - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dev-dependencies] -parking_lot = { workspace = true, default-features = true } -codec = { features = ["derive"], workspace = true, default-features = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } -log = { workspace = true } - -sp-runtime = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-staking = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -sp-npos-elections = { workspace = true } -sp-tracing = { workspace = true, default-features = true } - -frame-system = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } -frame-election-provider-support = { workspace = true, default-features = true } - -pallet-election-provider-multi-block = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } -pallet-nomination-pools = { workspace = true, default-features = true } -pallet-bags-list = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -pallet-timestamp = { workspace = true, default-features = true } -pallet-session = { workspace = true, default-features = true } - -[features] -try-runtime = [ - "frame-election-provider-support/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-bags-list/try-runtime", - "pallet-balances/try-runtime", - #"pallet-election-provider-multi-block/try-runtime", - "pallet-nomination-pools/try-runtime", - "pallet-session/try-runtime", - "pallet-staking/try-runtime", - "pallet-timestamp/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs deleted file mode 100644 index 3cd56def8e066..0000000000000 --- a/substrate/frame/election-provider-multi-block/integration-tests/src/lib.rs +++ /dev/null @@ -1,125 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![cfg(test)] -mod mock; - -pub(crate) const LOG_TARGET: &str = "integration-tests::epm-staking"; - -use mock::*; - -use frame_election_provider_support::{bounds::ElectionBoundsBuilder, ElectionDataProvider}; - -use frame_support::{assert_ok, traits::UnixTime}; - -// syntactic sugar for logging. -#[macro_export] -macro_rules! log { - ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { - log::$level!( - target: crate::LOG_TARGET, - concat!("🛠️ ", $patter) $(, $values)* - ) - }; -} - -fn log_current_time() { - log!( - info, - "block: {:?}, session: {:?}, era: {:?}, EPM phase: {:?} ts: {:?}", - System::block_number(), - Session::current_index(), - Staking::current_era(), - ElectionProvider::current_phase(), - Timestamp::now() - ); -} - -#[test] -fn block_progression_works() { - let (mut ext, _pool_state, _) = ExtBuilder::default().build_offchainify(); - ext.execute_with(|| {}) -} - -#[test] -fn verify_snapshot() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(Pages::get(), 3); - - // manually get targets and voters from staking to see the inspect the issue with the - // DataProvider. - let bounds = ElectionBoundsBuilder::default() - .targets_count((TargetSnapshotPerBlock::get() as u32).into()) - .voters_count((VoterSnapshotPerBlock::get() as u32).into()) - .build(); - - assert_ok!(::electable_targets(bounds.targets, 2)); - assert_ok!(::electing_voters(bounds.voters, 2)); - }) -} - -mod staking_integration { - use super::*; - use pallet_election_provider_multi_block::Phase; - - #[test] - fn call_elect_multi_block() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(Pages::get(), 3); - assert_eq!(ElectionProvider::current_round(), 0); - assert_eq!(Staking::current_era(), Some(0)); - - let export_starts_at = election_prediction() - Pages::get(); - - assert!(Staking::election_data_lock().is_none()); - - // check that the election data provider lock is set during the snapshot phase and - // released afterwards. - roll_to_phase(Phase::Snapshot(Pages::get() - 1), false); - assert!(Staking::election_data_lock().is_some()); - - roll_one(None, false); - assert!(Staking::election_data_lock().is_some()); - roll_one(None, false); - assert!(Staking::election_data_lock().is_some()); - // snapshot phase done, election data lock was released. - roll_one(None, false); - assert_eq!(ElectionProvider::current_phase(), Phase::Signed); - assert!(Staking::election_data_lock().is_none()); - - // last block where phase is waiting for unsignned submissions. - roll_to(election_prediction() - 4, false); - assert_eq!(ElectionProvider::current_phase(), Phase::Unsigned(17)); - - // staking prepares first page of exposures. - roll_to(export_starts_at, false); - assert_eq!(ElectionProvider::current_phase(), Phase::Export(export_starts_at)); - - // staking prepares second page of exposures. - roll_to(election_prediction() - 2, false); - assert_eq!(ElectionProvider::current_phase(), Phase::Export(export_starts_at)); - - // staking prepares third page of exposures. - roll_to(election_prediction() - 1, false); - - // election successfully, round & era progressed. - assert_eq!(ElectionProvider::current_phase(), Phase::Off); - assert_eq!(ElectionProvider::current_round(), 1); - assert_eq!(Staking::current_era(), Some(1)); - }) - } -} diff --git a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs b/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs deleted file mode 100644 index 66f79c612489f..0000000000000 --- a/substrate/frame/election-provider-multi-block/integration-tests/src/mock.rs +++ /dev/null @@ -1,1011 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -#![allow(dead_code)] - -use frame_support::{ - assert_ok, parameter_types, traits, - traits::{Hooks, VariantCountOf}, - weights::constants, -}; -use frame_system::EnsureRoot; -use sp_core::{ConstU32, Get}; -use sp_npos_elections::VoteWeight; -use sp_runtime::{ - offchain::{ - testing::{OffchainState, PoolState, TestOffchainExt, TestTransactionPoolExt}, - OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, - }, - testing, - traits::Zero, - transaction_validity, BuildStorage, PerU16, Perbill, Percent, -}; -use sp_staking::{ - offence::{OffenceDetails, OnOffenceHandler}, - EraIndex, SessionIndex, -}; -use std::collections::BTreeMap; - -use codec::Decode; -use frame_election_provider_support::{ - bounds::ElectionBoundsBuilder, onchain, ElectionDataProvider, ExtendedBalance, PageIndex, - SequentialPhragmen, Weight, -}; - -use pallet_election_provider_multi_block::{ - self as epm_core_pallet, - signed::{self as epm_signed_pallet}, - unsigned::{self as epm_unsigned_pallet, miner}, - verifier::{self as epm_verifier_pallet}, - Config, Phase, -}; - -use pallet_staking::StakerStatus; -use parking_lot::RwLock; -use std::sync::Arc; - -use frame_support::derive_impl; - -use crate::{log, log_current_time}; - -pub const INIT_TIMESTAMP: BlockNumber = 30_000; -pub const BLOCK_TIME: BlockNumber = 1000; - -type Block = frame_system::mocking::MockBlockU32; -type Extrinsic = testing::TestXt; -pub(crate) type T = Runtime; - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - - // EPM core and sub-pallets - ElectionProvider: epm_core_pallet, - VerifierPallet: epm_verifier_pallet, - SignedPallet: epm_signed_pallet, - UnsignedPallet: epm_unsigned_pallet, - - Pools: pallet_nomination_pools, - Staking: pallet_staking, - Balances: pallet_balances, - BagsList: pallet_bags_list, - Session: pallet_session, - Historical: pallet_session::historical, - Timestamp: pallet_timestamp, - } -); - -pub(crate) type AccountId = u64; -pub(crate) type AccountIndex = u32; -pub(crate) type BlockNumber = u32; -pub(crate) type Balance = u64; -pub(crate) type VoterIndex = u16; -pub(crate) type TargetIndex = u16; -pub(crate) type Moment = u32; - -pub type Solver = SequentialPhragmen; - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] -impl frame_system::Config for Runtime { - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -parameter_types! { - pub static ExistentialDeposit: Balance = 1; - pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults( - Weight::from_parts(2u64 * constants::WEIGHT_REF_TIME_PER_SECOND, u64::MAX), - NORMAL_DISPATCH_RATIO, - ); -} - -#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] -impl pallet_balances::Config for Runtime { - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxFreezes = VariantCountOf; - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; - type FreezeIdentifier = RuntimeFreezeReason; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = Moment; - type OnTimestampSet = (); - type MinimumPeriod = traits::ConstU32<5>; - type WeightInfo = (); -} - -parameter_types! { - pub static Period: u32 = 30; - pub static Offset: u32 = 0; -} - -sp_runtime::impl_opaque_keys! { - pub struct SessionKeys { - pub other: OtherSessionHandler, - } -} - -impl pallet_session::Config for Runtime { - type SessionManager = pallet_session::historical::NoteHistoricalRoot; - type Keys = SessionKeys; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionHandler = (OtherSessionHandler,); - type RuntimeEvent = RuntimeEvent; - type ValidatorId = AccountId; - type ValidatorIdOf = pallet_staking::StashOf; - type WeightInfo = (); -} -impl pallet_session::historical::Config for Runtime { - type FullIdentification = pallet_staking::Exposure; - type FullIdentificationOf = pallet_staking::ExposureOf; -} - -frame_election_provider_support::generate_solution_type!( - #[compact] - pub struct MockNposSolution::< - VoterIndex = VoterIndex, - TargetIndex = TargetIndex, - Accuracy = PerU16, - MaxVoters = ConstU32::<2_000> - >(6) -); - -parameter_types! { - pub static SignedPhase: BlockNumber = 10; - pub static UnsignedPhase: BlockNumber = 10; - pub static SignedValidationPhase: BlockNumber = Pages::get().into(); - pub static Lookhaead: BlockNumber = Pages::get(); - pub static VoterSnapshotPerBlock: VoterIndex = 4; - pub static TargetSnapshotPerBlock: TargetIndex = 8; - pub static Pages: PageIndex = 3; - pub static ExportPhaseLimit: BlockNumber = (Pages::get() * 2u32).into(); - - // TODO: remove what's not needed from here down: - - // we expect a minimum of 3 blocks in signed phase and unsigned phases before trying - // entering in emergency phase after the election failed. - pub static MinBlocksBeforeEmergency: BlockNumber = 3; - #[derive(Debug)] - pub static MaxVotesPerVoter: u32 = 16; - pub static SignedFixedDeposit: Balance = 1; - pub static SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); - pub static ElectionBounds: frame_election_provider_support::bounds::ElectionBounds = ElectionBoundsBuilder::default() - .voters_count(1_000.into()).targets_count(1_000.into()).build(); -} - -pub struct EPMBenchmarkingConfigs; -impl pallet_election_provider_multi_block::BenchmarkingConfig for EPMBenchmarkingConfigs { - const VOTERS: u32 = 100; - const TARGETS: u32 = 50; - const VOTERS_PER_PAGE: [u32; 2] = [1, 5]; - const TARGETS_PER_PAGE: [u32; 2] = [1, 8]; -} - -impl epm_core_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SignedPhase = SignedPhase; - type UnsignedPhase = UnsignedPhase; - type SignedValidationPhase = SignedValidationPhase; - type Lookhaead = Lookhaead; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; - type TargetSnapshotPerBlock = TargetSnapshotPerBlock; - type Pages = Pages; - type ExportPhaseLimit = ExportPhaseLimit; - type MaxWinnersPerPage = MaxWinnersPerPage; - type MaxBackersPerWinner = MaxBackersPerWinner; - type MinerConfig = Self; - type Fallback = frame_election_provider_support::NoElection<( - AccountId, - BlockNumber, - Staking, - MaxWinnersPerPage, - MaxBackersPerWinner, - )>; - type Verifier = VerifierPallet; - type DataProvider = Staking; - type BenchmarkingConfig = EPMBenchmarkingConfigs; - type WeightInfo = (); -} - -parameter_types! { - pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); - pub static MaxWinnersPerPage: u32 = 4; - pub static MaxBackersPerWinner: u32 = 16; -} - -impl epm_verifier_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ForceOrigin = frame_system::EnsureRoot; - type SolutionImprovementThreshold = SolutionImprovementThreshold; - type SolutionDataProvider = SignedPallet; - type WeightInfo = (); -} - -parameter_types! { - pub static DepositBase: Balance = 10; - pub static DepositPerPage: Balance = 1; - pub static Reward: Balance = 10; - pub static MaxSubmissions: u32 = 5; -} - -impl epm_signed_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EstimateCallFee = ConstU32<8>; - type OnSlash = (); // burn - type DepositBase = ConstDepositBase; - type DepositPerPage = DepositPerPage; - type Reward = Reward; - type MaxSubmissions = MaxSubmissions; - type RuntimeHoldReason = RuntimeHoldReason; - type WeightInfo = (); -} - -pub struct ConstDepositBase; -impl sp_runtime::traits::Convert for ConstDepositBase { - fn convert(_a: usize) -> Balance { - DepositBase::get() - } -} - -parameter_types! { - pub static OffchainRepeatInterval: BlockNumber = 0; - pub static TransactionPriority: transaction_validity::TransactionPriority = 1; - pub static MinerMaxLength: u32 = 256; - pub static MinerMaxWeight: Weight = BlockWeights::get().max_block; -} - -impl epm_unsigned_pallet::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OffchainRepeatInterval = OffchainRepeatInterval; - type MinerTxPriority = TransactionPriority; - type MaxLength = MinerMaxLength; - type MaxWeight = MinerMaxWeight; - type WeightInfo = (); -} - -impl miner::Config for Runtime { - type AccountId = AccountId; - type Solution = MockNposSolution; - type Solver = Solver; - type Pages = Pages; - type MaxVotesPerVoter = ConstU32<16>; - type MaxWinnersPerPage = MaxWinnersPerPage; - type MaxBackersPerWinner = MaxBackersPerWinner; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; - type TargetSnapshotPerBlock = TargetSnapshotPerBlock; - type MaxWeight = MinerMaxWeight; - type MaxLength = MinerMaxLength; -} - -const THRESHOLDS: [VoteWeight; 9] = [10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; - -parameter_types! { - pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; - pub const SessionsPerEra: sp_staking::SessionIndex = 2; - pub const BondingDuration: sp_staking::EraIndex = 28; - pub const SlashDeferDuration: sp_staking::EraIndex = 7; // 1/4 the bonding duration. -} - -impl pallet_bags_list::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type ScoreProvider = Staking; - type BagThresholds = BagThresholds; - type Score = VoteWeight; -} - -pub struct BalanceToU256; -impl sp_runtime::traits::Convert for BalanceToU256 { - fn convert(n: Balance) -> sp_core::U256 { - n.into() - } -} - -pub struct U256ToBalance; -impl sp_runtime::traits::Convert for U256ToBalance { - fn convert(n: sp_core::U256) -> Balance { - n.try_into().unwrap() - } -} - -parameter_types! { - pub const PoolsPalletId: frame_support::PalletId = frame_support::PalletId(*b"py/nopls"); - pub static MaxUnbonding: u32 = 8; -} - -impl pallet_nomination_pools::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type RuntimeFreezeReason = RuntimeFreezeReason; - type RewardCounter = sp_runtime::FixedU128; - type BalanceToU256 = BalanceToU256; - type U256ToBalance = U256ToBalance; - type StakeAdapter = pallet_nomination_pools::adapter::TransferStake; - type PostUnbondingPoolsWindow = ConstU32<2>; - type PalletId = PoolsPalletId; - type MaxMetadataLen = ConstU32<256>; - type MaxUnbonding = MaxUnbonding; - type MaxPointsToBalance = frame_support::traits::ConstU8<10>; - type AdminOrigin = frame_system::EnsureRoot; -} - -parameter_types! { - pub static MaxUnlockingChunks: u32 = 32; - pub MaxControllersInDeprecationBatch: u32 = 5900; - pub static MaxValidatorSet: u32 = 500; -} - -/// Upper limit on the number of NPOS nominations. -const MAX_QUOTA_NOMINATIONS: u32 = 16; -/// Disabling factor set explicitly to byzantine threshold -pub(crate) const SLASHING_DISABLING_FACTOR: usize = 3; - -#[derive_impl(pallet_staking::config_preludes::TestDefaultConfig)] -impl pallet_staking::Config for Runtime { - type Currency = Balances; - type CurrencyBalance = Balance; - type UnixTime = Timestamp; - type SessionsPerEra = SessionsPerEra; - type BondingDuration = BondingDuration; - type SlashDeferDuration = SlashDeferDuration; - type AdminOrigin = EnsureRoot; // root can cancel slashes - type SessionInterface = Self; - type EraPayout = (); - type NextNewSession = Session; - type MaxExposurePageSize = ConstU32<256>; - type MaxValidatorSet = MaxValidatorSet; - type ElectionProvider = ElectionProvider; - type GenesisElectionProvider = onchain::OnChainExecution; - type VoterList = BagsList; - type NominationsQuota = pallet_staking::FixedNominationsQuota; - type TargetList = pallet_staking::UseValidatorsMap; - type MaxUnlockingChunks = MaxUnlockingChunks; - type EventListeners = Pools; - type WeightInfo = pallet_staking::weights::SubstrateWeight; - type DisablingStrategy = pallet_staking::UpToLimitDisablingStrategy; - type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; -} - -impl frame_system::offchain::CreateTransactionBase for Runtime -where - RuntimeCall: From, -{ - type RuntimeCall = RuntimeCall; - type Extrinsic = Extrinsic; -} - -impl frame_system::offchain::CreateInherent for Runtime -where - RuntimeCall: From, -{ - fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { - Extrinsic::new_bare(call) - } -} - -pub struct OnChainSeqPhragmen; - -parameter_types! { - pub static VotersBound: u32 = 600; - pub static TargetsBound: u32 = 400; -} - -impl onchain::Config for OnChainSeqPhragmen { - type System = Runtime; - type Solver = Solver; - type DataProvider = Staking; - type WeightInfo = (); - type Bounds = ElectionBounds; - type MaxBackersPerWinner = MaxBackersPerWinner; - type MaxWinnersPerPage = MaxWinnersPerPage; -} - -pub struct OtherSessionHandler; -impl traits::OneSessionHandler for OtherSessionHandler { - type Key = testing::UintAuthorityId; - - fn on_genesis_session<'a, I: 'a>(_: I) - where - I: Iterator, - AccountId: 'a, - { - } - - fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) - where - I: Iterator, - AccountId: 'a, - { - } - - fn on_disabled(_validator_index: u32) {} -} - -impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { - type Public = testing::UintAuthorityId; -} - -pub struct StakingExtBuilder { - validator_count: u32, - minimum_validator_count: u32, - min_nominator_bond: Balance, - min_validator_bond: Balance, - status: BTreeMap>, - stakes: BTreeMap, - stakers: Vec<(AccountId, AccountId, Balance, StakerStatus)>, -} - -impl Default for StakingExtBuilder { - fn default() -> Self { - let stakers = vec![ - // (stash, ctrl, stake, status) - (11, 11, 1000, StakerStatus::::Validator), - (21, 21, 1000, StakerStatus::::Validator), - (31, 31, 500, StakerStatus::::Validator), - (41, 41, 1500, StakerStatus::::Validator), - (51, 51, 1500, StakerStatus::::Validator), - (61, 61, 1500, StakerStatus::::Validator), - (71, 71, 1500, StakerStatus::::Validator), - (81, 81, 1500, StakerStatus::::Validator), - (91, 91, 1500, StakerStatus::::Validator), - (101, 101, 500, StakerStatus::::Validator), - // idle validators - (201, 201, 1000, StakerStatus::::Idle), - (301, 301, 1000, StakerStatus::::Idle), - // nominators - (10, 10, 2000, StakerStatus::::Nominator(vec![11, 21])), - (20, 20, 2000, StakerStatus::::Nominator(vec![31])), - (30, 30, 2000, StakerStatus::::Nominator(vec![91, 101])), - (40, 40, 2000, StakerStatus::::Nominator(vec![11, 101])), - ]; - - Self { - validator_count: 6, - minimum_validator_count: 0, - min_nominator_bond: ExistentialDeposit::get(), - min_validator_bond: ExistentialDeposit::get(), - status: Default::default(), - stakes: Default::default(), - stakers, - } - } -} - -impl StakingExtBuilder { - pub fn validator_count(mut self, n: u32) -> Self { - self.validator_count = n; - self - } -} - -pub struct EpmExtBuilder {} - -impl Default for EpmExtBuilder { - fn default() -> Self { - EpmExtBuilder {} - } -} - -impl EpmExtBuilder { - pub fn disable_emergency_throttling(self) -> Self { - ::set(0); - self - } - - pub fn phases(self, signed: BlockNumber, unsigned: BlockNumber) -> Self { - ::set(signed); - ::set(unsigned); - self - } -} - -pub struct BalancesExtBuilder { - balances: Vec<(AccountId, Balance)>, -} - -impl Default for BalancesExtBuilder { - fn default() -> Self { - let balances = vec![ - // (account_id, balance) - (1, 10), - (2, 20), - (3, 300), - (4, 400), - // nominators - (10, 10_000), - (20, 10_000), - (30, 10_000), - (40, 10_000), - (50, 10_000), - (60, 10_000), - (70, 10_000), - (80, 10_000), - (90, 10_000), - (100, 10_000), - (200, 10_000), - // validators - (11, 1000), - (21, 2000), - (31, 3000), - (41, 4000), - (51, 5000), - (61, 6000), - (71, 7000), - (81, 8000), - (91, 9000), - (101, 10000), - (201, 20000), - (301, 20000), - // This allows us to have a total_payout different from 0. - (999, 1_000_000_000_000), - ]; - Self { balances } - } -} - -pub struct ExtBuilder { - staking_builder: StakingExtBuilder, - epm_builder: EpmExtBuilder, - balances_builder: BalancesExtBuilder, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { - staking_builder: StakingExtBuilder::default(), - epm_builder: EpmExtBuilder::default(), - balances_builder: BalancesExtBuilder::default(), - } - } -} - -impl ExtBuilder { - pub fn build(&self) -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - let _ = pallet_balances::GenesisConfig:: { - balances: self.balances_builder.balances.clone(), - } - .assimilate_storage(&mut storage); - - let mut stakers = self.staking_builder.stakers.clone(); - self.staking_builder.status.clone().into_iter().for_each(|(stash, status)| { - let (_, _, _, ref mut prev_status) = stakers - .iter_mut() - .find(|s| s.0 == stash) - .expect("set_status staker should exist; qed"); - *prev_status = status; - }); - // replaced any of the stakes if needed. - self.staking_builder.stakes.clone().into_iter().for_each(|(stash, stake)| { - let (_, _, ref mut prev_stake, _) = stakers - .iter_mut() - .find(|s| s.0 == stash) - .expect("set_stake staker should exits; qed."); - *prev_stake = stake; - }); - - let _ = pallet_staking::GenesisConfig:: { - stakers: stakers.clone(), - validator_count: self.staking_builder.validator_count, - minimum_validator_count: self.staking_builder.minimum_validator_count, - slash_reward_fraction: Perbill::from_percent(10), - min_nominator_bond: self.staking_builder.min_nominator_bond, - min_validator_bond: self.staking_builder.min_validator_bond, - ..Default::default() - } - .assimilate_storage(&mut storage); - - let _ = pallet_session::GenesisConfig:: { - // set the keys for the first session. - keys: stakers - .into_iter() - .map(|(id, ..)| (id, id, SessionKeys { other: (id as u64).into() })) - .collect(), - ..Default::default() - } - .assimilate_storage(&mut storage); - - let mut ext = sp_io::TestExternalities::from(storage); - - // We consider all test to start after timestamp is initialized This must be ensured by - // having `timestamp::on_initialize` called before `staking::on_initialize`. - ext.execute_with(|| { - System::set_block_number(1); - Session::on_initialize(1); - >::on_initialize(1); - Timestamp::set_timestamp(INIT_TIMESTAMP); - }); - - ext - } - - pub fn staking(mut self, builder: StakingExtBuilder) -> Self { - self.staking_builder = builder; - self - } - - pub fn epm(mut self, builder: EpmExtBuilder) -> Self { - self.epm_builder = builder; - self - } - - pub fn balances(mut self, builder: BalancesExtBuilder) -> Self { - self.balances_builder = builder; - self - } - - pub fn build_offchainify( - self, - ) -> (sp_io::TestExternalities, Arc>, Arc>) { - // add offchain and pool externality extensions. - let mut ext = self.build(); - let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, pool_state) = TestTransactionPoolExt::new(); - - ext.register_extension(OffchainDbExt::new(offchain.clone())); - ext.register_extension(OffchainWorkerExt::new(offchain)); - ext.register_extension(TransactionPoolExt::new(pool)); - - (ext, pool_state, offchain_state) - } - - pub fn build_and_execute(self, test: impl FnOnce() -> ()) { - let mut ext = self.build(); - ext.execute_with(test); - - #[cfg(feature = "try-runtime")] - ext.execute_with(|| { - let bn = System::block_number(); - - assert_ok!(>::try_state(bn)); - assert_ok!(>::try_state(bn)); - assert_ok!(>::try_state(bn)); - }); - } -} - -// Progress to given block, triggering session and era changes as we progress and ensuring that -// there is a solution queued when expected. -pub fn roll_to(n: BlockNumber, delay_solution: bool) { - for b in (System::block_number()) + 1..=n { - System::set_block_number(b); - Session::on_initialize(b); - Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); - - if ElectionProvider::current_phase() == Phase::Signed && !delay_solution { - let _ = try_submit_paged_solution().map_err(|e| { - log!(info, "failed to mine/queue solution: {:?}", e); - }); - }; - - ElectionProvider::on_initialize(b); - VerifierPallet::on_initialize(b); - SignedPallet::on_initialize(b); - UnsignedPallet::on_initialize(b); - - Staking::on_initialize(b); - if b != n { - Staking::on_finalize(System::block_number()); - } - - log_current_time(); - } -} - -// Progress to given block, triggering session and era changes as we progress and ensuring that -// there is a solution queued when expected. -pub fn roll_to_with_ocw(n: BlockNumber, pool: Arc>, delay_solution: bool) { - for b in (System::block_number()) + 1..=n { - System::set_block_number(b); - Session::on_initialize(b); - Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); - - ElectionProvider::on_initialize(b); - VerifierPallet::on_initialize(b); - SignedPallet::on_initialize(b); - UnsignedPallet::on_initialize(b); - - ElectionProvider::offchain_worker(b); - - if !delay_solution && pool.read().transactions.len() > 0 { - // decode submit_unsigned callable that may be queued in the pool by ocw. skip all - // other extrinsics in the pool. - for encoded in &pool.read().transactions { - let _extrinsic = Extrinsic::decode(&mut &encoded[..]).unwrap(); - - // TODO(gpestana): fix when EPM sub-pallets are ready - //let _ = match extrinsic.call { - // RuntimeCall::ElectionProvider( - // call @ Call::submit_unsigned { .. }, - // ) => { - // // call submit_unsigned callable in OCW pool. - // assert_ok!(call.dispatch_bypass_filter(RuntimeOrigin::none())); - // }, - // _ => (), - //}; - } - - pool.try_write().unwrap().transactions.clear(); - } - - Staking::on_initialize(b); - if b != n { - Staking::on_finalize(System::block_number()); - } - - log_current_time(); - } -} -// helper to progress one block ahead. -pub fn roll_one(pool: Option>>, delay_solution: bool) { - let bn = System::block_number().saturating_add(1); - match pool { - None => roll_to(bn, delay_solution), - Some(pool) => roll_to_with_ocw(bn, pool, delay_solution), - } -} - -/// Progresses from the current block number (whatever that may be) to the block where the session -/// `session_index` starts. -pub(crate) fn start_session( - session_index: SessionIndex, - pool: Arc>, - delay_solution: bool, -) { - let end = if Offset::get().is_zero() { - Period::get() * session_index - } else { - Offset::get() * session_index + Period::get() * session_index - }; - - assert!(end >= System::block_number()); - - roll_to_with_ocw(end, pool, delay_solution); - - // session must have progressed properly. - assert_eq!( - Session::current_index(), - session_index, - "current session index = {}, expected = {}", - Session::current_index(), - session_index, - ); -} - -/// Go one session forward. -pub(crate) fn advance_session(pool: Arc>) { - let current_index = Session::current_index(); - start_session(current_index + 1, pool, false); -} - -pub(crate) fn advance_session_delayed_solution(pool: Arc>) { - let current_index = Session::current_index(); - start_session(current_index + 1, pool, true); -} - -pub(crate) fn start_next_active_era(pool: Arc>) -> Result<(), ()> { - start_active_era(active_era() + 1, pool, false) -} - -pub(crate) fn start_next_active_era_delayed_solution( - pool: Arc>, -) -> Result<(), ()> { - start_active_era(active_era() + 1, pool, true) -} - -pub(crate) fn advance_eras(n: usize, pool: Arc>) { - for _ in 0..n { - assert_ok!(start_next_active_era(pool.clone())); - } -} - -/// Progress until the given era. -pub(crate) fn start_active_era( - era_index: EraIndex, - pool: Arc>, - delay_solution: bool, -) -> Result<(), ()> { - let era_before = current_era(); - - start_session((era_index * >::get()).into(), pool, delay_solution); - - log!( - info, - "start_active_era - era_before: {}, current era: {} -> progress to: {} -> after era: {}", - era_before, - active_era(), - era_index, - current_era(), - ); - - // if the solution was not delayed, era should have progressed. - if !delay_solution && (active_era() != era_index || current_era() != active_era()) { - Err(()) - } else { - Ok(()) - } -} - -pub(crate) fn active_era() -> EraIndex { - Staking::active_era().unwrap().index -} - -pub(crate) fn current_era() -> EraIndex { - Staking::current_era().unwrap() -} - -// Fast forward until a given election phase. -pub fn roll_to_phase(phase: Phase, delay: bool) { - while ElectionProvider::current_phase() != phase { - roll_to(System::block_number() + 1, delay); - } -} - -pub fn election_prediction() -> BlockNumber { - <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number(), - ) -} - -parameter_types! { - pub static LastSolutionSubmittedFor: Option = None; -} - -pub(crate) fn try_submit_paged_solution() -> Result<(), ()> { - let submit = || { - // TODO: to finish. - let voters_snapshot = Default::default(); - let targets_snapshot = Default::default(); - let round = Default::default(); - let desired_targets = Default::default(); - - let (paged_solution, _) = - miner::Miner::<::MinerConfig>::mine_paged_solution_with_snapshot( - &voters_snapshot, - &targets_snapshot, - Pages::get(), - round, - desired_targets, - false, - ) - .unwrap(); - - let _ = SignedPallet::register(RuntimeOrigin::signed(10), paged_solution.score).unwrap(); - - for (_idx, _page) in paged_solution.solution_pages.into_iter().enumerate() {} - log!( - info, - "submitter: successfully submitted {} pages with {:?} score in round {}.", - Pages::get(), - paged_solution.score, - ElectionProvider::current_round(), - ); - }; - - match LastSolutionSubmittedFor::get() { - Some(submitted_at) => { - if submitted_at == ElectionProvider::current_round() { - // solution already submitted in this round, do nothing. - } else { - // haven't submit in this round, submit it. - submit() - } - }, - // never submitted, do it. - None => submit(), - }; - LastSolutionSubmittedFor::set(Some(ElectionProvider::current_round())); - - Ok(()) -} - -pub(crate) fn on_offence_now( - offenders: &[OffenceDetails>], - slash_fraction: &[Perbill], -) { - let now = Staking::active_era().unwrap().index; - let _ = Staking::on_offence( - offenders, - slash_fraction, - Staking::eras_start_session_index(now).unwrap(), - ); -} - -// Add offence to validator, slash it. -pub(crate) fn add_slash(who: &AccountId) { - on_offence_now( - &[OffenceDetails { - offender: (*who, Staking::eras_stakers(active_era(), who)), - reporters: vec![], - }], - &[Perbill::from_percent(10)], - ); -} - -// Slashes 1/2 of the active set. Returns the `AccountId`s of the slashed validators. -pub(crate) fn slash_half_the_active_set() -> Vec { - let mut slashed = Session::validators(); - slashed.truncate(slashed.len() / 2); - - for v in slashed.iter() { - add_slash(v); - } - - slashed -} - -// Slashes a percentage of the active nominators that haven't been slashed yet, with -// a minimum of 1 validator slash. -pub(crate) fn slash_percentage(percentage: Perbill) -> Vec { - let validators = Session::validators(); - let mut remaining_slashes = (percentage * validators.len() as u32).max(1); - let mut slashed = vec![]; - - for v in validators.into_iter() { - if remaining_slashes != 0 { - add_slash(&v); - slashed.push(v); - remaining_slashes -= 1; - } - } - slashed -} - -pub(crate) fn set_minimum_election_score( - _minimal_stake: ExtendedBalance, - _sum_stake: ExtendedBalance, - _sum_stake_squared: ExtendedBalance, -) -> Result<(), ()> { - todo!() -} - -pub(crate) fn staked_amount_for(account_id: AccountId) -> Balance { - pallet_staking::asset::staked::(&account_id) -} - -pub(crate) fn staking_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) - .collect::>() -} - -pub(crate) fn epm_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map( - |e| { - if let RuntimeEvent::ElectionProvider(inner) = e { - Some(inner) - } else { - None - } - }, - ) - .collect::>() -} diff --git a/substrate/frame/election-provider-multi-block/src/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/benchmarking.rs deleted file mode 100644 index d0d9a98b6bae3..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/benchmarking.rs +++ /dev/null @@ -1,318 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Benchmarking for the Elections Multiblock pallet and sub-pallets. - -use super::*; -use crate::Snapshot; - -use frame_benchmarking::v2::*; -use frame_support::{assert_ok, traits::OnInitialize}; - -/// Seed to generate account IDs. -const SEED: u32 = 999; -/// Default page to use in the benchmarking. -const PAGE: u32 = 0; -/// Minimum number of voters in the data provider and per snapshot page. -const MIN_VOTERS: u32 = 10; - -#[benchmarks( - where T: ConfigCore + ConfigSigned + ConfigVerifier, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn create_targets_snapshot_paged( - t: Linear< - { T::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { T::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - T::BenchmarkingConfig::VOTERS, - T::BenchmarkingConfig::TARGETS.max(t), - ); - - assert!(Snapshot::::targets().is_none()); - - #[block] - { - assert_ok!(PalletCore::::create_targets_snapshot_inner(t)); - } - - assert!(Snapshot::::targets().is_some()); - - Ok(()) - } - - #[benchmark] - fn create_voters_snapshot_paged( - v: Linear< - { T::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { T::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - T::BenchmarkingConfig::VOTERS.max(v), - T::BenchmarkingConfig::TARGETS, - ); - - assert!(Snapshot::::voters(PAGE).is_none()); - - #[block] - { - assert_ok!(PalletCore::::create_voters_snapshot_inner(PAGE, v)); - } - - assert!(Snapshot::::voters(PAGE).is_some()); - - Ok(()) - } - - #[benchmark] - fn on_initialize_start_signed() -> Result<(), BenchmarkError> { - assert!(PalletCore::::current_phase() == Phase::Off); - - #[block] - { - let _ = PalletCore::::start_signed_phase(); - } - - assert!(PalletCore::::current_phase() == Phase::Signed); - - Ok(()) - } - - #[benchmark] - fn on_phase_transition() -> Result<(), BenchmarkError> { - assert!(PalletCore::::current_phase() == Phase::Off); - - #[block] - { - let _ = PalletCore::::phase_transition(Phase::Snapshot(0)); - } - - assert!(PalletCore::::current_phase() == Phase::Snapshot(0)); - - Ok(()) - } - - #[benchmark] - fn on_initialize_start_export() -> Result<(), BenchmarkError> { - #[block] - { - let _ = PalletCore::::do_export_phase(1u32.into(), 100u32.into()); - } - - Ok(()) - } - - #[benchmark] - fn on_initialize_do_nothing() -> Result<(), BenchmarkError> { - assert!(PalletCore::::current_phase() == Phase::Off); - - #[block] - { - let _ = PalletCore::::on_initialize(0u32.into()); - } - - assert!(PalletCore::::current_phase() == Phase::Off); - - Ok(()) - } - - impl_benchmark_test_suite!( - PalletCore, - crate::mock::ExtBuilder::default(), - crate::mock::Runtime, - exec_name = build_and_execute - ); -} - -/// Helper fns to use across the benchmarking of the core pallet and its sub-pallets. -pub(crate) mod helpers { - use super::*; - use crate::{signed::pallet::Submissions, unsigned::miner::Miner, SolutionOf}; - use frame_election_provider_support::ElectionDataProvider; - use frame_support::traits::tokens::Precision; - use sp_std::vec::Vec; - - pub(crate) fn setup_funded_account( - domain: &'static str, - id: u32, - balance_factor: u32, - ) -> T::AccountId { - use frame_support::traits::fungible::{Balanced, Inspect}; - - let account = frame_benchmarking::account::(domain, id, SEED); - let funds = (T::Currency::minimum_balance() + 1u32.into()) * balance_factor.into(); - // increase issuance to ensure a sane voter weight. - let _ = T::Currency::deposit(&account, funds.into(), Precision::Exact); - - account - } - - /// Generates and adds `v` voters and `t` targets in the data provider stores. The voters - /// nominate `DataProvider::MaxVotesPerVoter` targets. - pub(crate) fn setup_data_provider(v: u32, t: u32) { - ::DataProvider::clear(); - - log!(info, "setup_data_provider with v: {}, t: {}", v, t,); - - // generate and add targets. - let mut targets = (0..t) - .map(|i| { - let target = setup_funded_account::("Target", i, 200); - ::DataProvider::add_target(target.clone()); - target - }) - .collect::>(); - - // we should always have enough voters to fill. - assert!( - targets.len() > - <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter::get() - as usize - ); - - targets.truncate( - <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter::get() as usize, - ); - - // generate and add voters with `MaxVotesPerVoter` nominations from the list of targets. - (0..v.max(MIN_VOTERS)).for_each(|i| { - let voter = setup_funded_account::("Voter", i, 2_000); - <::DataProvider as ElectionDataProvider>::add_voter( - voter, - 1_000, - targets.clone().try_into().unwrap(), - ); - }); - } - - /// Generates the full paged snapshot for both targets and voters. - pub(crate) fn setup_snapshot(v: u32, t: u32) -> Result<(), &'static str> { - // set desired targets to match the size off the target page. - ::set_desired_targets(t); - - log!( - info, - "setting up the snapshot. voters/page: {:?}, targets/page: {:?} (desired_targets: {:?})", - v, - t, - ::desired_targets(), - ); - - let _ = PalletCore::::create_targets_snapshot_inner(t) - .map_err(|_| "error creating the target snapshot, most likely `T::TargetSnapshotPerBlock` config needs to be adjusted")?; - - for page in 0..T::Pages::get() { - let _ = PalletCore::::create_voters_snapshot_inner(page, v) - .map_err(|_| "error creating the voter snapshot, most likely `T::VoterSnapshotPerBlock` config needs to be adjusted")?; - } - - Ok(()) - } - - /// Mines a full solution for the current snapshot and submits `maybe_page`. Otherwise submits - /// all pages. `valid` defines whether the solution is valid or not. - pub(crate) fn mine_and_submit< - T: ConfigCore + ConfigUnsigned + ConfigSigned + ConfigVerifier, - >( - maybe_page: Option, - valid: bool, - ) -> Result { - // ensure that the number of desired targets fits within the bound of max winners per page, - // otherwise preemptively since the feasibilty check will fail. - ensure!( - ::desired_targets() - .expect("desired_targets is set") <= - ::MaxWinnersPerPage::get(), - "`MaxWinnersPerPage` must be equal or higher than desired_targets. fix the configs.", - ); - - let submitter = setup_funded_account::("Submitter", 1, 1_000); - - let (mut solution, _) = - Miner::::mine_paged_solution(T::Pages::get(), true).map_err( - |e| { - log!(info, "ERR:: {:?}", e); - "error mining solution" - }, - )?; - - // if the submission is full and the fesibility check must fail, mess up with the solution's - // claimed score to fail the verification (worst case scenario in terms of async solution - // verification). - let claimed_score = if maybe_page.is_none() && !valid { - solution.score.sum_stake += 1_000_000; - solution.score - } else { - solution.score - }; - - // set transition to phase to ensure the page mutation works. - PalletCore::::phase_transition(Phase::Signed); - - // first register submission. - PalletSigned::::do_register(&submitter, claimed_score, PalletCore::::current_round()) - .map_err(|_| "error registering solution")?; - - for page in maybe_page - .map(|p| sp_std::vec![p]) - .unwrap_or((0..T::Pages::get()).rev().collect::>()) - .into_iter() - { - let paged_solution = - solution.solution_pages.get(page as usize).ok_or("page out of bounds")?; - - // if it is a single page submission and submission should be invalid, make the paged - // paged submission invalid by tweaking the current snapshot. - if maybe_page.is_some() && !valid { - ensure_solution_invalid::(&paged_solution)?; - } - - // process and submit only onle page. - Submissions::::try_mutate_page( - &submitter, - PalletCore::::current_round(), - page, - Some(paged_solution.clone()), - ) - .map_err(|_| "error storing page")?; - } - - Ok(submitter) - } - - /// ensures `solution` will be considered invalid in the feasibility check by tweaking the - /// snapshot which was used to compute the solution and remove one of the targets from the - /// snapshot. NOTE: we expect that the `solution` was generated based on the current snapshot - /// state. - fn ensure_solution_invalid( - solution: &SolutionOf, - ) -> Result<(), &'static str> { - let new_count_targets = solution.unique_targets().len().saturating_sub(1); - - // remove a target from the snapshot to invalidate solution. - let _ = PalletCore::::create_targets_snapshot_inner(new_count_targets as u32) - .map_err(|_| "error regenerating the target snapshot")?; - - Ok(()) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/helpers.rs b/substrate/frame/election-provider-multi-block/src/helpers.rs deleted file mode 100644 index 61c6f0b907ae3..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/helpers.rs +++ /dev/null @@ -1,331 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! Some helper functions/macros for this crate. - -use crate::{ - types::{AllTargetPagesOf, AllVoterPagesOf, MaxWinnersPerPageOf, MinerVoterOf}, - SolutionTargetIndexOf, SolutionVoterIndexOf, -}; -use frame_election_provider_support::{PageIndex, VoteWeight}; -use frame_support::{traits::Get, BoundedVec}; -use sp_runtime::SaturatedConversion; -use sp_std::{cmp::Reverse, collections::btree_map::BTreeMap, vec, vec::Vec}; - -#[macro_export] -macro_rules! log { - ($level:tt, $pattern:expr $(, $values:expr)* $(,)?) => { - log::$level!( - target: $crate::LOG_TARGET, - concat!("[#{:?}]: 🎯🎯🎯 🗳 ", $pattern), >::block_number() $(, $values)* - ) - }; -} - -macro_rules! sublog { - ($level:tt, $sub_pallet:tt, $pattern:expr $(, $values:expr)* $(,)?) => { - #[cfg(not(feature = "std"))] - log!($level, $pattern $(, $values )*); - #[cfg(feature = "std")] - log::$level!( - target: format!("{}::{}", $crate::LOG_TARGET, $sub_pallet).as_ref(), - concat!("[#{:?}]: 🎯🎯🎯 🗳 ", $pattern), >::block_number() $(, $values )* - ) - }; -} - -use crate::unsigned::miner::Config as MinerConfig; - -/// Generate a btree-map cache of the voters and their indices within the provided `snapshot`. -/// -/// This does not care about pagination. `snapshot` might be a single page or the entire blob of -/// voters. -/// -/// This can be used to efficiently build index getter closures. -pub fn generate_voter_cache>( - snapshot: &BoundedVec, AnyBound>, -) -> BTreeMap { - let mut cache: BTreeMap = BTreeMap::new(); - snapshot.iter().enumerate().for_each(|(i, (x, _, _))| { - let _existed = cache.insert(x.clone(), i); - // if a duplicate exists, we only consider the last one. Defensive only, should never - // happen. - debug_assert!(_existed.is_none()); - }); - - cache -} - -pub fn generate_target_cache( - snapshot: &Vec, -) -> BTreeMap { - let mut cache: BTreeMap = BTreeMap::new(); - snapshot.iter().enumerate().for_each(|(i, x)| { - let _existed = cache.insert(x.clone(), i); - // if a duplicate exists, we only consider the last one. Defensive only, should never - // happen. - debug_assert!(_existed.is_none()); - }); - - cache -} - -pub fn generate_voter_staked_cache( - snapshot: &Vec<&MinerVoterOf>, -) -> BTreeMap { - let mut cache: BTreeMap = BTreeMap::new(); - snapshot.into_iter().enumerate().for_each(|(i, (x, _, _))| { - let _existed = cache.insert(x.clone(), i); - // if a duplicate exists, we only consider the last one. Defensive only, should never - // happen. - debug_assert!(_existed.is_none()); - }); - cache -} - -/// Generate an efficient closure of voters and the page in which they live in. -/// -/// The bucketing of voters into a page number is based on their position in the snapshot's page. -pub fn generate_voter_page_fn( - paged_snapshot: &AllVoterPagesOf, -) -> impl Fn(&T::AccountId) -> Option { - let mut cache: BTreeMap = BTreeMap::new(); - paged_snapshot - .iter() - .enumerate() - .map(|(page, whatever)| (page.saturated_into::(), whatever)) - .for_each(|(page, page_voters)| { - page_voters.iter().for_each(|(v, _, _)| { - let _existed = cache.insert(v.clone(), page); - // if a duplicate exists, we only consider the last one. Defensive only, should - // never happen. - debug_assert!(_existed.is_none()); - }); - }); - - move |who| cache.get(who).copied() -} - -pub fn generate_target_page_fn( - paged_snapshot: &AllTargetPagesOf, -) -> impl Fn(&T::AccountId) -> Option { - let mut cache: BTreeMap = BTreeMap::new(); - paged_snapshot - .iter() - .enumerate() - .map(|(page, whatever)| (page.saturated_into::(), whatever)) - .for_each(|(page, page_voters)| { - page_voters.iter().for_each(|t| { - let _existed = cache.insert(t.clone(), page); - // if a duplicate exists, we only consider the last one. Defensive only, should - // never happen. - debug_assert!(_existed.is_none()); - }); - }); - move |who| cache.get(who).copied() -} - -/// stake. -/// -/// The bucketing of voters into a page number is based on their relative stake in the assignments -/// set (the larger the stake, the higher the page). -pub fn generate_voter_page_stake_fn( - paged_snapshot: &AllVoterPagesOf, -) -> impl Fn(&T::AccountId) -> Option { - let mut cache: BTreeMap = BTreeMap::new(); - let mut sorted_by_weight: Vec<(VoteWeight, T::AccountId)> = vec![]; - - // sort voter stakes. - let _ = paged_snapshot.to_vec().iter().flatten().for_each(|voter| { - let pos = sorted_by_weight - .binary_search_by_key(&Reverse(&voter.1), |(weight, _)| Reverse(weight)) - .unwrap_or_else(|pos| pos); - sorted_by_weight.insert(pos, (voter.1, voter.0.clone())); - }); - - sorted_by_weight.iter().enumerate().for_each(|(idx, voter)| { - let page = idx - .saturating_div(MaxWinnersPerPageOf::::get() as usize) - .min(T::Pages::get() as usize); - let _existed = cache.insert(voter.1.clone(), page as PageIndex); - debug_assert!(_existed.is_none()); - }); - - move |who| cache.get(who).copied() -} - -/// Create a function that returns the index of a voter in the snapshot. -/// -/// The returning index type is the same as the one defined in `T::Solution::Voter`. -/// -/// ## Warning -/// -/// Note that this will represent the snapshot data from which the `cache` is generated. -pub fn voter_index_fn( - cache: &BTreeMap, -) -> impl Fn(&T::AccountId) -> Option> + '_ { - move |who| { - cache - .get(who) - .and_then(|i| >>::try_into(*i).ok()) - } -} - -/// Create a function that returns the index of a voter in the snapshot. -/// -/// Same as [`voter_index_fn`] but the returned function owns all its necessary data; nothing is -/// borrowed. -pub fn voter_index_fn_owned( - cache: BTreeMap, -) -> impl Fn(&T::AccountId) -> Option> { - move |who| { - cache - .get(who) - .and_then(|i| >>::try_into(*i).ok()) - } -} - -pub fn target_index_fn_owned( - cache: BTreeMap, -) -> impl Fn(&T::AccountId) -> Option> { - move |who| { - cache - .get(who) - .and_then(|i| >>::try_into(*i).ok()) - } -} - -/// Create a function that returns the index of a target in the snapshot. -/// -/// The returned index type is the same as the one defined in `T::Solution::Target`. -/// -/// Note: to the extent possible, the returned function should be cached and reused. Producing that -/// function requires a `O(n log n)` data transform. Each invocation of that function completes -/// in `O(log n)`. -pub fn target_index_fn( - snapshot: &Vec, -) -> impl Fn(&T::AccountId) -> Option> + '_ { - let cache: BTreeMap<_, _> = - snapshot.iter().enumerate().map(|(idx, account_id)| (account_id, idx)).collect(); - move |who| { - cache - .get(who) - .and_then(|i| >>::try_into(*i).ok()) - } -} - -/// Create a function that can map a voter index ([`SolutionVoterIndexOf`]) to the actual voter -/// account using a linearly indexible snapshot. -pub fn voter_at_fn( - snapshot: &Vec>, -) -> impl Fn(SolutionVoterIndexOf) -> Option + '_ { - move |i| { - as TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot.get(i).map(|(x, _, _)| x).cloned()) - } -} - -/// Create a function that can map a target index ([`SolutionTargetIndexOf`]) to the actual target -/// account using a linearly indexible snapshot. -pub fn target_at_fn( - snapshot: &Vec, -) -> impl Fn(SolutionTargetIndexOf) -> Option + '_ { - move |i| { - as TryInto>::try_into(i) - .ok() - .and_then(|i| snapshot.get(i).cloned()) - } -} - -/// Same as [`voter_index_fn`], but the returning index is converted into usize, if possible. -/// -/// ## Warning -/// -/// Note that this will represent the snapshot data from which the `cache` is generated. -pub fn voter_index_fn_usize( - cache: &BTreeMap, -) -> impl Fn(&T::AccountId) -> Option + '_ { - move |who| cache.get(who).cloned() -} - -pub fn target_index_fn_usize( - cache: &BTreeMap, -) -> impl Fn(&T::AccountId) -> Option + '_ { - move |who| cache.get(who).cloned() -} - -/// Create a function to get the stake of a voter. -pub fn stake_of_fn<'a, T: MinerConfig, AnyBound: Get>( - snapshot: &'a BoundedVec, AnyBound>, - cache: &'a BTreeMap, -) -> impl Fn(&T::AccountId) -> VoteWeight + 'a { - move |who| { - if let Some(index) = cache.get(who) { - snapshot.get(*index).map(|(_, x, _)| x).cloned().unwrap_or_default() - } else { - 0 - } - } -} - -#[cfg(test)] -mod tests { - - use super::*; - use crate::mock::*; - - use sp_runtime::bounded_vec; - - type TargetsPerSnapshotPageOf = ::TargetSnapshotPerBlock; - - #[test] - fn paged_targets_indexing_works() { - ExtBuilder::default().build_and_execute(|| { - let all_target_pages: BoundedVec< - BoundedVec>, - ::Pages, - > = bounded_vec![ - bounded_vec![], // page 0 - bounded_vec![11, 61], // page 1 - bounded_vec![51, 101, 31, 41, 21, 81, 71, 91], // page 2 - ]; - - // flatten all targets. - let all_targets = all_target_pages.iter().cloned().flatten().collect::>(); - - // `targets_index_fn` get the snapshot page of the target. - let targets_index_fn = generate_target_page_fn::(&all_target_pages); - let all_targets_cache = generate_target_cache::(&all_targets); - let target_index = target_index_fn_usize::(&all_targets_cache); - - // check that the `targets_index_page` is correct. - for (page, targets) in all_target_pages.iter().enumerate() { - for t in targets { - assert_eq!(targets_index_fn(&t), Some(page as PageIndex)); - } - } - - // check that the `generate_target_cache` ad `target_index_fn_usize` return the correct - // btree cache/idx. - for (idx, target) in all_targets.iter().enumerate() { - assert_eq!(all_targets_cache.get(target), Some(idx).as_ref()); - assert_eq!(target_index(target), Some(idx)); - } - }) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/lib.rs b/substrate/frame/election-provider-multi-block/src/lib.rs deleted file mode 100644 index 3308c3c261706..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/lib.rs +++ /dev/null @@ -1,1193 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Multi-phase, multi-block election provider pallet -//! -//! This pallet manages the NPoS election across its different phases, with the ability to accept -//! both on-chain and off-chain solutions. The off-chain solutions may be submitted as a signed or -//! unsigned transaction. Crucially, it supports paginated, multi-block elections. The goal of -//! supporting paged elections is to scale the elections linearly with the number of blocks -//! allocated to the election. -//! -//! **PoV-friendly**: The work performed in a block by this pallet must be measurable and the time -//! and computation required per block must be deterministic with regards to the number of voters, -//! targets and any other configurations that are set apriori. These assumptions make this pallet -//! suitable to run on a parachain. -//! -//! ## Pallet organization and sub-pallets -//! -//! This pallet consists of a `core` pallet and multiple sub-pallets. Conceptually, the pallets have -//! a hierarquical relationship, where the `core` pallet sets and manages shared state between all -//! pallets. Its "child" pallets can not depend on the `core` pallet and iteract with it through -//! trait interfaces: -//! -//!```text -//! pallet-core -//! | -//! | -//! - pallet-verifier -//! | -//! - pallet-signed -//! | -//! - pallet-unsigned -//! ``` -//! -//! Each sub-pallet has a specific set of tasks and implement one or more interfaces to expose their -//! functionality to the core pallet: -//! - The [`verifier`] pallet provides an implementation of the [`verifier::Verifier`] trait, which -//! exposes the functionality to verify NPoS solutions in a multi-block context. In addition, it -//! implements [`verifier::AsyncVerifier`] which verifies multi-paged solution asynchronously. -//! - The [`signed`] pallet implements the signed phase, where off-chain entities commit to and -//! submit their election solutions. This pallet implements the -//! [`verifier::SolutionDataProvider`], which is used by the [`verifier`] pallet to fetch solution -//! data to perform the solution verification. -//! - The [`unsigned`] pallet implements the unsigned phase, where block authors can compute and -//! submit through inherent paged solutions. This pallet also implements the -//! [`verifier::SolutionDataProvider`] interface. -//! -//! ### Pallet ordering -//! -//! Due to the assumptions of when the `on_initialize` hook must be called by the executor for the -//! core pallet and each sub-pallets, it is crucial the the pallets are ordered correctly in the -//! construct runtime. The ordering must be the following: -//! -//! ```text -//! 1. pallet-core -//! 2. pallet-verifier -//! 3. pallet-signed -//! 4. pallet-unsigned -//! ``` -//! -//! ## Election Phases -//! -//! This pallet manages the election phases which signal to the other sub-pallets which actions to -//! take at a given block. The election phases are the following: -//! -//! -//! // TODO(gpestana): use a diagram instead of text diagram. -//! ```text -//! // ----------- ----------- -------------- ------------ -------- -//! // | | | | | | | -//! // Off Snapshot Signed SignedValidation Unsigned elect() Export -//! ``` -//! -//! Each phase duration depends on the estimate block number election, which can be fetched from -//! [`pallet::Config::DataProvider`]. -//! -//! TODO(gpestana): finish, add all info related to EPM-MB - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame_election_provider_support::{ - bounds::ElectionBoundsBuilder, BoundedSupportsOf, ElectionDataProvider, ElectionProvider, - LockableElectionDataProvider, PageIndex, Weight, -}; -use frame_support::{ - defensive, ensure, - traits::{Defensive, DefensiveSaturating, Get}, - BoundedVec, -}; -use sp_runtime::traits::{One, Zero}; - -use frame_system::pallet_prelude::BlockNumberFor; - -#[macro_use] -pub mod helpers; - -pub mod signed; -pub mod types; -pub mod unsigned; -pub mod verifier; -pub mod weights; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -#[cfg(test)] -mod mock; - -pub use pallet::*; -pub use types::*; - -pub use crate::{unsigned::miner, verifier::Verifier, weights::WeightInfo}; - -/// Internal crate re-exports to use across benchmarking and tests. -#[cfg(any(test, feature = "runtime-benchmarks"))] -use crate::verifier::Pallet as PalletVerifier; - -/// Log target for this the core EPM-MB pallet. -const LOG_TARGET: &'static str = "runtime::multiblock-election"; - -/// Page configured for the election. -pub type PagesOf = ::Pages; - -/// Trait defining the benchmarking configs. -pub trait BenchmarkingConfig { - /// Range of voters registerd in the system. - const VOTERS: u32; - /// Range of targets registered in the system. - const TARGETS: u32; - /// Range of voters per snapshot page. - const VOTERS_PER_PAGE: [u32; 2]; - /// Range of targets per snapshot page. - const TARGETS_PER_PAGE: [u32; 2]; -} - -#[frame_support::pallet] -pub mod pallet { - - use super::*; - use frame_support::{ - pallet_prelude::{ValueQuery, *}, - sp_runtime::Saturating, - Twox64Concat, - }; - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> - + IsType<::RuntimeEvent> - + TryInto>; - - /// Duration of the signed phase; - /// - /// During the signed phase, staking miners may register their solutions and submit - /// paginated solutions. - #[pallet::constant] - type SignedPhase: Get>; - - /// Duration of the unsigned phase; - /// - /// During the unsigned phase, offchain workers of block producing validators compute and - /// submit paginated solutions. - #[pallet::constant] - type UnsignedPhase: Get>; - - /// Duration of the signed validation phase. - /// - /// During the signed validation phase, the async verifier verifies one or all the queued - /// solution submitions during the signed phase. Once one solution is accepted, this phase - /// terminates. - /// - /// The duration of this phase **SHOULD NOT** be less than `T::Pages` and there is no point - /// in it being more than the maximum number of pages per submission. - #[pallet::constant] - type SignedValidationPhase: Get>; - - /// The limit number of blocks that the `Phase::Export` will be open for. - /// - /// During the export phase, this pallet is open to return paginated, verified solution - /// pages if at least one solution has been verified and accepted in the current era. - /// - /// The export phase will terminate if it has been open for `T::ExportPhaseLimit` blocks or - /// the `EPM::call(0)` is called. - type ExportPhaseLimit: Get>; - - /// The number of blocks that the election should be ready before the election deadline. - #[pallet::constant] - type Lookhaead: Get>; - - /// The number of snapshot voters to fetch per block. - #[pallet::constant] - type VoterSnapshotPerBlock: Get; - - /// The number of snapshot targets to fetch per block. - #[pallet::constant] - type TargetSnapshotPerBlock: Get; - - /// Maximum number of supports (i.e. winners/validators/targets) that can be represented - /// in one page of a solution. - type MaxWinnersPerPage: Get; - - /// Maximum number of voters that can support a single target, across **ALL(()) the solution - /// pages. Thus, this can only be verified when processing the last solution page. - /// - /// This limit must be set so that the memory limits of the rest of the system are - /// respected. - type MaxBackersPerWinner: Get; - - /// The number of pages. - /// - /// A solution may contain at **MOST** this many pages. - #[pallet::constant] - type Pages: Get; - - /// Something that will provide the election data. - type DataProvider: LockableElectionDataProvider< - AccountId = Self::AccountId, - BlockNumber = BlockNumberFor, - >; - - // The miner configuration. - type MinerConfig: miner::Config< - AccountId = AccountIdOf, - Pages = Self::Pages, - MaxVotesPerVoter = ::MaxVotesPerVoter, - TargetSnapshotPerBlock = Self::TargetSnapshotPerBlock, - VoterSnapshotPerBlock = Self::VoterSnapshotPerBlock, - MaxWinnersPerPage = Self::MaxWinnersPerPage, - MaxBackersPerWinner = Self::MaxBackersPerWinner, - >; - - /// Something that implements a fallback election. - /// - /// This provider must run the election in one block, thus it has at most 1 page. - type Fallback: ElectionProvider< - AccountId = Self::AccountId, - BlockNumber = BlockNumberFor, - DataProvider = Self::DataProvider, - MaxWinnersPerPage = ::MaxWinnersPerPage, - MaxBackersPerWinner = ::MaxBackersPerWinner, - Pages = ConstU32<1>, - >; - - /// Something that implements an election solution verifier. - type Verifier: verifier::Verifier< - AccountId = Self::AccountId, - Solution = SolutionOf, - > + verifier::AsyncVerifier; - - /// Benchmarking configurations for this and sub-pallets. - type BenchmarkingConfig: BenchmarkingConfig; - - /// The weights for this pallet. - type WeightInfo: WeightInfo; - } - - // Expose miner configs over the metadata such that they can be re-implemented. - #[pallet::extra_constants] - impl Pallet { - #[pallet::constant_name(MinerMaxVotesPerVoter)] - fn max_votes_per_voter() -> u32 { - ::MaxVotesPerVoter::get() - } - - #[pallet::constant_name(MinerMaxBackersPerWinner)] - fn max_backers_per_winner() -> u32 { - ::MaxBackersPerWinner::get() - } - - #[pallet::constant_name(MinerMaxWinnersPerPage)] - fn max_winners_per_page() -> u32 { - ::MaxWinnersPerPage::get() - } - } - - /// Election failure strategy. - /// - /// This strategy defines the actions of this pallet once an election fails. - #[pallet::storage] - pub(crate) type ElectionFailure = - StorageValue<_, ElectionFailureStrategy, ValueQuery>; - - /// Current phase. - #[pallet::storage] - pub(crate) type CurrentPhase = StorageValue<_, Phase>, ValueQuery>; - - /// Current round. - #[pallet::storage] - pub(crate) type Round = StorageValue<_, u32, ValueQuery>; - - /// Target snapshot. - /// - /// Note: The target snapshot is single-paged. - #[pallet::storage] - pub(crate) type TargetSnapshot = StorageValue<_, TargetPageOf, OptionQuery>; - - /// Paginated voter snapshot. - #[pallet::storage] - pub(crate) type PagedVoterSnapshot = - StorageMap<_, Twox64Concat, PageIndex, VoterPageOf>; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// There was a phase transition in a given round. - PhaseTransitioned { - from: Phase>, - to: Phase>, - round: u32, - }, - } - - #[pallet::error] - pub enum Error {} - - #[pallet::call] - impl Pallet {} - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(now: BlockNumberFor) -> Weight { - // ---------- ---------- ---------- ----------- ---------- -------- - // | | | | | | | - // Off Snapshot (Signed SigValid) Unsigned Export elect() - - let export_deadline = T::ExportPhaseLimit::get().saturating_add(T::Lookhaead::get()); - let unsigned_deadline = export_deadline.saturating_add(T::UnsignedPhase::get()); - let signed_validation_deadline = - unsigned_deadline.saturating_add(T::SignedValidationPhase::get()); - let signed_deadline = signed_validation_deadline.saturating_add(T::SignedPhase::get()); - let snapshot_deadline = signed_deadline - .saturating_add(T::Pages::get().into()) - .saturating_add(One::one()); - - let next_election = T::DataProvider::next_election_prediction(now) - .saturating_sub(T::Lookhaead::get()) - .max(now); - - let remaining_blocks = next_election - now; - let current_phase = Self::current_phase(); - - log!( - trace, - "now {:?} - current phase {:?} | \ - snapshot_deadline: {:?} (at #{:?}), signed_deadline: {:?} (at #{:?}), \ - signed_validation_deadline: {:?} (at #{:?}), unsigned_deadline: {:?} (at #{:?}) \ - export_deadline: {:?} (at #{:?}) - [next election at #{:?}, remaining: {:?}]", - now, - current_phase, - snapshot_deadline, - next_election.saturating_sub(snapshot_deadline), - signed_deadline, - next_election.saturating_sub(signed_deadline), - signed_validation_deadline, - next_election.saturating_sub(signed_validation_deadline), - unsigned_deadline, - next_election.saturating_sub(unsigned_deadline), - export_deadline, - next_election.saturating_sub(export_deadline), - next_election, - remaining_blocks, - ); - - match current_phase { - // start snapshot. - Phase::Off - // allocate one extra block for the (single-page) target snapshot. - if remaining_blocks <= snapshot_deadline && - remaining_blocks > signed_deadline => - Self::try_progress_snapshot(T::Pages::get() + 1), - - // continue snapshot. - Phase::Snapshot(x) if x > 0 => Self::try_progress_snapshot(x.saturating_sub(1)), - - // start unsigned phase if snapshot is ready and signed phase is disabled. - Phase::Snapshot(0) if T::SignedPhase::get().is_zero() => { - Self::phase_transition(Phase::Unsigned(now)); - T::WeightInfo::on_phase_transition() - }, - - // start signed phase. The `signed` sub-pallet will take further actions now. - Phase::Snapshot(0) - if remaining_blocks <= signed_deadline && - remaining_blocks > signed_validation_deadline => - Self::start_signed_phase(), - - // start signed validation. The `signed` sub-pallet will take further actions now. - Phase::Signed - if remaining_blocks <= signed_validation_deadline && - remaining_blocks > unsigned_deadline => - { - Self::phase_transition(Phase::SignedValidation(now)); - T::WeightInfo::on_phase_transition() - }, - - // start unsigned phase. The `unsigned` sub-pallet will take further actions now. - Phase::Signed | Phase::SignedValidation(_) | Phase::Snapshot(0) - if remaining_blocks <= unsigned_deadline && remaining_blocks > Zero::zero() => - { - Self::phase_transition(Phase::Unsigned(now)); - T::WeightInfo::on_phase_transition() - }, - - // start export phase. - Phase::Unsigned(_) if now == next_election.saturating_sub(export_deadline) => { - Self::phase_transition(Phase::Export(now)); - T::WeightInfo::on_phase_transition() - }, - - // election solution **MAY** be ready, start export phase to allow external pallets - // to request paged election solutions. - Phase::Export(started_at) => Self::do_export_phase(now, started_at), - - _ => T::WeightInfo::on_initialize_do_nothing(), - } - } - - fn integrity_test() { - // the signed validator phase must not be less than the number of pages of a - // submission. - assert!( - T::SignedValidationPhase::get() <= T::Pages::get().into(), - "signed validaton phase ({:?}) should not be less than the number of pages per submission ({:?})", - T::SignedValidationPhase::get(), - T::Pages::get(), - ); - } - } - - #[pallet::pallet] - pub struct Pallet(PhantomData); -} - -/// Wrapper struct for working with snapshots. -/// -/// It manages the following storage items: -/// -/// - [`PagedVoterSnapshot`]: Paginated map of voters. -/// - [`TargetSnapshot`]: Single page, bounded list of targets. -/// -/// To ensure correctness and data consistency, all the reads and writes to storage items related -/// to the snapshot and "wrapped" by this struct must be performed through the methods exposed by -/// the implementation of [`Snapshot`]. -pub(crate) struct Snapshot(sp_std::marker::PhantomData); -impl Snapshot { - /// Returns the targets snapshot. - /// - /// The target snapshot is single paged. - fn targets() -> Option> { - TargetSnapshot::::get() - } - - /// Sets a page of targets in the snapshot's storage. - /// - /// The target snapshot is single paged. - fn set_targets(targets: TargetPageOf) { - TargetSnapshot::::set(Some(targets)); - } - - /// Returns whether the target snapshot exists in storage. - fn targets_snapshot_exists() -> bool { - TargetSnapshot::::get().is_some() - } - - /// Returns the number of desired targets, as defined by [`T::DataProvider`]. - fn desired_targets() -> Option { - match T::DataProvider::desired_targets() { - Ok(desired) => Some(desired), - Err(err) => { - defensive!( - "error fetching the desired targets from the election data provider {}", - err - ); - None - }, - } - } - - /// Returns the voters of a specific `page` index of the current snapshot, if any. - fn voters(page: PageIndex) -> Option> { - PagedVoterSnapshot::::get(page) - } - - /// Sets a single page of voters in the snapshot's storage. - fn set_voters(page: PageIndex, voters: VoterPageOf) { - PagedVoterSnapshot::::insert(page, voters); - } - - /// Clears all data related to a snapshot. - /// - /// At the end of a round, all the snapshot related data must be cleared. Clearing the - /// snapshot data **MUST* only be performed only during `Phase::Off`. - fn kill() { - let _ = PagedVoterSnapshot::::clear(u32::MAX, None); - let _ = TargetSnapshot::::kill(); - - debug_assert_eq!(>::get(), Phase::Off); - } - - #[cfg(any(test, debug_assertions))] - #[allow(dead_code)] - pub(crate) fn ensure() -> Result<(), &'static str> { - let pages = T::Pages::get(); - ensure!(pages > 0, "number pages must be higer than 0."); - - // target snapshot exists (one page only); - ensure!(Self::targets().is_some(), "target snapshot does not exist."); - - // ensure that snapshot pages exist as expected. - for page in (crate::Pallet::::lsp()..=crate::Pallet::::msp()).rev() { - ensure!( - Self::voters(page).is_some(), - "at least one page of the snapshot does not exist" - ); - } - - Ok(()) - } -} - -impl Pallet { - /// Return the current election phase. - pub fn current_phase() -> Phase> { - >::get() - } - - /// Return the current election round. - pub fn current_round() -> u32 { - >::get() - } - - /// Phase transition helper. - pub(crate) fn phase_transition(to: Phase>) { - Self::deposit_event(Event::PhaseTransitioned { - from: >::get(), - to, - round: >::get(), - }); - >::put(to); - } - - /// Return the most significant page of the snapshot. - /// - /// Based on the contract with `ElectionDataProvider`, this is the first page to be requested - /// and filled. - pub fn msp() -> PageIndex { - T::Pages::get().checked_sub(1).defensive_unwrap_or_default() - } - - /// Return the least significant page of the snapshot. - /// - /// Based on the contract with `ElectionDataProvider`, this is the last page to be requested - /// and filled. - pub fn lsp() -> PageIndex { - Zero::zero() - } - - /// Creates and stores the target snapshot. - /// - /// Note: the target snapshot is single paged. - fn create_targets_snapshot() -> Result> { - let stored_count = Self::create_targets_snapshot_inner(T::TargetSnapshotPerBlock::get())?; - log!(trace, "created target snapshot with {} targets.", stored_count); - - Ok(stored_count) - } - - fn create_targets_snapshot_inner(targets_per_page: u32) -> Result> { - // set target count bound as the max number of targets per block. - let bounds = ElectionBoundsBuilder::default() - .targets_count(targets_per_page.into()) - .build() - .targets; - - let targets: BoundedVec<_, T::TargetSnapshotPerBlock> = - T::DataProvider::electable_targets(bounds, Zero::zero()) - .and_then(|t| { - t.try_into().map_err(|_| "too many targets returned by the data provider.") - }) - .map_err(|e| { - log!(error, "error fetching electable targets from data provider: {:?}", e); - ElectionError::::DataProvider - })?; - - let count = targets.len() as u32; - Snapshot::::set_targets(targets); - - Ok(count) - } - - /// Creates and store a single page of the voter snapshot. - fn create_voters_snapshot(remaining_pages: u32) -> Result> { - ensure!(remaining_pages < T::Pages::get(), ElectionError::::RequestedPageExceeded); - - let paged_voters_count = - Self::create_voters_snapshot_inner(remaining_pages, T::VoterSnapshotPerBlock::get())?; - log!(trace, "created voter snapshot with {} voters.", paged_voters_count); - - Ok(paged_voters_count) - } - - fn create_voters_snapshot_inner( - remaining_pages: u32, - voters_per_page: u32, - ) -> Result> { - // set voter count bound as the max number of voters per page. - let bounds = ElectionBoundsBuilder::default() - .voters_count(voters_per_page.into()) - .build() - .voters; - - let paged_voters: BoundedVec<_, T::VoterSnapshotPerBlock> = - T::DataProvider::electing_voters(bounds, remaining_pages) - .and_then(|v| { - v.try_into().map_err(|_| "too many voters returned by the data provider") - }) - .map_err(|_| ElectionError::::DataProvider)?; - - let count = paged_voters.len() as u32; - Snapshot::::set_voters(remaining_pages, paged_voters); - - Ok(count) - } - - /// Tries to progress the snapshot. - /// - /// The first call to this method will calculate and store the (single-paged) target snapshot. - /// The subsequent calls will fetch the voter pages. Thus, the caller must call this method - /// `T::Pages`..0 times. - fn try_progress_snapshot(remaining_pages: PageIndex) -> Weight { - let _ = ::set_lock(); - - debug_assert!( - CurrentPhase::::get().is_snapshot() || - !Snapshot::::targets_snapshot_exists() && - remaining_pages == T::Pages::get() + 1, - ); - - if !Snapshot::::targets_snapshot_exists() { - // first block for single target snapshot. - match Self::create_targets_snapshot() { - Ok(target_count) => { - log!(trace, "target snapshot created with {} targets", target_count); - Self::phase_transition(Phase::Snapshot(remaining_pages.saturating_sub(1))); - T::WeightInfo::create_targets_snapshot_paged(T::TargetSnapshotPerBlock::get()) - }, - Err(err) => { - log!(error, "error preparing targets snapshot: {:?}", err); - // TODO: T::WeightInfo::snapshot_error(); - Weight::default() - }, - } - } else { - // try progress voter snapshot. - match Self::create_voters_snapshot(remaining_pages) { - Ok(voter_count) => { - log!( - trace, - "voter snapshot progressed: page {} with {} voters", - remaining_pages, - voter_count, - ); - Self::phase_transition(Phase::Snapshot(remaining_pages)); - T::WeightInfo::create_voters_snapshot_paged(T::VoterSnapshotPerBlock::get()) - }, - Err(err) => { - log!(error, "error preparing voter snapshot: {:?}", err); - // TODO: T::WeightInfo::snapshot_error(); - Weight::default() - }, - } - } - } - - /// Start the signed phase. - /// We expect the snapshot to be ready by now. Thus the the data provider lock should be - /// released and transition to the signed phase. - pub(crate) fn start_signed_phase() -> Weight { - debug_assert!(Snapshot::::ensure().is_ok()); - - ::unlock(); - Self::phase_transition(Phase::Signed); - - T::WeightInfo::on_initialize_start_signed() - } - - /// Export phase. - /// - /// In practice, we just need to ensure the export phase does not remain open for too long. - /// During this phase, we expect the external entities to call [`ElectionProvider::elect`] for - /// all the solution pages. Once the least significant page is called, the phase should - /// transition to `Phase::Off`. Thus, if the export phase remains open for too long, it means - /// that the election failed. - pub(crate) fn do_export_phase(now: BlockNumberFor, started_at: BlockNumberFor) -> Weight { - debug_assert!(Pallet::::current_phase().is_export()); - - if now > started_at + T::ExportPhaseLimit::get() { - log!( - error, - "phase `Export` has been open for too long ({:?} blocks). election round failed.", - T::ExportPhaseLimit::get(), - ); - - match ElectionFailure::::get() { - ElectionFailureStrategy::Restart => Self::reset_round_restart(), - ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), - } - } - - T::WeightInfo::on_initialize_start_export() - } - - /// Performs all tasks required after a successful election: - /// - /// 1. Increment round. - /// 2. Change phase to [`Phase::Off`]. - /// 3. Clear all snapshot data. - /// 4. Resets verifier. - fn rotate_round() { - >::mutate(|r| r.defensive_saturating_accrue(1)); - Self::phase_transition(Phase::Off); - - Snapshot::::kill(); - ::kill(); - } - - /// Performs all tasks required after an unsuccessful election which should be self-healing - /// (i.e. the election should restart without entering in emergency phase). - /// - /// Note: the round should not restart as the previous election failed. - /// - /// 1. Change phase to [`Phase::Off`]. - /// 2. Clear all snapshot data. - /// 3. Resets verifier. - fn reset_round_restart() { - Self::phase_transition(Phase::Off); - - Snapshot::::kill(); - ::kill(); - } -} - -impl ElectionProvider for Pallet { - type AccountId = T::AccountId; - type BlockNumber = BlockNumberFor; - type Error = ElectionError; - type MaxWinnersPerPage = ::MaxWinnersPerPage; - type MaxBackersPerWinner = ::MaxBackersPerWinner; - type Pages = T::Pages; - type DataProvider = T::DataProvider; - - /// Important note: we do exect the caller of `elect` to call pages down to `lsp == 0`. - /// Otherwise the export phase will not explicitly finish which will result in a failed - /// election. - fn elect(remaining: PageIndex) -> Result, Self::Error> { - ensure!(Pallet::::current_phase().is_export(), ElectionError::ElectionNotReady); - - T::Verifier::get_queued_solution(remaining) - .ok_or(ElectionError::::SupportPageNotAvailable(remaining)) - .or_else(|err| { - log!( - error, - "elect(): (page {:?}) election provider failed due to {:?}, trying fallback.", - remaining, - err - ); - T::Fallback::elect(remaining).map_err(|fe| ElectionError::::Fallback(fe)) - }) - .map(|supports| { - if remaining.is_zero() { - log!(trace, "elect(): provided the last supports page, rotating round."); - Self::rotate_round(); - } else { - // Phase::Export is on while the election is calling all pages of `elect`. - if !Self::current_phase().is_export() { - let now = >::block_number(); - Self::phase_transition(Phase::Export(now)); - } - } - supports.into() - }) - .map_err(|err| { - log!(error, "elect(): fetching election page {} and fallback failed.", remaining); - - match ElectionFailure::::get() { - // force emergency phase for testing. - ElectionFailureStrategy::Restart => Self::reset_round_restart(), - ElectionFailureStrategy::Emergency => Self::phase_transition(Phase::Emergency), - } - err - }) - } - - fn ongoing() -> bool { - match CurrentPhase::::get() { - Phase::Off => false, - _ => true, - } - } -} - -#[cfg(test)] -mod phase_transition { - use super::*; - use crate::mock::*; - - use frame_support::assert_ok; - - #[test] - fn single_page() { - let (mut ext, _) = ExtBuilder::default() - .pages(1) - .signed_phase(3) - .validate_signed_phase(1) - .lookahead(0) - .build_offchainify(1); - - ext.execute_with(|| { - assert_eq!(System::block_number(), 0); - assert_eq!(Pages::get(), 1); - assert_eq!(>::get(), 0); - assert_eq!(>::get(), Phase::Off); - - let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number() - ); - assert_eq!(next_election, 30); - - // representing the blocknumber when the phase transition happens. - let export_deadline = next_election - (ExportPhaseLimit::get() + Lookhaead::get()); - let expected_unsigned = export_deadline - UnsignedPhase::get(); - let expected_validate = expected_unsigned - SignedValidationPhase::get(); - let expected_signed = expected_validate - SignedPhase::get(); - let expected_snapshot = expected_signed - Pages::get() as u64; - - // tests transition phase boundaries. - roll_to(expected_snapshot); - assert_eq!(>::get(), Phase::Snapshot(Pages::get() - 1)); - - roll_to(expected_signed); - assert_eq!(>::get(), Phase::Signed); - - roll_to(expected_validate); - let start_validate = System::block_number(); - assert_eq!(>::get(), Phase::SignedValidation(start_validate)); - - roll_to(expected_unsigned); - let start_unsigned = System::block_number(); - assert_eq!(>::get(), Phase::Unsigned(start_unsigned)); - - // roll to export phase to call elect(). - roll_to_export(); - - // elect() should work. - assert_ok!(MultiPhase::elect(0)); - - // one page only -- election done, go to off phase. - assert_eq!(>::get(), Phase::Off); - }) - } - - #[test] - fn multi_page() { - let (mut ext, _) = ExtBuilder::default() - .pages(2) - .signed_phase(3) - .validate_signed_phase(1) - .lookahead(0) - .build_offchainify(1); - - ext.execute_with(|| { - assert_eq!(System::block_number(), 0); - assert_eq!(Pages::get(), 2); - assert_eq!(>::get(), 0); - assert_eq!(>::get(), Phase::Off); - - let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number() - ); - assert_eq!(next_election, 30); - - // representing the blocknumber when the phase transition happens. - let export_deadline = next_election - (ExportPhaseLimit::get() + Lookhaead::get()); - let expected_unsigned = export_deadline - UnsignedPhase::get(); - let expected_validate = expected_unsigned - SignedValidationPhase::get(); - let expected_signed = expected_validate - SignedPhase::get(); - let expected_snapshot = expected_signed - Pages::get() as u64; - - // two blocks for snapshot. - roll_to(expected_snapshot); - assert_eq!(>::get(), Phase::Snapshot(Pages::get() - 1)); - - roll_to(expected_snapshot + 1); - assert_eq!(>::get(), Phase::Snapshot(0)); - - // ensure snapshot is sound by end of snapshot phase. - assert_ok!(Snapshot::::ensure()); - - roll_to(expected_signed); - assert_eq!(>::get(), Phase::Signed); - - roll_to(expected_signed + 1); - assert_eq!(>::get(), Phase::Signed); - - // two blocks for validate signed. - roll_to(expected_validate); - let start_validate = System::block_number(); - assert_eq!(>::get(), Phase::SignedValidation(start_validate)); - - // now in unsigned until elect() is called. - roll_to(expected_validate + 2); - let start_unsigned = System::block_number(); - assert_eq!(>::get(), Phase::Unsigned(start_unsigned - 1)); - - }) - } - - #[test] - fn emergency_phase_works() { - let (mut ext, _) = ExtBuilder::default().build_offchainify(1); - ext.execute_with(|| { - let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number() - ); - - // if election fails, enters in emergency phase. - ElectionFailure::::set(ElectionFailureStrategy::Emergency); - - compute_snapshot_checked(); - roll_to(next_election); - - // election will fail due to inexistent solution. - assert!(MultiPhase::elect(Pallet::::msp()).is_err()); - // thus entering in emergency phase. - assert_eq!(>::get(), Phase::Emergency); - }) - } - - #[test] - fn restart_after_elect_fails_works() { - let (mut ext, _) = ExtBuilder::default().build_offchainify(1); - ext.execute_with(|| { - let next_election = <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number() - ); - - // if election fails, restart the election round. - ElectionFailure::::set(ElectionFailureStrategy::Restart); - - compute_snapshot_checked(); - roll_to(next_election); - - // election will fail due to inexistent solution. - assert!(MultiPhase::elect(Pallet::::msp()).is_err()); - // thus restarting from Off phase. - assert_eq!(>::get(), Phase::Off); - }) - } -} - -#[cfg(test)] -mod snapshot { - use super::*; - use crate::mock::*; - - use frame_support::{assert_noop, assert_ok}; - - #[test] - fn setters_getters_work() { - ExtBuilder::default().pages(2).build_and_execute(|| { - let t = BoundedVec::<_, _>::try_from(vec![]).unwrap(); - let v = BoundedVec::<_, _>::try_from(vec![]).unwrap(); - - assert!(Snapshot::::targets().is_none()); - assert!(Snapshot::::voters(0).is_none()); - assert!(Snapshot::::voters(1).is_none()); - - Snapshot::::set_targets(t.clone()); - assert!(Snapshot::::targets().is_some()); - - Snapshot::::set_voters(0, v.clone()); - Snapshot::::set_voters(1, v.clone()); - - assert!(Snapshot::::voters(0).is_some()); - assert!(Snapshot::::voters(1).is_some()); - - // ensure snapshot is sound. - assert_ok!(Snapshot::::ensure()); - - Snapshot::::kill(); - assert!(Snapshot::::targets().is_none()); - assert!(Snapshot::::voters(0).is_none()); - assert!(Snapshot::::voters(1).is_none()); - }) - } - - #[test] - fn targets_voters_snapshot_boundary_checks_works() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(Pages::get(), 3); - assert_eq!(MultiPhase::msp(), 2); - assert_eq!(MultiPhase::lsp(), 0); - - assert_ok!(MultiPhase::create_targets_snapshot()); - - assert_ok!(MultiPhase::create_voters_snapshot(2)); - assert_ok!(MultiPhase::create_voters_snapshot(1)); - assert_ok!(MultiPhase::create_voters_snapshot(0)); - - assert_noop!( - MultiPhase::create_voters_snapshot(3), - ElectionError::::RequestedPageExceeded - ); - assert_noop!( - MultiPhase::create_voters_snapshot(10), - ElectionError::::RequestedPageExceeded - ); - }) - } - - #[test] - fn create_targets_snapshot_works() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(MultiPhase::msp(), 2); - - let no_bounds = ElectionBoundsBuilder::default().build().targets; - let all_targets = - ::electable_targets(no_bounds, 0); - assert_eq!(all_targets.unwrap(), Targets::get()); - assert_eq!(Targets::get().len(), 8); - - // sets max targets per page to 2. - TargetSnapshotPerBlock::set(2); - - let result_and_count = MultiPhase::create_targets_snapshot(); - assert_eq!(result_and_count.unwrap(), 2); - assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20]); - - // sets max targets per page to 4. - TargetSnapshotPerBlock::set(4); - - let result_and_count = MultiPhase::create_targets_snapshot(); - assert_eq!(result_and_count.unwrap(), 4); - assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20, 30, 40]); - - Snapshot::::kill(); - - TargetSnapshotPerBlock::set(6); - - let result_and_count = MultiPhase::create_targets_snapshot(); - assert_eq!(result_and_count.unwrap(), 6); - assert_eq!(Snapshot::::targets().unwrap().to_vec(), vec![10, 20, 30, 40, 50, 60]); - - // reset storage. - Snapshot::::kill(); - }) - } - - #[test] - fn voters_snapshot_works() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(MultiPhase::msp(), 2); - - let no_bounds = ElectionBoundsBuilder::default().build().voters; - let all_voters = ::electing_voters(no_bounds, 0); - assert_eq!(all_voters.unwrap(), Voters::get()); - assert_eq!(Voters::get().len(), 16); - - // sets max voters per page to 7. - VoterSnapshotPerBlock::set(7); - - let voters_page = |page: PageIndex| { - Snapshot::::voters(page) - .unwrap() - .iter() - .map(|v| v.0) - .collect::>() - }; - - // page `msp`. - let result_and_count = MultiPhase::create_voters_snapshot(MultiPhase::msp()); - assert_eq!(result_and_count.unwrap(), 7); - assert_eq!(voters_page(MultiPhase::msp()), vec![1, 2, 3, 4, 5, 6, 7]); - - let result_and_count = MultiPhase::create_voters_snapshot(1); - assert_eq!(result_and_count.unwrap(), 7); - assert_eq!(voters_page(1), vec![8, 10, 20, 30, 40, 50, 60]); - - // page `lsp`. - let result_and_count = MultiPhase::create_voters_snapshot(MultiPhase::lsp()); - assert_eq!(result_and_count.unwrap(), 2); - assert_eq!(voters_page(MultiPhase::lsp()), vec![70, 80]); - }) - } - - #[test] - fn try_progress_snapshot_works() {} -} - -#[cfg(test)] -mod election_provider { - use super::*; - use crate::{mock::*, unsigned::miner::Miner}; - use frame_support::testing_prelude::*; - - #[test] - fn snapshot_to_supports_conversions_work() { - type VotersPerPage = ::VoterSnapshotPerBlock; - type TargetsPerPage = ::TargetSnapshotPerBlock; - type Pages = ::Pages; - - ExtBuilder::default() - .pages(2) - .snasphot_voters_page(4) - .snasphot_targets_page(4) - .desired_targets(2) - .build_and_execute(|| { - assert_eq!(MultiPhase::msp(), 1); - - let all_targets: BoundedVec = - bounded_vec![10, 20, 30, 40]; - - let all_voter_pages: BoundedVec< - BoundedVec, VotersPerPage>, - Pages, - > = bounded_vec![ - bounded_vec![ - (1, 100, bounded_vec![10, 20]), - (2, 20, bounded_vec![30]), - (3, 30, bounded_vec![10]), - (10, 10, bounded_vec![10]) - ], - bounded_vec![ - (20, 20, bounded_vec![20]), - (30, 30, bounded_vec![30]), - (40, 40, bounded_vec![40]) - ], - ]; - - Snapshot::::set_targets(all_targets.clone()); - Snapshot::::set_voters(0, all_voter_pages[0].clone()); - Snapshot::::set_voters(1, all_voter_pages[1].clone()); - - let desired_targets = Snapshot::::desired_targets().unwrap(); - let (results, _) = Miner::::mine_paged_solution_with_snapshot( - &all_voter_pages, - &all_targets, - Pages::get(), - current_round(), - desired_targets, - false, - ) - .unwrap(); - - let supports_page_zero = - PalletVerifier::::feasibility_check(results.solution_pages[0].clone(), 0) - .unwrap(); - let supports_page_one = - PalletVerifier::::feasibility_check(results.solution_pages[1].clone(), 1) - .unwrap(); - - use frame_election_provider_support::{BoundedSupports, TryIntoBoundedSupports}; - use sp_npos_elections::{Support, Supports}; - - let s0: Supports = vec![ - (10, Support { total: 90, voters: vec![(3, 30), (10, 10), (1, 50)] }), - (20, Support { total: 50, voters: vec![(1, 50)] }), - ]; - let bs0: BoundedSupports<_, _, _> = s0.try_into_bounded_supports().unwrap(); - - let s1: Supports = - vec![(20, Support { total: 20, voters: vec![(20, 20)] })]; - let bs1: BoundedSupports<_, _, _> = s1.try_into_bounded_supports().unwrap(); - - assert_eq!(supports_page_zero, bs0); - assert_eq!(supports_page_one, bs1); - }) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/mock/mod.rs b/substrate/frame/election-provider-multi-block/src/mock/mod.rs deleted file mode 100644 index 3a564adaa515c..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/mock/mod.rs +++ /dev/null @@ -1,624 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(unused)] - -mod staking; - -use frame_election_provider_support::{bounds::ElectionBounds, onchain, SequentialPhragmen}; -use sp_npos_elections::ElectionScore; -pub use staking::*; - -use crate::{ - self as epm, - signed::{self as signed_pallet, HoldReason}, - unsigned::{ - self as unsigned_pallet, - miner::{self, Miner, MinerError, OffchainWorkerMiner}, - }, - verifier::{self as verifier_pallet}, - Config, *, -}; -use frame_support::{ - derive_impl, pallet_prelude::*, parameter_types, traits::fungible::InspectHold, -}; -use parking_lot::RwLock; -use sp_runtime::{ - offchain::{ - testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, - OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, - }, - BuildStorage, Perbill, -}; -use std::sync::Arc; - -frame_support::construct_runtime!( - pub struct Runtime { - System: frame_system, - Balances: pallet_balances, - MultiPhase: epm, - VerifierPallet: verifier_pallet, - SignedPallet: signed_pallet, - UnsignedPallet: unsigned_pallet, - } -); - -pub type AccountId = u64; -pub type Balance = u128; -pub type BlockNumber = u64; -pub type VoterIndex = u32; -pub type TargetIndex = u16; -pub type T = Runtime; -pub type Block = frame_system::mocking::MockBlock; -pub(crate) type Solver = SequentialPhragmen; - -frame_election_provider_support::generate_solution_type!( - #[compact] - pub struct TestNposSolution::< - VoterIndex = VoterIndex, - TargetIndex = TargetIndex, - Accuracy = sp_runtime::PerU16, - MaxVoters = frame_support::traits::ConstU32::<2_000> - >(16) -); - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] -impl frame_system::Config for Runtime { - type Block = Block; - type AccountData = pallet_balances::AccountData; -} - -parameter_types! { - pub const ExistentialDeposit: Balance = 1; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - type FreezeIdentifier = (); - type MaxFreezes = (); - type DoneSlashHandler = (); - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = (); -} - -parameter_types! { - pub static SignedPhase: BlockNumber = 3; - pub static UnsignedPhase: BlockNumber = 5; - pub static SignedValidationPhase: BlockNumber = Pages::get().into(); - pub static Lookhaead: BlockNumber = 0; - pub static VoterSnapshotPerBlock: VoterIndex = 5; - pub static TargetSnapshotPerBlock: TargetIndex = 8; - pub static Pages: PageIndex = 3; - pub static ExportPhaseLimit: BlockNumber = (Pages::get() * 2u32).into(); -} - -pub struct EPMBenchmarkingConfigs; -impl BenchmarkingConfig for EPMBenchmarkingConfigs { - const VOTERS: u32 = 100; - const TARGETS: u32 = 50; - const VOTERS_PER_PAGE: [u32; 2] = [1, 5]; - const TARGETS_PER_PAGE: [u32; 2] = [1, 8]; -} - -impl Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SignedPhase = SignedPhase; - type UnsignedPhase = UnsignedPhase; - type SignedValidationPhase = SignedValidationPhase; - type Lookhaead = Lookhaead; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; - type TargetSnapshotPerBlock = TargetSnapshotPerBlock; - type MaxBackersPerWinner = MaxBackersPerWinner; - type MaxWinnersPerPage = MaxWinnersPerPage; - type Pages = Pages; - type ExportPhaseLimit = ExportPhaseLimit; - type DataProvider = MockStaking; - type MinerConfig = Self; - type Fallback = MockFallback; - type Verifier = VerifierPallet; - type BenchmarkingConfig = EPMBenchmarkingConfigs; - type WeightInfo = (); -} - -parameter_types! { - pub static SolutionImprovementThreshold: Perbill = Perbill::zero(); - pub static MaxWinnersPerPage: u32 = 100; - pub static MaxBackersPerWinner: u32 = 1000; -} - -impl crate::verifier::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ForceOrigin = frame_system::EnsureRoot; - type SolutionImprovementThreshold = SolutionImprovementThreshold; - type SolutionDataProvider = SignedPallet; - type WeightInfo = (); -} - -parameter_types! { - pub static DepositBase: Balance = 10; - pub static DepositPerPage: Balance = 1; - pub static Reward: Balance = 10; - pub static MaxSubmissions: u32 = 5; -} - -impl crate::signed::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type EstimateCallFee = ConstU32<8>; - type OnSlash = (); // burn - type DepositBase = ConstDepositBase; - type DepositPerPage = DepositPerPage; - type Reward = Reward; - type MaxSubmissions = MaxSubmissions; - type RuntimeHoldReason = RuntimeHoldReason; - type WeightInfo = (); -} - -parameter_types! { - pub OffchainRepeatInterval: BlockNumber = 10; - pub MinerTxPriority: u64 = 0; - pub MinerSolutionMaxLength: u32 = 10; - pub MinerSolutionMaxWeight: Weight = Default::default(); -} - -impl crate::unsigned::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OffchainRepeatInterval = OffchainRepeatInterval; - type MinerTxPriority = MinerTxPriority; - type MaxLength = MinerSolutionMaxLength; - type MaxWeight = MinerSolutionMaxWeight; - type WeightInfo = (); -} - -impl miner::Config for Runtime { - type AccountId = AccountId; - type Solution = TestNposSolution; - type Solver = Solver; - type Pages = Pages; - type MaxVotesPerVoter = MaxVotesPerVoter; - type MaxWinnersPerPage = MaxWinnersPerPage; - type MaxBackersPerWinner = MaxBackersPerWinner; - type VoterSnapshotPerBlock = VoterSnapshotPerBlock; - type TargetSnapshotPerBlock = TargetSnapshotPerBlock; - type MaxWeight = MinerSolutionMaxWeight; - type MaxLength = MinerSolutionMaxLength; -} - -pub type Extrinsic = sp_runtime::testing::TestXt; - -impl frame_system::offchain::CreateTransactionBase for Runtime -where - RuntimeCall: From, -{ - type RuntimeCall = RuntimeCall; - type Extrinsic = Extrinsic; -} - -impl frame_system::offchain::CreateInherent for Runtime -where - RuntimeCall: From, -{ - fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { - Extrinsic::new_bare(call) - } -} - -pub struct ConstDepositBase; -impl sp_runtime::traits::Convert for ConstDepositBase { - fn convert(_a: usize) -> Balance { - DepositBase::get() - } -} - -parameter_types! { - pub static OnChainElectionBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); - pub static MaxVotesPerVoter: u32 = ::LIMIT as u32; - pub static FallbackEnabled: bool = true; -} - -impl onchain::Config for Runtime { - type System = Runtime; - type Solver = Solver; - type MaxWinnersPerPage = MaxWinnersPerPage; - type MaxBackersPerWinner = MaxBackersPerWinner; - type Bounds = OnChainElectionBounds; - type DataProvider = MockStaking; - type WeightInfo = (); -} - -pub struct MockFallback; -impl ElectionProvider for MockFallback { - type AccountId = AccountId; - type BlockNumber = BlockNumberFor; - type Error = &'static str; - type DataProvider = MockStaking; - type Pages = ConstU32<1>; - type MaxWinnersPerPage = MaxWinnersPerPage; - type MaxBackersPerWinner = MaxBackersPerWinner; - - fn elect(remaining: PageIndex) -> Result, Self::Error> { - if FallbackEnabled::get() { - onchain::OnChainExecution::::elect(remaining) - .map_err(|_| "fallback election failed") - } else { - Err("fallback election failed (forced in mock)") - } - } - - fn ongoing() -> bool { - false - } -} - -#[derive(Default)] -pub struct ExtBuilder { - with_verifier: bool, -} - -// TODO(gpestana): separate ext builder into separate builders for each pallet. -impl ExtBuilder { - pub(crate) fn pages(self, pages: u32) -> Self { - Pages::set(pages); - self - } - - pub(crate) fn snasphot_voters_page(self, voters: VoterIndex) -> Self { - VoterSnapshotPerBlock::set(voters); - self - } - - pub(crate) fn snasphot_targets_page(self, targets: TargetIndex) -> Self { - TargetSnapshotPerBlock::set(targets); - self - } - - pub(crate) fn signed_phase(self, blocks: BlockNumber) -> Self { - SignedPhase::set(blocks); - self - } - - pub(crate) fn validate_signed_phase(self, blocks: BlockNumber) -> Self { - SignedValidationPhase::set(blocks); - self - } - - pub(crate) fn unsigned_phase(self, blocks: BlockNumber) -> Self { - UnsignedPhase::set(blocks); - self - } - - pub(crate) fn lookahead(self, blocks: BlockNumber) -> Self { - Lookhaead::set(blocks); - self - } - - pub(crate) fn max_winners_per_page(self, max: u32) -> Self { - MaxWinnersPerPage::set(max); - self - } - - pub(crate) fn max_backers_per_winner(self, max: u32) -> Self { - MaxBackersPerWinner::set(max); - self - } - - pub(crate) fn desired_targets(self, desired: u32) -> Self { - DesiredTargets::set(desired); - self - } - - pub(crate) fn signed_max_submissions(self, max: u32) -> Self { - MaxSubmissions::set(max); - self - } - - pub(crate) fn solution_improvements_threshold(self, threshold: Perbill) -> Self { - SolutionImprovementThreshold::set(threshold); - self - } - - pub(crate) fn verifier() -> Self { - ExtBuilder { with_verifier: true } - } - - pub(crate) fn build(self) -> sp_io::TestExternalities { - sp_tracing::try_init_simple(); - - let mut storage = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let _ = pallet_balances::GenesisConfig:: { - balances: vec![ - (10, 100_000), - (20, 100_000), - (30, 100_000), - (40, 100_000), - (50, 100_000), - (60, 100_000), - (70, 100_000), - (80, 100_000), - (90, 100_000), - (91, 100), - (92, 100), - (93, 100), - (94, 100), - (95, 100), - (96, 100), - (97, 100), - (99, 100), - (999, 100), - (9999, 100), - ], - } - .assimilate_storage(&mut storage); - - if self.with_verifier { - // nothing special for now - } - - sp_io::TestExternalities::from(storage) - } - - pub fn build_offchainify( - self, - iters: u32, - ) -> (sp_io::TestExternalities, Arc>) { - let mut ext = self.build(); - let (offchain, offchain_state) = TestOffchainExt::new(); - let (pool, pool_state) = TestTransactionPoolExt::new(); - - let mut seed = [0_u8; 32]; - seed[0..4].copy_from_slice(&iters.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)); - - (ext, pool_state) - } - - pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { - let mut ext = self.build(); - ext.execute_with(test); - - #[cfg(feature = "try-runtime")] - ext.execute_with(|| { - //MultiPhase::do_try_state().unwrap(); - // etc.. - - let _ = VerifierPallet::do_try_state() - .map_err(|err| println!(" 🕵️‍♂️ Verifier `try_state` failure: {:?}", err)); - }); - } -} - -pub(crate) fn compute_snapshot_checked() { - let msp = crate::Pallet::::msp(); - - for page in (0..=Pages::get()).rev() { - CurrentPhase::::set(Phase::Snapshot(page)); - crate::Pallet::::try_progress_snapshot(page); - - assert!(Snapshot::::targets_snapshot_exists()); - - if page <= msp { - assert!(Snapshot::::voters(page).is_some()); - } - } -} - -pub(crate) fn mine_and_verify_all() -> Result< - Vec< - frame_election_provider_support::BoundedSupports< - AccountId, - MaxWinnersPerPage, - MaxBackersPerWinner, - >, - >, - &'static str, -> { - let msp = crate::Pallet::::msp(); - let mut paged_supports = vec![]; - - for page in (0..=msp).rev() { - let (_, score, solution) = - OffchainWorkerMiner::::mine(page).map_err(|e| "error mining")?; - - let supports = - ::verify_synchronous(solution, score, page) - .map_err(|_| "error verifying paged solution")?; - - paged_supports.push(supports); - } - - Ok(paged_supports) -} - -pub(crate) fn roll_to(n: BlockNumber) { - for bn in (System::block_number()) + 1..=n { - System::set_block_number(bn); - - MultiPhase::on_initialize(bn); - VerifierPallet::on_initialize(bn); - SignedPallet::on_initialize(bn); - UnsignedPallet::on_initialize(bn); - UnsignedPallet::offchain_worker(bn); - - // TODO: add try-checks for all pallets here too, as we progress the blocks. - log!( - trace, - "Block: {}, Phase: {:?}, Round: {:?}, Election at {:?}", - bn, - >::get(), - >::get(), - election_prediction() - ); - } -} - -// Fast forward until a given election phase. -pub fn roll_to_phase(phase: Phase) { - while MultiPhase::current_phase() != phase { - roll_to(System::block_number() + 1); - } -} - -pub fn roll_to_export() { - while !MultiPhase::current_phase().is_export() { - roll_to(System::block_number() + 1); - } -} - -pub fn roll_one_with_ocw(maybe_pool: Option>>) { - use sp_runtime::traits::Dispatchable; - let bn = System::block_number() + 1; - // if there's anything in the submission pool, submit it. - if let Some(ref pool) = maybe_pool { - pool.read() - .transactions - .clone() - .into_iter() - .map(|uxt| ::decode(&mut &*uxt).unwrap()) - .for_each(|xt| { - xt.function.dispatch(frame_system::RawOrigin::None.into()).unwrap(); - }); - pool.try_write().unwrap().transactions.clear(); - } - - roll_to(bn); -} - -pub fn roll_to_phase_with_ocw( - phase: Phase, - maybe_pool: Option>>, -) { - while MultiPhase::current_phase() != phase { - roll_one_with_ocw(maybe_pool.clone()); - } -} - -pub fn roll_to_with_ocw(n: BlockNumber, maybe_pool: Option>>) { - let now = System::block_number(); - for _i in now + 1..=n { - roll_one_with_ocw(maybe_pool.clone()); - } -} - -pub fn election_prediction() -> BlockNumber { - <::DataProvider as ElectionDataProvider>::next_election_prediction( - System::block_number(), - ) -} - -pub fn current_phase() -> Phase { - MultiPhase::current_phase() -} - -pub fn current_round() -> u32 { - Pallet::::current_round() -} - -pub fn call_elect() -> Result<(), crate::ElectionError> { - for p in (0..=Pallet::::msp()).rev() { - ::elect(p)?; - } - Ok(()) -} - -pub fn assert_snapshots() -> Result<(), &'static str> { - Snapshot::::ensure() -} - -pub fn clear_snapshot() { - let _ = crate::PagedVoterSnapshot::::clear(u32::MAX, None); - let _ = crate::TargetSnapshot::::kill(); -} - -/// Returns the free balance, and the total on-hold for the election submissions. -pub fn balances(who: AccountId) -> (Balance, Balance) { - ( - Balances::free_balance(who), - Balances::balance_on_hold(&HoldReason::ElectionSolutionSubmission.into(), &who), - ) -} - -pub fn mine_full(pages: PageIndex) -> Result, MinerError> { - let (targets, voters) = - OffchainWorkerMiner::::fetch_snapshots().map_err(|_| MinerError::DataProvider)?; - - let reduce = false; - let round = crate::Pallet::::current_round(); - let desired_targets = ::desired_targets() - .map_err(|_| MinerError::DataProvider)?; - - Miner::::mine_paged_solution_with_snapshot( - &targets, - &voters, - Pages::get(), - round, - desired_targets, - reduce, - ) - .map(|(s, _)| s) -} - -pub fn mine( - page: PageIndex, -) -> Result<(ElectionScore, SolutionOf<::MinerConfig>), ()> { - let (_, partial_score, partial_solution) = - OffchainWorkerMiner::::mine(page).map_err(|_| ())?; - - Ok((partial_score, partial_solution)) -} - -// Pallet events filters. - -pub(crate) fn unsigned_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map( - |e| if let RuntimeEvent::UnsignedPallet(inner) = e { Some(inner) } else { None }, - ) - .collect() -} - -pub(crate) fn signed_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::SignedPallet(inner) = e { Some(inner) } else { None }) - .collect() -} - -// TODO fix or use macro. -pub(crate) fn filter_events( - types: Vec, -) -> Vec { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if types.contains(&e) { Some(e) } else { None }) - .collect() -} diff --git a/substrate/frame/election-provider-multi-block/src/mock/staking.rs b/substrate/frame/election-provider-multi-block/src/mock/staking.rs deleted file mode 100644 index 52fc297700420..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/mock/staking.rs +++ /dev/null @@ -1,235 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use sp_runtime::bounded_vec; - -use frame_election_provider_support::{ - bounds::CountBound, data_provider, DataProviderBounds, ElectionDataProvider, - LockableElectionDataProvider, PageIndex, VoterOf as VoterOfProvider, -}; - -use super::{AccountId, BlockNumber, MaxVotesPerVoter, T}; - -// alias for a voter of EPM-MB. -type VoterOf = frame_election_provider_support::VoterOf<::DataProvider>; - -frame_support::parameter_types! { - pub static Targets: Vec = vec![10, 20, 30, 40, 50, 60, 70, 80]; - pub static Voters: Vec> = vec![ - (1, 10, bounded_vec![10, 20]), - (2, 10, bounded_vec![30, 40]), - (3, 10, bounded_vec![40]), - (4, 10, bounded_vec![10, 20, 40]), - (5, 10, bounded_vec![10, 30, 40]), - (6, 10, bounded_vec![20, 30, 40]), - (7, 10, bounded_vec![20, 30]), - (8, 10, bounded_vec![10]), - (10, 10, bounded_vec![10]), - (20, 20, bounded_vec![20]), - (30, 30, bounded_vec![30]), - (40, 40, bounded_vec![40]), - (50, 50, bounded_vec![50]), - (60, 60, bounded_vec![60]), - (70, 70, bounded_vec![70]), - (80, 80, bounded_vec![80]), - ]; - pub static EpochLength: u64 = 30; - pub static DesiredTargets: u32 = 5; - - pub static LastIteratedTargetIndex: Option = None; - pub static LastIteratedVoterIndex: Option = None; - - pub static ElectionDataLock: Option<()> = None; // not locker. -} - -pub struct MockStaking; -impl ElectionDataProvider for MockStaking { - type AccountId = AccountId; - type BlockNumber = BlockNumber; - type MaxVotesPerVoter = MaxVotesPerVoter; - - fn electable_targets( - bounds: DataProviderBounds, - remaining: PageIndex, - ) -> data_provider::Result> { - let mut targets = Targets::get(); - - // drop previously processed targets. - if let Some(last_index) = LastIteratedTargetIndex::get() { - targets = targets.iter().skip(last_index).cloned().collect::>(); - } - - // take as many targets as requested. - if let Some(max_len) = bounds.count { - targets.truncate(max_len.0 as usize); - } - - assert!(!bounds.exhausted(None, CountBound(targets.len() as u32).into(),)); - - // update the last iterated target index accordingly. - if remaining > 0 { - if let Some(last) = targets.last().cloned() { - LastIteratedTargetIndex::set(Some( - Targets::get().iter().position(|v| v == &last).map(|i| i + 1).unwrap(), - )); - } else { - // no more targets to process, do nothing. - } - } else { - LastIteratedTargetIndex::set(None); - } - - Ok(targets) - } - - /// Note: electing voters bounds are only constrained by the count of voters. - fn electing_voters( - bounds: DataProviderBounds, - remaining: PageIndex, - ) -> data_provider::Result>> { - let mut voters = Voters::get(); - - // skip the already iterated voters in previous pages. - if let Some(index) = LastIteratedVoterIndex::get() { - voters = voters.iter().skip(index).cloned().collect::>(); - } - - // take as many voters as permitted by the bounds. - if let Some(max_len) = bounds.count { - voters.truncate(max_len.0 as usize); - } - - assert!(!bounds.exhausted(None, CountBound(voters.len() as u32).into())); - - // update the last iterater voter index accordingly. - if remaining > 0 { - if let Some(last) = voters.last().cloned() { - LastIteratedVoterIndex::set(Some( - Voters::get().iter().position(|v| v == &last).map(|i| i + 1).unwrap(), - )); - } else { - // no more voters to process, do nothing. - } - } else { - LastIteratedVoterIndex::set(None); - } - - Ok(voters) - } - - fn desired_targets() -> data_provider::Result { - Ok(DesiredTargets::get()) - } - - fn next_election_prediction(now: Self::BlockNumber) -> Self::BlockNumber { - now + EpochLength::get() - now % EpochLength::get() - } -} - -impl LockableElectionDataProvider for MockStaking { - fn set_lock() -> data_provider::Result<()> { - ElectionDataLock::get() - .ok_or("lock is already set") - .map(|_| ElectionDataLock::set(Some(()))) - } - - fn unlock() { - ElectionDataLock::set(None); - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::mock::{ExtBuilder, Pages}; - - #[test] - fn multi_page_targets() { - ExtBuilder::default().build_and_execute(|| { - // no bounds. - let targets = - ::electable_targets(Default::default(), 0); - assert_eq!(targets.unwrap().len(), 8); - assert_eq!(LastIteratedTargetIndex::get(), None); - - // 2 targets per page. - let bounds: DataProviderBounds = - DataProviderBounds { count: Some(2.into()), size: None }; - - let mut all_targets = vec![]; - for page in (0..(Pages::get())).rev() { - let mut targets = - ::electable_targets(bounds, page).unwrap(); - assert_eq!(targets.len(), bounds.count.unwrap().0 as usize); - - all_targets.append(&mut targets); - } - - assert_eq!(all_targets, vec![10, 20, 30, 40, 50, 60]); - assert_eq!(LastIteratedTargetIndex::get(), None); - }) - } - - #[test] - fn multi_page_voters() { - ExtBuilder::default().build_and_execute(|| { - // no bounds. - let voters = - ::electing_voters(Default::default(), 0); - assert_eq!(voters.unwrap().len(), 16); - assert_eq!(LastIteratedVoterIndex::get(), None); - - // 2 voters per page. - let bounds: DataProviderBounds = - DataProviderBounds { count: Some(2.into()), size: None }; - - let mut all_voters = vec![]; - for page in (0..(Pages::get())).rev() { - let mut voters = - ::electing_voters(bounds, page).unwrap(); - - assert_eq!(voters.len(), bounds.count.unwrap().0 as usize); - - all_voters.append(&mut voters); - } - - let mut expected_voters = Voters::get(); - expected_voters.truncate(6); - - assert_eq!(all_voters, expected_voters); - assert_eq!(LastIteratedVoterIndex::get(), None); - - // bound based on the *encoded size* of the voters, per page. - let bounds: DataProviderBounds = - DataProviderBounds { count: None, size: Some(100.into()) }; - - let mut all_voters = vec![]; - for page in (0..(Pages::get())).rev() { - let mut voters = - ::electing_voters(bounds, page).unwrap(); - - all_voters.append(&mut voters); - } - - let mut expected_voters = Voters::get(); - expected_voters.truncate(all_voters.len()); - - assert_eq!(all_voters, expected_voters); - assert_eq!(LastIteratedVoterIndex::get(), None); - }) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs deleted file mode 100644 index 9629acce2ed38..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/signed/benchmarking.rs +++ /dev/null @@ -1,66 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Benchmarking for the Elections Multiblock Unsigned sub-pallet. - -use super::*; -use crate::{benchmarking::helpers, BenchmarkingConfig, ConfigCore, ConfigSigned, ConfigUnsigned}; -use frame_benchmarking::v2::*; - -#[benchmarks( - where T: ConfigCore + ConfigSigned + ConfigUnsigned, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn verify_page( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS, - ::BenchmarkingConfig::TARGETS, - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - #[block] - { - // TODO - let _ = 1 + 2; - } - - Ok(()) - } - - impl_benchmark_test_suite!( - PalletSigned, - crate::mock::ExtBuilder::default(), - crate::mock::Runtime, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/election-provider-multi-block/src/signed/mod.rs b/substrate/frame/election-provider-multi-block/src/signed/mod.rs deleted file mode 100644 index a13c2a105aedc..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/signed/mod.rs +++ /dev/null @@ -1,856 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Signed sub-pallet -//! -//! The main goal of the signed sub-pallet is to manage a solution submissions from list of sorted -//! score commitments and correponding paged solutions during the [`crate::Phase::Signed`] and to -//! implement the [`SolutionDataProvider`] trait which exposes an interface for external entities to -//! fetch data related to signed submissions for the active round. -//! -//! ## Overview -//! -//! The core logic of this pallet is only active during [`Phase::Signed`]. During the signed phase, -//! accounts can register a solution for the current round and submit the solution's pages, one per -//! extrindic call. The main flow is the following: -//! -//! 1. [`Phase::Signed`] is enacted in the parent EPM pallet; -//! 2. Submitters call [`Call::register`] to register a solution with a given claimed score. This -//! pallet ensures that accepted submission registrations (encapsulated as -//! [`SubmissionMetadata`]) are kept sorted by claimed score in the [`SubmissionMetadata`] -//! storage map. This pallet accepts up to [`Config::MaxSubmissions`] active registrations per -//! round. -//! 3. Submitters that have successfully registered, may submit the solution pages through -//! [`Call::submit_page`], one page per call. -//! 4. Submitters may bail from a registered solution by calling [`Call::bail`]. Bailing from a -//! solution registration will result in a partial slash. -//! 5. This pallet implements the trait [`SolutionDataProvider`] which exposes methods for external -//! entities (e.g. verifier pallet) to query the data and metadata of the current best submitted -//! solution. -//! 6. Upon solution verification (performed by an external entity e.g. the verifier pallet), -//! [`SolutionDataProvider::report_result`] can be called to report the verification result of -//! the current best solution. Depending on the result, the corresponding submitter's deposit may -//! be fully slashed or the submitter may be rewarded with [`Config::Reward`]. -//! -//! Accounts may submit up to [`Config::MaxSubmissions`] score commitments per election round and -//! this pallet ensures that the scores are stored under the map `SortedScores` are sorted and keyed -//! by the correct round number. -//! -//! ## Reporting the verification result -//! -//! When the time to evaluate the signed submission comes, the solutions are checked from best to -//! worse. The [`SolutionDataProvider`] trait exposes the submission data and metadata to an -//! external entity that verifies the queued solutions until it accepts one solution (or none). The -//! verifier entity reports the result of the solution verification which may result in one of three -//! scenarios: -//! -//! 1. If the *best* committed score and page submissions are correct, the submitter is rewarded. -//! 2. Any queued score that was not evaluated, the held deposit is fully returned. -//! 3. Any invalid solution results in a 100% slash of the held deposit. -//! -//! ## Submission deposit -//! -//! Each submitter must hold a "base deposit" per submission that is calculated based on the number -//! of the number of submissions in the queue. In addition, for each solution page submitted there -//! is a fixed [`Config::PageDeposit`] deposit held. The held deposit may be returned or slashed at -//! by the end of the round, depending on the following: -//! -//! 1. If a submission is verified and accepted, the deposit is returned. -//! 2. If a submission is verified and not accepted, the whole deposit is slashed. -//! 3. If a submission is not verified, the deposit is returned. -//! 4. Bailing a registration will return the page deposit and burn the base balance. -//! -//! The deposit is burned when all the data from the submitter is cleared through the -//! [`Call::force_clear_submission`]. -//! -//! ## Submission reward -//! -//! Exposing [`SolutionDataProvider::report_result`] allows an external verifier to signal whether -//! the current best solution is correct or not. If the solution is correct, the submitter is -//! rewarded and the pallet can start clearing up the state of the current round. -//! -//! ## Storage management -//! -//! ### Storage mutations -//! -//! The [`Submissions`] wraps all the mutation and getters related to the sorted scores, metadata -//! and submissions storage types. All the mutations to those storage items *MUST* be performed -//! through [`Submissions`] to leverage the mutate checks and ensure the data consistency of the -//! submissions data. -//! -//! ### Clearing up the storage -//! -//! The [`SortedScores`] of the *active* submissions in a -//! given round. Each of the registered submissions may have one or more associated paged solution -//! stored in [`SubmissionsStorage`] and its corresponding [`SubmissionMetadata`]. -//! -//! This pallet never implicitly clears either the metadata or the paged submissions storage data. -//! The data is kept in storage until [`Call::force_clear_submission`] extrinsic is called. At that -//! time, the hold deposit may be slashed depending on the state of the `release_strategy` -//! associated with the metadata. - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -#[cfg(test)] -mod tests; - -use crate::{ - signed::pallet::Submissions, - types::AccountIdOf, - verifier::{AsyncVerifier, SolutionDataProvider, VerificationResult}, - PageIndex, PagesOf, SolutionOf, -}; - -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - defensive, - traits::{ - fungible::{ - hold::Balanced as FnBalanced, Credit, Inspect as FnInspect, - InspectHold as FnInspectHold, Mutate as FnMutate, MutateHold as FnMutateHold, - }, - tokens::Precision, - Defensive, DefensiveSaturating, Get, - }, - RuntimeDebugNoBound, -}; -use scale_info::TypeInfo; -use sp_npos_elections::ElectionScore; -use sp_runtime::BoundedVec; -use sp_std::vec::Vec; - -// public re-exports. -pub use pallet::{ - Call, Config, Error, Event, HoldReason, Pallet, __substrate_call_check, - __substrate_event_check, tt_default_parts, tt_default_parts_v2, tt_error_token, -}; - -/// Alias for the pallet's balance type. -type BalanceOf = <::Currency as FnInspect>>::Balance; -/// Alias for the pallet's hold credit type. -pub type CreditOf = Credit, ::Currency>; - -/// Release strategy for currency held by this pallet. -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebugNoBound, PartialEq)] -pub(crate) enum ReleaseStrategy { - /// Releases all held deposit. - All, - /// Releases only the base deposit, - BaseDeposit, - /// Releases only the pages deposit. - PageDeposit, - /// Burn all held deposit. - BurnAll, -} - -impl Default for ReleaseStrategy { - fn default() -> Self { - Self::All - } -} - -/// Metadata of a registered submission. -#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, Default, RuntimeDebugNoBound)] -#[cfg_attr(test, derive(frame_support::PartialEqNoBound, frame_support::EqNoBound))] -#[codec(mel_bound(T: Config))] -#[scale_info(skip_type_params(T))] -pub struct SubmissionMetadata { - /// The score that this submission is proposing. - claimed_score: ElectionScore, - /// A bit-wise bounded vec representing the submitted pages thus far. - pages: BoundedVec>, - /// The amount held for this submission. - deposit: BalanceOf, - /// Current release strategy for this metadata entry. - release_strategy: ReleaseStrategy, -} - -#[frame_support::pallet] -pub mod pallet { - use core::marker::PhantomData; - - use crate::verifier::{AsyncVerifier, Verifier}; - - use super::*; - use frame_support::{ - pallet_prelude::{ValueQuery, *}, - traits::{tokens::Fortitude, Defensive, EstimateCallFee, OnUnbalanced}, - Twox64Concat, - }; - use frame_system::{ - ensure_signed, - pallet_prelude::{BlockNumberFor, OriginFor}, - WeightInfo, - }; - use sp_npos_elections::ElectionScore; - use sp_runtime::traits::Convert; - - #[pallet::config] - #[pallet::disable_frame_system_supertrait_check] - pub trait Config: crate::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The currency type. - type Currency: FnMutateHold - + FnBalanced - + FnInspectHold - + FnMutate; - - /// Something that can predict the fee of a call. Used to sensibly distribute rewards. - type EstimateCallFee: EstimateCallFee, BalanceOf>; - - /// Handler for the unbalanced reduction that happens when submitters are slashed. - type OnSlash: OnUnbalanced>; - - /// Something that calculates the signed base deposit based on the size of the current - /// queued solution proposals. - type DepositBase: Convert>; - - /// Per-page deposit for a signed solution. - #[pallet::constant] - type DepositPerPage: Get>; - - /// Reward for an accepted solution. - #[pallet::constant] - type Reward: Get>; - - /// The maximum number of signed submissions per round. - #[pallet::constant] - type MaxSubmissions: Get; - - /// The pallet's hold reason. - type RuntimeHoldReason: From; - - type WeightInfo: WeightInfo; - } - - /// A sorted list of the current submissions scores corresponding to solution commitments - /// submitted in the signed phase, keyed by round. - /// - /// This pallet *MUST* ensure the bounded vec of scores is always sorted after mutation. - #[pallet::storage] - type SortedScores = StorageMap< - _, - Twox64Concat, - u32, - BoundedVec<(T::AccountId, ElectionScore), T::MaxSubmissions>, - ValueQuery, - >; - - /// A double-map from (`round`, `account_id`) to a submission metadata of a registered - /// solution commitment. - #[pallet::storage] - type SubmissionMetadataStorage = - StorageDoubleMap<_, Twox64Concat, u32, Twox64Concat, T::AccountId, SubmissionMetadata>; - - /// A triple-map from (round, account, page) to a submitted solution. - #[pallet::storage] - type SubmissionStorage = StorageNMap< - _, - ( - NMapKey, - NMapKey, - NMapKey, - ), - SolutionOf, - OptionQuery, - >; - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - /// A reason for this pallet placing a hold on funds. - #[pallet::composite_enum] - pub enum HoldReason { - /// Deposit for registering an election solution. - ElectionSolutionSubmission, - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A score commitment has been successfully registered. - Registered { round: u32, who: AccountIdOf, claimed_score: ElectionScore }, - /// A submission page was stored successfully. - PageStored { round: u32, who: AccountIdOf, page: PageIndex }, - /// Retracted a submission successfully. - Bailed { round: u32, who: AccountIdOf }, - /// A submission has been cleared by request. - SubmissionCleared { round: u32, submitter: AccountIdOf, reward: Option> }, - } - - #[pallet::error] - pub enum Error { - /// The election system is not expecting signed submissions. - NotAcceptingSubmissions, - /// Duplicate registering for a given round, - DuplicateRegister, - /// The submissions queue is full. Reject submission. - SubmissionsQueueFull, - /// Submission with a page index higher than the supported. - BadPageIndex, - /// A page submission was attempted for a submission that was not previously registered. - SubmissionNotRegistered, - /// A submission score is not high enough. - SubmissionScoreTooLow, - /// Bad timing for force clearing a stored submission. - CannotClear, - /// Error releasing held funds. - CannotReleaseFunds, - } - - /// Wrapper for signed submissions. - /// - /// It handle 3 storage items: - /// - /// 1. [`SortedScores`]: A flat, striclty sorted, vector with all the submission's scores. The - /// vector contains a tuple of `submitter_id` and `claimed_score`. - /// 2. [`SubmissionStorage`]: Paginated map with all submissions, keyed by round, submitter and - /// page index. - /// 3. [`SubmissionMetadataStorage`]: Double map with submissions metadata, keyed by submitter - /// ID and round. - /// - /// Invariants: - /// - [`SortedScores`] must be strictly sorted or empty. - /// - All registered scores in [`SortedScores`] must be higher than the minimum score. - /// - An entry in [`SortedScores`] for a given round must have an associated entry in - /// [`SubmissionMetadataStorage`]. - /// - For all registered submissions, there is a held deposit that matches that of the - /// submission metadata and the number of submitted pages. - pub(crate) struct Submissions(core::marker::PhantomData); - impl Submissions { - /// Generic mutation helper with checks. - /// - /// All the mutation functions must be done through this function. - fn mutate_checked R>(_round: u32, mutate: F) -> R { - let result = mutate(); - - #[cfg(debug_assertions)] - assert!(Self::sanity_check_round(crate::Pallet::::current_round()).is_ok()); - - result - } - - /// Try to register a submission commitment. - /// - /// The submission is not accepted if one of these invariants fails: - /// - The claimed score is not higher than the minimum expected score. - /// - The queue is full and the election score is strictly worse than all the current - /// queued solutions. - /// - /// A queued solution may be discarded if the queue is full and the new submission has a - /// better score. - /// - /// It must ensure that the metadata queue is sorted by election score. - fn try_register( - who: &T::AccountId, - round: u32, - metadata: SubmissionMetadata, - ) -> DispatchResult { - Self::mutate_checked(round, || Self::try_register_inner(who, round, metadata)) - } - - fn try_register_inner( - who: &T::AccountId, - round: u32, - metadata: SubmissionMetadata, - ) -> DispatchResult { - let mut scores = Submissions::::scores_for(round); - scores.iter().try_for_each(|(account, _)| -> DispatchResult { - ensure!(account != who, Error::::DuplicateRegister); - Ok(()) - })?; - - // most likely checked before, but double-checking. - debug_assert!(!SubmissionMetadataStorage::::contains_key(round, who)); - - // the submission score must be higher than the minimum trusted score. Note that since - // there is no queued solution yet, the check is only performed against the minimum - // score. - ensure!( - ::ensure_score_quality(metadata.claimed_score), - Error::::SubmissionScoreTooLow, - ); - - let pos = - match scores.binary_search_by_key(&metadata.claimed_score, |(_, score)| *score) { - // in the unlikely event that election scores already exists in the storage, we - // store the submissions next to one other. - Ok(pos) | Err(pos) => pos, - }; - - let submission = (who.clone(), metadata.claimed_score); - - match scores.force_insert_keep_right(pos, submission) { - // entry inserted without discarding. - Ok(None) => Ok(()), - // entry inserted but queue was full, clear the discarded submission. - Ok(Some((discarded, _s))) => { - let _ = SubmissionStorage::::clear_prefix( - (round, &discarded), - u32::max_value(), - None, - ); - // unreserve full deposit - let _ = T::Currency::release_all( - &HoldReason::ElectionSolutionSubmission.into(), - &who, - Precision::Exact, - ) - .defensive()?; - - Ok(()) - }, - Err(_) => Err(Error::::SubmissionsQueueFull), - }?; - - // hold deposit for this submission. - T::Currency::hold( - &HoldReason::ElectionSolutionSubmission.into(), - &who, - metadata.deposit, - )?; - - SortedScores::::insert(round, scores); - SubmissionMetadataStorage::::insert(round, who, metadata); - - Ok(()) - } - - /// Store a paged solution for `who` in a given `round`. - /// - /// If `maybe_solution` is None, it will delete the given page from the submission store. - /// Successive calls to this with the same page index will replace the existing page - /// submission. - pub(crate) fn try_mutate_page( - who: &T::AccountId, - round: u32, - page: PageIndex, - maybe_solution: Option>, - ) -> DispatchResult { - Self::mutate_checked(round, || { - Self::try_mutate_page_inner(who, round, page, maybe_solution) - }) - } - - fn try_mutate_page_inner( - who: &T::AccountId, - round: u32, - page: PageIndex, - maybe_solution: Option>, - ) -> DispatchResult { - ensure!(page < T::Pages::get(), Error::::BadPageIndex); - - ensure!(Self::metadata_for(round, &who).is_some(), Error::::SubmissionNotRegistered); - - let should_hold_extra = - SubmissionStorage::::mutate_exists((round, who, page), |maybe_old_solution| { - let exists = maybe_old_solution.is_some(); - *maybe_old_solution = maybe_solution; - - !exists - }); - - // the deposit per page is held IFF it is a new page being stored. - if should_hold_extra { - T::Currency::hold( - &HoldReason::ElectionSolutionSubmission.into(), - &who, - T::DepositPerPage::get(), - )?; - }; - - Ok(()) - } - - /// Set metadata for submitter. - pub(crate) fn set_metadata( - round: u32, - who: &T::AccountId, - metadata: SubmissionMetadata, - ) { - debug_assert!(SortedScores::::get(round).iter().any(|(account, _)| who == account)); - - Self::mutate_checked(round, || { - SubmissionMetadataStorage::::insert(round, who, metadata); - }); - } - - /// Clears the leader's score data, effectively disabling the submittion. - /// - /// Returns the submission metadata of the disabled. - pub(crate) fn take_leader_score( - round: u32, - ) -> Option<(T::AccountId, Option>)> { - Self::mutate_checked(round, || { - SortedScores::::mutate(round, |scores| scores.pop()).and_then( - |(submitter, _)| { - Some((submitter.clone(), Self::metadata_for(round, &submitter))) - }, - ) - }) - } - - /// Clear the registed metadata of a submission and its score and release the held deposit - /// based on the `release_strategy`. - /// - /// Clearing a submission only clears the metadata and stored score of a solution. The - /// paged submissions must be cleared by explicitly calling - /// [`Call::force_clear_submission`]. - /// - /// Note: the deposit can never be released completely or burned completely since - /// an account may have lingering held deposit from previous or subsequent rounds. Thus, the - /// amount to release and burn must always be calculated explicitly based on the round's - /// metadata and release strategy. - /// - /// The held deposit that is not released is burned as a penalty. - pub(crate) fn clear_submission_of( - who: &T::AccountId, - round: u32, - release_strategy: ReleaseStrategy, - ) -> DispatchResult { - let reason = HoldReason::ElectionSolutionSubmission; - - // calculates current base held deposit for this round, if any. - let base_deposit = if let Some(metadata) = Self::metadata_for(round, &who) { - metadata.deposit - } else { - return Err(Error::::SubmissionNotRegistered.into()); - }; - - // calculates current held page deposit for this round. - let page_deposit = T::DepositPerPage::get().defensive_saturating_mul( - Submissions::::page_count_submission_for(round, who).into(), - ); - - Self::mutate_checked(round, || { - SubmissionMetadataStorage::::remove(round, who); - SortedScores::::get(round).retain(|(submitter, _)| submitter != who); - }); - - let (burn, release) = match release_strategy { - ReleaseStrategy::All => - (Zero::zero(), base_deposit.defensive_saturating_add(page_deposit)), - ReleaseStrategy::BurnAll => - (base_deposit.defensive_saturating_add(page_deposit), Zero::zero()), - ReleaseStrategy::BaseDeposit => (page_deposit, base_deposit), - ReleaseStrategy::PageDeposit => (base_deposit, page_deposit), - }; - - T::Currency::burn_held(&reason.into(), who, burn, Precision::Exact, Fortitude::Force)?; - - T::Currency::release(&reason.into(), who, release, Precision::Exact)?; - - // clear the submission metadata for `who` in `round`. May be a noop. - Self::mutate_checked(round, || { - let _ = SubmissionMetadataStorage::::remove(round, who); - SortedScores::::get(round).retain(|(submitter, _)| submitter != who); - }); - - Ok(()) - } - - /// Returns the leader submitter for the current round and corresponding claimed score. - pub(crate) fn leader(round: u32) -> Option<(T::AccountId, ElectionScore)> { - Submissions::::scores_for(round).last().cloned() - } - - /// Returns the metadata of a submitter for a given account. - pub(crate) fn metadata_for( - round: u32, - who: &T::AccountId, - ) -> Option> { - SubmissionMetadataStorage::::get(round, who) - } - - /// Returns the scores for a given round. - pub(crate) fn scores_for( - round: u32, - ) -> BoundedVec<(T::AccountId, ElectionScore), T::MaxSubmissions> { - SortedScores::::get(round) - } - - /// Returns the submission of a submitter for a given round and page. - pub(crate) fn page_submission_for( - round: u32, - who: T::AccountId, - page: PageIndex, - ) -> Option> { - SubmissionStorage::::get((round, who, page)) - } - - pub(crate) fn page_count_submission_for(round: u32, who: &T::AccountId) -> u32 { - SubmissionStorage::::iter_key_prefix((round, who)).count() as u32 - } - - #[cfg(debug_assertions)] - fn sanity_check_round(_round: u32) -> Result<(), &'static str> { - // TODO - Ok(()) - } - } - - impl Pallet { - pub(crate) fn do_register( - who: &T::AccountId, - claimed_score: ElectionScore, - round: u32, - ) -> DispatchResult { - // base deposit depends on the number of submissions for the current `round`. - let deposit = T::DepositBase::convert( - SubmissionMetadataStorage::::iter_key_prefix(round).count(), - ); - - let pages: BoundedVec<_, T::Pages> = (0..T::Pages::get()) - .map(|_| false) - .collect::>() - .try_into() - .expect("bounded vec constructed from bound; qed."); - - let metadata = SubmissionMetadata { - pages, - claimed_score, - deposit, - // new submissions should receive back all held deposit. - release_strategy: ReleaseStrategy::All, - }; - - let _ = Submissions::::try_register(&who, round, metadata)?; - Ok(()) - } - } - - #[pallet::call] - impl Pallet { - /// Submit a score commitment for a solution in the current round. - /// - /// The scores must be kept sorted in the `SortedScores` storage map. - #[pallet::call_index(1)] - #[pallet::weight(Weight::default())] - pub fn register(origin: OriginFor, claimed_score: ElectionScore) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!( - crate::Pallet::::current_phase().is_signed(), - Error::::NotAcceptingSubmissions - ); - - let round = crate::Pallet::::current_round(); - ensure!( - Submissions::::metadata_for(round, &who).is_none(), - Error::::DuplicateRegister - ); - - Self::do_register(&who, claimed_score, round)?; - - Self::deposit_event(Event::::Registered { round, who, claimed_score }); - Ok(()) - } - - /// Submit a page for a solution. - /// - /// To submit a solution page successfull, the submitter must have registered the - /// commitment before. - #[pallet::call_index(2)] - #[pallet::weight(Weight::default())] - pub fn submit_page( - origin: OriginFor, - page: PageIndex, - maybe_solution: Option>, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!( - crate::Pallet::::current_phase().is_signed(), - Error::::NotAcceptingSubmissions - ); - - let round = crate::Pallet::::current_round(); - Submissions::::try_mutate_page(&who, round, page, maybe_solution)?; - - Self::deposit_event(Event::::PageStored { - round: crate::Pallet::::current_round(), - who, - page, - }); - - Ok(()) - } - - /// Unregister a submission. - /// - /// This will fully remove the solution and corresponding metadata from storage and refund - /// the page submissions deposit only. - /// - /// Note: the base deposit will be burned to prevent the attack where rogue submitters - /// deprive honest submitters submitting a solution. - #[pallet::call_index(3)] - #[pallet::weight(Weight::default())] - pub fn bail(origin: OriginFor) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!( - crate::Pallet::::current_phase().is_signed(), - Error::::NotAcceptingSubmissions - ); - - let round = crate::Pallet::::current_round(); - Submissions::::clear_submission_of(&who, round, ReleaseStrategy::PageDeposit)?; - - Self::deposit_event(Event::::Bailed { round, who }); - - Ok(()) - } - - /// Force clean submissions storage for a given (`sumitter`, `round`) tuple. - /// - /// This pallet expects that submitted pages for `round` may exist IFF a corresponding - /// metadata exists. - #[pallet::call_index(4)] - #[pallet::weight(Weight::default())] - pub fn force_clear_submission( - origin: OriginFor, - round: u32, - submitter: T::AccountId, - ) -> DispatchResultWithPostInfo { - let _who = ensure_signed(origin); - - // force clearing submissions may happen only during phase off. - ensure!(crate::Pallet::::current_phase().is_off(), Error::::CannotClear); - - if let Some(metadata) = Submissions::::metadata_for(round, &submitter) { - Submissions::::mutate_checked(round, || { - // clear submission metadata from submitter for `round`. - let _ = Submissions::::clear_submission_of( - &submitter, - round, - metadata.release_strategy, - ); - - // clear all pages from submitter in `round`. - let _ = SubmissionStorage::::clear_prefix( - (round, &submitter), - u32::max_value(), - None, - ); - }); - } else { - debug_assert!( - Submissions::::page_count_submission_for(round, &submitter).is_zero() - ); - - return Err(Error::::CannotClear.into()) - } - - Self::deposit_event(Event::::SubmissionCleared { - round: crate::Pallet::::current_round(), - submitter, - reward: None, - }); - - Ok(Pays::No.into()) - } - } - - #[pallet::hooks] - impl Hooks> for Pallet { - /// The `on_initialize` signals the [`AsyncVerifier`] whenever it should start or stop the - /// asynchronous verification of stored submissions. - /// - /// - Start async verification at the beginning of the [`crate::Phase::SignedValidation`]. - /// - Stops async verification at the beginning of the [`crate::Phase::Unsigned`]. - fn on_initialize(now: BlockNumberFor) -> Weight { - if crate::Pallet::::current_phase().is_signed_validation_open_at(Some(now)) { - sublog!(debug, "signed", "signed validation phase started, signaling the verifier to start async verifiacton."); - let _ = ::start().defensive(); - }; - - if crate::Pallet::::current_phase().is_unsigned_open_at(now) { - sublog!(debug, "signed", "signed validation phase ended, signaling the verifier to stop async verifiacton."); - ::stop(); - } - - Weight::default() - } - } -} - -impl SolutionDataProvider for Pallet { - type Solution = SolutionOf; - - /// Returns a paged solution of the *best* solution in the queue. - fn get_paged_solution(page: PageIndex) -> Option { - let round = crate::Pallet::::current_round(); - - Submissions::::leader(round).map(|(who, _score)| { - sublog!(info, "signed", "returning page {} of leader's {:?} solution", page, who); - Submissions::::page_submission_for(round, who, page).unwrap_or_default() - }) - } - - /// Returns the score of the *best* solution in the queueu. - fn get_score() -> Option { - let round = crate::Pallet::::current_round(); - Submissions::::leader(round).map(|(_who, score)| score) - } - - /// Called by an external entity to report a verification result of the current *best* - /// solution. - /// - /// If the verification is rejected, update the leader's metadata to be slashed (i.e. set - /// release strategy to [`ReleaseStrategy::BurnAll`] in the leader's metadata). If successful - /// (represented by the variant [``VerificationResult::Queued]), reward the submitter and - /// signal the verifier to stop the async election verification. - fn report_result(result: VerificationResult) { - let round = crate::Pallet::::current_round(); - - let (leader, mut metadata) = - if let Some((leader, maybe_metadata)) = Submissions::::take_leader_score(round) { - let metadata = match maybe_metadata { - Some(m) => m, - None => { - defensive!("unexpected: leader with inconsistent data (no metadata)."); - return; - }, - }; - (leader, metadata) - } else { - // TODO(gpestana): turn into defensive. - sublog!(error, "signed", "unexpected: leader called without active submissions."); - return - }; - - match result { - VerificationResult::Queued => { - // solution was accepted by the verifier, reward leader and stop async - // verification. - // TODO(gpestana): think better about the reward minting process -- should we keep - // a pot for rewards instead of minting it in staking? - let _ = T::Currency::mint_into(&leader, T::Reward::get()).defensive(); - let _ = ::stop(); - }, - VerificationResult::Rejected | VerificationResult::DataUnavailable => { - // updates metadata release strategy so that all the deposit is burned when the - // leader's data is cleared. - metadata.release_strategy = ReleaseStrategy::BurnAll; - Submissions::::set_metadata(round, &leader, metadata); - }, - } - } -} diff --git a/substrate/frame/election-provider-multi-block/src/signed/tests.rs b/substrate/frame/election-provider-multi-block/src/signed/tests.rs deleted file mode 100644 index 3346c84cc7dcf..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/signed/tests.rs +++ /dev/null @@ -1,405 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use crate::{mock::*, verifier::SolutionDataProvider, Phase, Verifier}; -use frame_support::{assert_noop, assert_ok, testing_prelude::*}; -use sp_npos_elections::ElectionScore; -use sp_runtime::traits::Convert; - -#[test] -fn clear_submission_of_works() { - ExtBuilder::default().build_and_execute(|| {}); -} - -mod calls { - use super::*; - use sp_core::bounded_vec; - - #[test] - fn register_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to_phase(Phase::Signed); - assert_ok!(assert_snapshots()); - - assert_eq!(balances(99), (100, 0)); - let score = ElectionScore { minimal_stake: 100, ..Default::default() }; - - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), score)); - assert_eq!(balances(99), (90, 10)); - - assert_eq!( - Submissions::::metadata_for(current_round(), &99).unwrap(), - SubmissionMetadata { - claimed_score: score, - deposit: 10, - pages: bounded_vec![false, false, false], - release_strategy: Default::default(), - } - ); - - assert_eq!( - signed_events(), - vec![Event::Registered { round: 0, who: 99, claimed_score: score }], - ); - - // duplicate submission for the same round fails. - assert_noop!( - SignedPallet::register(RuntimeOrigin::signed(99), score), - Error::::DuplicateRegister, - ); - - // if claimed score if below the minimum score, submission will fail. - ::set_minimum_score(ElectionScore { - minimal_stake: 20, - ..Default::default() - }); - - let low_score = ElectionScore { minimal_stake: 10, ..Default::default() }; - assert_noop!( - SignedPallet::register(RuntimeOrigin::signed(97), low_score), - Error::::SubmissionScoreTooLow, - ); - }) - } - - #[test] - fn register_sorted_works() { - ExtBuilder::default().signed_max_submissions(3).build_and_execute(|| { - // try register 5 submissions: - // - 3 are stored. - // - one submission is registered after queue is full while the score improves current - // submission in the queue; other submission is discarded. - // - one submission is registered after queue is full while the score does not improve - // the current submission in the queue; submission is discarded. - - roll_to_phase(Phase::Signed); - - let score = ElectionScore { minimal_stake: 40, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(40), score)); - - let score = ElectionScore { minimal_stake: 30, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(30), score)); - - let score = ElectionScore { minimal_stake: 20, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(20), score)); - - // submission queue is full, next submissions will only be accepted if the submitted - // score improves the current lower score. - - // registration discarded. - let score = ElectionScore { minimal_stake: 10, ..Default::default() }; - assert_noop!( - SignedPallet::register(RuntimeOrigin::signed(10), score), - Error::::SubmissionsQueueFull - ); - - // higher score is successfully registered. - let higher_score = ElectionScore { minimal_stake: 50, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(50), higher_score)); - - assert_eq!(Submissions::::leader(current_round()).unwrap(), (50, higher_score),); - - assert_eq!( - signed_events(), - vec![ - Event::Registered { - round: 0, - who: 40, - claimed_score: ElectionScore { - minimal_stake: 40, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - Event::Registered { - round: 0, - who: 30, - claimed_score: ElectionScore { - minimal_stake: 30, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - Event::Registered { - round: 0, - who: 20, - claimed_score: ElectionScore { - minimal_stake: 20, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - Event::Registered { - round: 0, - who: 50, - claimed_score: ElectionScore { - minimal_stake: 50, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - ], - ); - }) - } - - #[test] - fn submit_page_works() { - ExtBuilder::default().build_and_execute(|| { - // bad timing. - assert_noop!( - SignedPallet::submit_page(RuntimeOrigin::signed(40), 0, None), - Error::::NotAcceptingSubmissions - ); - - roll_to_phase(Phase::Signed); - - // submission not registered before. - assert_noop!( - SignedPallet::submit_page(RuntimeOrigin::signed(10), 0, None), - Error::::SubmissionNotRegistered - ); - - let score = ElectionScore { minimal_stake: 10, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(10), score)); - - // 0 pages submitted so far. - assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 0); - - // now submission works since there is a registered commitment. - assert_ok!(SignedPallet::submit_page( - RuntimeOrigin::signed(10), - 0, - Some(Default::default()) - )); - - assert_eq!( - Submissions::::page_submission_for(current_round(), 10, 0), - Some(Default::default()), - ); - - // 1 page submitted so far. - assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 1); - - // tries to submit a page out of bounds. - assert_noop!( - SignedPallet::submit_page(RuntimeOrigin::signed(10), 10, Some(Default::default())), - Error::::BadPageIndex, - ); - - // 1 successful page submitted so far. - assert_eq!(Submissions::::page_count_submission_for(current_round(), &10), 1); - - assert_eq!( - signed_events(), - vec![ - Event::Registered { - round: 0, - who: 10, - claimed_score: ElectionScore { - minimal_stake: 10, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - Event::PageStored { round: 0, who: 10, page: 0 } - ], - ); - }) - } - - #[test] - fn bail_works() { - ExtBuilder::default().build_and_execute(|| { - // TODO - }) - } - - #[test] - fn force_clear_submission_works() { - ExtBuilder::default().build_and_execute(|| { - // TODO - }) - } -} - -mod deposit { - use super::*; - - #[test] - fn register_submit_bail_deposit_works() { - ExtBuilder::default().build_and_execute(|| { - assert_eq!(::Pages::get(), 3); - - roll_to_phase(Phase::Signed); - assert_ok!(assert_snapshots()); - - // expected base deposit with 0 submissions in the queue. - let base_deposit = ::DepositBase::convert(0); - let page_deposit = ::DepositPerPage::get(); - assert!(base_deposit != 0 && page_deposit != 0 && base_deposit != page_deposit); - - // 99 has 100 free balance and 0 held balance for elections. - assert_eq!(balances(99), (100, 0)); - - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(99), Default::default())); - - // free balance and held deposit updated as expected. - assert_eq!(balances(99), (100 - base_deposit, base_deposit)); - - // submit page 2. - assert_ok!(SignedPallet::submit_page( - RuntimeOrigin::signed(99), - 2, - Some(Default::default()) - )); - - // free balance and held deposit updated as expected. - assert_eq!( - balances(99), - (100 - base_deposit - page_deposit, base_deposit + page_deposit) - ); - - // submit remaining pages. - assert_ok!(SignedPallet::submit_page( - RuntimeOrigin::signed(99), - 1, - Some(Default::default()) - )); - assert_ok!(SignedPallet::submit_page( - RuntimeOrigin::signed(99), - 0, - Some(Default::default()) - )); - - // free balance and held deposit updated as expected (ie. base_deposit + Pages * - // page_deposit) - assert_eq!( - balances(99), - (100 - base_deposit - (3 * page_deposit), base_deposit + (3 * page_deposit)) - ); - - // now if 99 bails, all the deposits are released. - assert_ok!(SignedPallet::bail(RuntimeOrigin::signed(99))); - - // the base deposit was burned after bail and all the pages deposit were released. - assert_eq!(balances(99), (100 - base_deposit, 0)); - }) - } -} - -mod solution_data_provider { - use super::*; - - #[test] - fn higher_score_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to_phase(Phase::Signed); - - assert_eq!(::get_score(), None); - - let higher_score = ElectionScore { minimal_stake: 40, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(40), higher_score)); - - let score = ElectionScore { minimal_stake: 30, ..Default::default() }; - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(30), score)); - - assert_eq!(::get_score(), Some(higher_score)); - }) - } - - #[test] - fn get_page_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to_phase(Phase::Signed); - assert_eq!(::get_score(), None); - }) - } -} - -mod e2e { - use super::*; - - type MaxSubmissions = ::MaxSubmissions; - - mod simple_e2e_works { - use super::*; - - #[test] - fn submit_solution_happy_path_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to_phase(Phase::Signed); - - let current_round = MultiPhase::current_round(); - assert!(Submissions::::metadata_for(current_round, &10).is_none()); - - let claimed_score = ElectionScore { minimal_stake: 100, ..Default::default() }; - - // register submission - assert_ok!(SignedPallet::register(RuntimeOrigin::signed(10), claimed_score,)); - - // metadata and claimed scores have been stored as expected. - assert_eq!( - Submissions::::metadata_for(current_round, &10), - Some(SubmissionMetadata { - claimed_score, - deposit: 10, - pages: bounded_vec![false, false, false], - release_strategy: Default::default(), - }) - ); - let expected_scores: BoundedVec<(AccountId, ElectionScore), MaxSubmissions> = - bounded_vec![(10, claimed_score)]; - assert_eq!(Submissions::::scores_for(current_round), expected_scores); - - // submit all pages of a noop solution; - let solution = TestNposSolution::default(); - for page in (0..=MultiPhase::msp()).into_iter().rev() { - assert_ok!(SignedPallet::submit_page( - RuntimeOrigin::signed(10), - page, - Some(solution.clone()) - )); - - assert_eq!( - Submissions::::page_submission_for(current_round, 10, page), - Some(solution.clone()) - ); - } - - assert_eq!( - signed_events(), - vec![ - Event::Registered { - round: 0, - who: 10, - claimed_score: ElectionScore { - minimal_stake: 100, - sum_stake: 0, - sum_stake_squared: 0 - } - }, - Event::PageStored { round: 0, who: 10, page: 2 }, - Event::PageStored { round: 0, who: 10, page: 1 }, - Event::PageStored { round: 0, who: 10, page: 0 }, - ] - ); - }) - } - } -} diff --git a/substrate/frame/election-provider-multi-block/src/types.rs b/substrate/frame/election-provider-multi-block/src/types.rs deleted file mode 100644 index 7f4c1d2cefdd2..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/types.rs +++ /dev/null @@ -1,261 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Types for the multi-block election provider pallet and sub-pallets. - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -use crate::{unsigned::miner::Config as MinerConfig, Verifier}; -use frame_election_provider_support::{ElectionProvider, NposSolution, PageIndex}; -use frame_support::{ - BoundedVec, CloneNoBound, DebugNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, - RuntimeDebugNoBound, -}; -use sp_npos_elections::ElectionScore; -use sp_runtime::SaturatedConversion; -use sp_std::{boxed::Box, vec::Vec}; - -/// The main account ID type. -pub type AccountIdOf = ::AccountId; - -/// Supports that are returned from a given [`Verifier`]. -pub type SupportsOf = frame_election_provider_support::BoundedSupports< - ::AccountId, - ::MaxWinnersPerPage, - ::MaxBackersPerWinner, ->; - -/// Supports that are returned from a given [`miner::Config`]. -pub type MinerSupportsOf = frame_election_provider_support::BoundedSupports< - ::AccountId, - ::MaxWinnersPerPage, - ::MaxBackersPerWinner, ->; - -/// The voter index. Derived from the solution of the Miner config. -pub type SolutionVoterIndexOf = <::Solution as NposSolution>::VoterIndex; -/// The target index. Derived from the solution of the Miner config. -pub type SolutionTargetIndexOf = <::Solution as NposSolution>::TargetIndex; - -/// The solution type used by this crate. -pub type SolutionOf = ::Solution; - -/// Alias for an error of a fallback election provider. -type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; - -/// Alias for a voter, parameterized by this crate's config. -pub(crate) type VoterOf = - frame_election_provider_support::VoterOf<::DataProvider>; - -/// Same as [`VoterOf`], but parameterized by the `miner::Config`. -pub(crate) type MinerVoterOf = frame_election_provider_support::Voter< - ::AccountId, - ::MaxVotesPerVoter, ->; - -/// Alias for a page of voters, parameterized by this crate's config. -pub(crate) type VoterPageOf = - BoundedVec, ::VoterSnapshotPerBlock>; -/// Alias for a page of targets, parameterized by this crate's config. -pub(crate) type TargetPageOf = - BoundedVec, ::TargetSnapshotPerBlock>; - -/// Same as [`VoterPageOf`], but parameterized by [`miner::Config`]. -pub(crate) type VoterPageMinerOf = - BoundedVec, ::VoterSnapshotPerBlock>; -/// Same as [`TargetPageOf`], but parameterized by []`miner::Config`]. -pub(crate) type TargetPageMinerOf = - BoundedVec<::AccountId, ::TargetSnapshotPerBlock>; - -pub(crate) type MaxWinnersPerPageOf = ::MaxWinnersPerPage; - -/// Alias for all pages of voters, parameterized by the miner's Config. -pub(crate) type AllVoterPagesOf = BoundedVec, ::Pages>; -pub(crate) type AllTargetPagesOf = BoundedVec, ::Pages>; - -/// Edges from voters to nominated targets that are part of the winner set. -pub type AssignmentOf = - sp_npos_elections::Assignment<::AccountId, SolutionAccuracyOf>; - -// Accuracy of the election. -pub type SolutionAccuracyOf = <::Solution as NposSolution>::Accuracy; - -/// Encodes the length of a page of either a solution or a snapshot. -/// -/// This is stored automatically on-chain, and it contains the **size of the entire snapshot page**. -/// This is also used in dispatchables as weight witness data and should **only contain the size of -/// the presented solution page**, not the entire snapshot or page snaphsot. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, Debug, Default, TypeInfo)] -pub struct PageSize { - /// The length of voters. - #[codec(compact)] - pub voters: u32, - /// The length of targets. - #[codec(compact)] - pub targets: u32, -} - -/// Strategies for when the election fails. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)] -pub enum ElectionFailureStrategy { - /// Enters in emergency phase when election fails. - Emergency, - /// Restarts the election phase without starting a new era. - Restart, -} - -impl Default for ElectionFailureStrategy { - fn default() -> Self { - ElectionFailureStrategy::Restart - } -} - -/// Current phase of an election. -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, MaxEncodedLen, Debug, TypeInfo)] -pub enum Phase { - /// Election has halted -- nothing will happen. - Halted, - /// The election is off. - Off, - /// Signed phase is open. - Signed, - /// The signed validations phase - SignedValidation(Bn), - Unsigned(Bn), - /// Preparing the paged target and voter snapshots. - Snapshot(PageIndex), - /// Exporting the paged election result (i.e. most likely staking is requesting election - /// pages). It includes the block at which the export phase started. - Export(Bn), - /// Emergency phase, something went wrong and the election is halted. - Emergency, -} - -impl Default for Phase { - fn default() -> Self { - Phase::Off - } -} - -impl Phase { - pub(crate) fn is_off(&self) -> bool { - matches!(self, Phase::Off) - } - - pub(crate) fn is_signed(&self) -> bool { - matches!(self, Phase::Signed) - } - - pub(crate) fn is_snapshot(&self) -> bool { - matches!(self, Phase::Snapshot(_)) - } - - /// Returns whether the validation phase is ongoing. - pub(crate) fn is_signed_validation_open_at(&self, at: Option) -> bool { - match at { - Some(at) => matches!(self, Phase::SignedValidation(real) if *real == at), - None => matches!(self, Phase::SignedValidation(_)), - } - } - - pub(crate) fn is_unsigned_open_at(&self, at: Bn) -> bool { - matches!(self, Phase::Unsigned(real) if *real == at) - } - - pub(crate) fn is_unsigned(&self) -> bool { - matches!(self, Phase::Unsigned(_)) - } - - pub(crate) fn is_export(&self) -> bool { - matches!(self, Phase::Export(_)) - } -} - -#[derive(DebugNoBound, PartialEq)] -pub enum ElectionError { - /// Error returned by the election data provider. - DataProvider, - /// The data provider returned data that exceeded the boundaries defined in the contract with - /// the election provider. - DataProviderBoundariesExceeded, - /// The support `page_index` was not available at request. - SupportPageNotAvailable(PageIndex), - /// The requested page exceeds the number of election pages defined of the current election - /// config. - RequestedPageExceeded, - /// Election not ready yet. - ElectionNotReady, - /// The fallback election error'ed. - Fallback(FallbackErrorOf), -} - -/// A paged raw solution which contains a set of paginated solutions to be submitted. -/// -/// A raw solution has not been checked for correctness. -#[derive( - TypeInfo, - Encode, - Decode, - RuntimeDebugNoBound, - CloneNoBound, - EqNoBound, - PartialEqNoBound, - MaxEncodedLen, - DefaultNoBound, -)] -#[codec(mel_bound(T: MinerConfig))] -#[scale_info(skip_type_params(T))] -pub struct PagedRawSolution { - pub solution_pages: BoundedVec, T::Pages>, - pub score: ElectionScore, - pub round: u32, -} - -/// A helper trait to deal with the page index of partial solutions. -/// -/// This should only be called on the `Vec` or similar types. If the solution is *full*, -/// it returns a normal iterator that is just mapping the index (usize) to `PageIndex`. -/// -/// if the solution is partial, it shifts the indices sufficiently so that the most significant page -/// of the solution matches with the most significant page of the snapshot onchain. -pub trait Pagify { - fn pagify(&self, bound: PageIndex) -> Box + '_>; - fn into_pagify(self, bound: PageIndex) -> Box>; -} - -impl Pagify for Vec { - fn pagify(&self, desired_pages: PageIndex) -> Box + '_> { - Box::new( - self.into_iter() - .enumerate() - .map(|(p, s)| (p.saturated_into::(), s)) - .map(move |(p, s)| { - let desired_pages_usize = desired_pages as usize; - // TODO: this could be an error. - debug_assert!(self.len() <= desired_pages_usize); - let padding = desired_pages_usize.saturating_sub(self.len()); - let new_page = p.saturating_add(padding.saturated_into::()); - (new_page, s) - }), - ) - } - - fn into_pagify(self, _: PageIndex) -> Box> { - todo!() - } -} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs deleted file mode 100644 index ba2d769a11bc0..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/unsigned/benchmarking.rs +++ /dev/null @@ -1,88 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Benchmarking for the Elections Multiblock Unsigned sub-pallet. - -use super::*; -use crate::{ - benchmarking::helpers, signed::Config as ConfigSigned, unsigned::Config, BenchmarkingConfig, - Config as ConfigCore, ConfigVerifier, Pallet as PalletCore, Phase, -}; -use frame_system::RawOrigin; - -use frame_benchmarking::v2::*; - -#[benchmarks( - where T: Config + ConfigCore + ConfigSigned + ConfigVerifier, -)] -mod benchmarks { - use super::*; - - #[benchmark] - fn submit_page_unsigned( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - // configs necessary to proceed with the unsigned submission. - PalletCore::::phase_transition(Phase::Unsigned(0u32.into())); - - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - // the last page (0) will also perfom a full feasibility check for all the pages in the - // queue. For this benchmark, we want to ensure that we do not call `submit_page_unsigned` - // on the last page, to avoid this extra step. - assert!(T::Pages::get() >= 2); - - let (claimed_full_score, partial_score, paged_solution) = - OffchainWorkerMiner::::mine(PalletCore::::msp()).map_err(|err| { - log!(error, "mine error: {:?}", err); - BenchmarkError::Stop("miner error") - })?; - - #[extrinsic_call] - _( - RawOrigin::None, - PalletCore::::msp(), - paged_solution, - partial_score, - claimed_full_score, - ); - - Ok(()) - } - - impl_benchmark_test_suite!( - PalletUnsigned, - crate::mock::ExtBuilder::default(), - crate::mock::Runtime, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs b/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs deleted file mode 100644 index 1a1145b280336..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/unsigned/miner.rs +++ /dev/null @@ -1,811 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # NPoS miner - -use crate::{ - helpers, - types::{PageSize, Pagify}, - unsigned::{pallet::Config as UnsignedConfig, Call}, - verifier::FeasibilityError, - AssignmentOf, MinerSupportsOf, MinerVoterOf, Pallet as EPM, Snapshot, -}; - -use frame_election_provider_support::{ - ElectionDataProvider, IndexAssignmentOf, NposSolution, NposSolver, PageIndex, - TryIntoBoundedSupports, Weight, -}; -use frame_support::{ensure, traits::Get, BoundedVec}; -use scale_info::TypeInfo; -use sp_npos_elections::{ElectionResult, ElectionScore, ExtendedBalance, Support}; -use sp_runtime::{offchain::storage::StorageValueRef, SaturatedConversion}; -use sp_std::{prelude::ToOwned, vec, vec::Vec}; - -pub type TargetSnaphsotOf = - BoundedVec<::AccountId, ::TargetSnapshotPerBlock>; -pub type VoterSnapshotPagedOf = BoundedVec< - BoundedVec, ::VoterSnapshotPerBlock>, - ::Pages, ->; - -#[derive(Debug, Eq, PartialEq, Clone)] -pub enum MinerError { - /// An internal error in the NPoS elections crate. - NposElections(sp_npos_elections::Error), - /// Snapshot data was unavailable. - SnapshotUnAvailable(SnapshotType), - /// An error from the election solver. - Solver, - /// The solution generated from the miner is not feasible. - Feasibility(FeasibilityError), - InvalidPage, - SubmissionFailed, - NotEnoughTargets, - DataProvider, -} - -impl From for MinerError { - fn from(e: sp_npos_elections::Error) -> Self { - MinerError::NposElections(e) - } -} - -impl From for MinerError { - fn from(e: FeasibilityError) -> Self { - MinerError::Feasibility(e) - } -} - -impl From for MinerError { - fn from(typ: SnapshotType) -> Self { - MinerError::SnapshotUnAvailable(typ) - } -} - -/// The type of the snapshot. -/// -/// Used to express errors. -#[derive(Debug, Eq, PartialEq, Clone)] -pub enum SnapshotType { - /// Voters at the given page missing. - Voters(PageIndex), - /// Targets are missing. - Targets, - // Desired targets are missing. - DesiredTargets, -} - -/// Reports the trimming result of a mined solution -#[derive(Debug, Clone, PartialEq)] -pub struct TrimmingStatus { - weight: usize, - length: usize, -} - -impl Default for TrimmingStatus { - fn default() -> Self { - Self { weight: 0, length: 0 } - } -} - -use crate::PagedRawSolution; -use codec::{EncodeLike, MaxEncodedLen}; - -pub trait Config { - type AccountId: Ord + Clone + codec::Codec + core::fmt::Debug; - - type Solution: codec::Codec - + sp_std::fmt::Debug - + Default - + PartialEq - + Eq - + Clone - + Sized - + Ord - + NposSolution - + TypeInfo - + EncodeLike - + MaxEncodedLen; - - type Solver: NposSolver< - AccountId = Self::AccountId, - Accuracy = ::Accuracy, - >; - - type Pages: Get; - - type MaxVotesPerVoter: Get; - type MaxWinnersPerPage: Get; - type MaxBackersPerWinner: Get; - - type VoterSnapshotPerBlock: Get; - type TargetSnapshotPerBlock: Get; - - type MaxWeight: Get; - type MaxLength: Get; -} - -pub struct Miner(sp_std::marker::PhantomData); - -impl Miner { - pub fn mine_paged_solution_with_snapshot( - all_voter_pages: &BoundedVec< - BoundedVec, T::VoterSnapshotPerBlock>, - T::Pages, - >, - all_targets: &BoundedVec, - pages: PageIndex, - round: u32, - desired_targets: u32, - do_reduce: bool, - ) -> Result<(PagedRawSolution, TrimmingStatus), MinerError> { - // useless to proceed if the solution will not be feasible. - ensure!(all_targets.len() >= desired_targets as usize, MinerError::NotEnoughTargets); - - // flatten pages of voters and target snapshots. - let all_voters: Vec> = - all_voter_pages.iter().cloned().flatten().collect::>(); - - // these closures generate an efficient index mapping of each tvoter -> the snaphot - // that they are part of. this needs to be the same indexing fn in the verifier side to - // sync when reconstructing the assingments page from a solution. - //let binding_targets = all_targets.clone(); - let voters_page_fn = helpers::generate_voter_page_fn::(&all_voter_pages); - let targets_index_fn = helpers::target_index_fn::(&all_targets); - - // run the election with all voters and targets. - let ElectionResult { winners: _, assignments } = ::solve( - desired_targets as usize, - all_targets.clone().to_vec(), - all_voters.clone(), - ) - .map_err(|_| MinerError::Solver)?; - - if do_reduce { - // TODO(gpestana): reduce and trim. - } - // split assignments into `T::Pages pages. - let mut paged_assignments: BoundedVec>, T::Pages> = - BoundedVec::with_bounded_capacity(pages as usize); - - paged_assignments.bounded_resize(pages as usize, vec![]); - - // adds assignment to the correct page, based on the voter's snapshot page. - for assignment in assignments { - let page = voters_page_fn(&assignment.who).ok_or(MinerError::InvalidPage)?; - let assignment_page = - paged_assignments.get_mut(page as usize).ok_or(MinerError::InvalidPage)?; - assignment_page.push(assignment); - } - - // convert each page of assignments to a paged `T::Solution`. - let solution_pages: BoundedVec<::Solution, T::Pages> = paged_assignments - .clone() - .into_iter() - .enumerate() - .map(|(page_index, assignment_page)| { - let page: PageIndex = page_index.saturated_into(); - let voter_snapshot_page = all_voter_pages - .get(page as usize) - .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Voters(page)))?; - - let voters_index_fn = { - let cache = helpers::generate_voter_cache::(&voter_snapshot_page); - helpers::voter_index_fn_owned::(cache) - }; - - <::Solution>::from_assignment( - &assignment_page, - &voters_index_fn, - &targets_index_fn, - ) - .map_err(|e| MinerError::NposElections(e)) - }) - .collect::, _>>()? - .try_into() - .expect("paged_assignments is bound by `T::Pages. qed."); - - // TODO(gpestana): trim again? - let trimming_status = Default::default(); - - let mut paged_solution = - PagedRawSolution { solution_pages, score: Default::default(), round }; - - // everytthing's ready - calculate final solution score. - paged_solution.score = - Self::compute_score(all_voter_pages, all_targets, &paged_solution, desired_targets)?; - - Ok((paged_solution, trimming_status)) - } - - /// Take the given raw paged solution and compute its score. This will replicate what the chain - /// would do as closely as possible, and expects all the corresponding snapshot data to be - /// available. - fn compute_score( - voters: &VoterSnapshotPagedOf, - targets: &TargetSnaphsotOf, - paged_solution: &PagedRawSolution, - desired_targets: u32, - ) -> Result { - use sp_npos_elections::EvaluateSupport; - use sp_std::collections::btree_map::BTreeMap; - - let all_supports = - Self::feasibility_check(voters, targets, paged_solution, desired_targets)?; - let mut total_backings: BTreeMap = BTreeMap::new(); - all_supports.into_iter().map(|x| x.0).flatten().for_each(|(who, support)| { - let backing = total_backings.entry(who).or_default(); - *backing = backing.saturating_add(support.total); - }); - - let all_supports = total_backings - .into_iter() - .map(|(who, total)| (who, Support { total, ..Default::default() })) - .collect::>(); - - Ok((&all_supports).evaluate()) - } - - // Checks the feasibility of a paged solution and calculates the score associated with the - // page. - pub fn compute_partial_score( - voters: &VoterSnapshotPagedOf, - targets: &TargetSnaphsotOf, - solution: &::Solution, - desired_targets: u32, - page: PageIndex, - ) -> Result { - let supports = Self::feasibility_check_partial( - voters, - targets, - solution.clone(), - desired_targets, - page, - )?; - let score = sp_npos_elections::evaluate_support( - supports.clone().into_iter().map(|(_, backings)| backings), - ); - - Ok(score) - } - - /// Perform the feasibility check on all pages of a solution, one by one, and returns the - /// supports of the full solution. - pub fn feasibility_check( - voters: &VoterSnapshotPagedOf, - targets: &TargetSnaphsotOf, - paged_solution: &PagedRawSolution, - desired_targets: u32, - ) -> Result>, MinerError> { - // check every solution page for feasibility. - paged_solution - .solution_pages - .pagify(T::Pages::get()) - .map(|(page_index, page_solution)| { - Self::feasibility_check_partial( - voters, - targets, - page_solution.clone(), - desired_targets, - page_index as PageIndex, - ) - }) - .collect::, _>>() - .map_err(|err| MinerError::from(err)) - } - - /// Performs the feasibility check of a single page, returns the supports of the partial - /// feasibility check. - pub fn feasibility_check_partial( - voters: &VoterSnapshotPagedOf, - targets: &TargetSnaphsotOf, - partial_solution: ::Solution, - desired_targets: u32, - page: PageIndex, - ) -> Result, FeasibilityError> { - let voters_page: BoundedVec, ::VoterSnapshotPerBlock> = voters - .get(page as usize) - .ok_or(FeasibilityError::Incomplete) - .map(|v| v.to_owned())?; - - let voter_cache = helpers::generate_voter_cache::(&voters_page); - let voter_at = helpers::voter_at_fn::(&voters_page); - let target_at = helpers::target_at_fn::(targets); - let voter_index = helpers::voter_index_fn_usize::(&voter_cache); - - // Then convert solution -> assignment. This will fail if any of the indices are - // gibberish. - let assignments = partial_solution - .into_assignment(voter_at, target_at) - .map_err::(Into::into)?; - - // Ensure that assignments are all correct. - let _ = assignments - .iter() - .map(|ref assignment| { - // Check that assignment.who is actually a voter (defensive-only). NOTE: while - // using the index map from `voter_index` is better than a blind linear search, - // this *still* has room for optimization. Note that we had the index when we - // did `solution -> assignment` and we lost it. Ideal is to keep the index - // around. - - // Defensive-only: must exist in the snapshot. - let snapshot_index = - voter_index(&assignment.who).ok_or(FeasibilityError::InvalidVoter)?; - // Defensive-only: index comes from the snapshot, must exist. - let (_voter, _stake, targets) = - voters_page.get(snapshot_index).ok_or(FeasibilityError::InvalidVoter)?; - debug_assert!(*_voter == assignment.who); - - // Check that all of the targets are valid based on the snapshot. - if assignment.distribution.iter().any(|(t, _)| !targets.contains(t)) { - return Err(FeasibilityError::InvalidVote) - } - Ok(()) - }) - .collect::>()?; - - // ----- Start building support. First, we need one more closure. - let stake_of = helpers::stake_of_fn::(&voters_page, &voter_cache); - - // This might fail if the normalization fails. Very unlikely. See `integrity_test`. - let staked_assignments = - sp_npos_elections::assignment_ratio_to_staked_normalized(assignments, stake_of) - .map_err::(Into::into)?; - - let supports = sp_npos_elections::to_supports(&staked_assignments); - - // Check the maximum number of backers per winner. If this is a single-page solution, this - // is enough to check `MaxBackersPerWinner`. Else, this is just a heuristic, and needs to be - // checked again at the end (via `QueuedSolutionBackings`). - ensure!( - supports - .iter() - .all(|(_, s)| (s.voters.len() as u32) <= T::MaxBackersPerWinner::get()), - FeasibilityError::TooManyBackings - ); - - // supports per page must not be higher than the desired targets, otherwise final solution - // will also be higher than desired_targets. - ensure!((supports.len() as u32) <= desired_targets, FeasibilityError::WrongWinnerCount); - - // almost-defensive-only: `MaxBackersPerWinner` is already checked. A sane value of - // `MaxWinnersPerPage` should be more than any possible value of `desired_targets()`, which - // is ALSO checked, so this conversion can almost never fail. - let bounded_supports = supports - .try_into_bounded_supports() - .map_err(|_| FeasibilityError::WrongWinnerCount)?; - - Ok(bounded_supports) - } - - /// Greedily reduce the size of the solution to fit into the block w.r.t length. - /// - /// The length of the solution is largely a function of the number of voters. The number of - /// winners cannot be changed Thus, to reduce the solution size, we need to strip voters. - /// - /// Note that this solution is already computed, and winners are elected based on the merit of - /// the total stake in the system. Nevertheless, some of the voters may be removed here. - /// - /// Sometimes, removing a voter can cause a validator to also be implicitly removed, if - /// that voter was the only backer of that winner. In such cases, this solution is invalid, - /// which will be caught prior to submission. - /// - /// The score must be computed **after** this step. If this step reduces the score too much, - /// then the solution must be discarded. - pub fn trim_assignments_length( - max_allowed_length: u32, - assignments: &mut Vec>, - encoded_size_of: impl Fn( - &[IndexAssignmentOf], - ) -> Result, - ) -> Result { - // Perform a binary search for the max subset of which can fit into the allowed - // length. Having discovered that, we can truncate efficiently. - let max_allowed_length: usize = max_allowed_length.saturated_into(); - let mut high = assignments.len(); - let mut low = 0; - - // not much we can do if assignments are already empty. - if high == low { - return Ok(0) - } - - while high - low > 1 { - let test = (high + low) / 2; - if encoded_size_of(&assignments[..test])? <= max_allowed_length { - low = test; - } else { - high = test; - } - } - let maximum_allowed_voters = if low < assignments.len() && - encoded_size_of(&assignments[..low + 1])? <= max_allowed_length - { - low + 1 - } else { - low - }; - - // ensure our post-conditions are correct - //debug_assert!( - // encoded_size_of(&assignments[..maximum_allowed_voters]).unwrap() <= max_allowed_length - //); - debug_assert!(if maximum_allowed_voters < assignments.len() { - encoded_size_of(&assignments[..maximum_allowed_voters + 1]).unwrap() > - max_allowed_length - } else { - true - }); - - // NOTE: before this point, every access was immutable. - // after this point, we never error. - // check before edit. - - let remove = assignments.len().saturating_sub(maximum_allowed_voters); - assignments.truncate(maximum_allowed_voters); - - Ok(remove) - } - - /// Greedily reduce the size of the 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. - /// `assignments.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 from the `assignments`. - /// - /// Note that the solution is already computed, and the winners are elected based on the merit - /// of the 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 or remove a winner, then the solution must be discarded **after** this step. - pub fn trim_assignments_weight( - desired_targets: u32, - size: PageSize, - max_weight: Weight, - assignments: &mut Vec>, - ) -> usize { - let maximum_allowed_voters = - Self::maximum_voter_for_weight(desired_targets, size, max_weight); - let removing: usize = - assignments.len().saturating_sub(maximum_allowed_voters.saturated_into()); - assignments.truncate(maximum_allowed_voters as usize); - - removing - } - - /// Find the maximum `len` that a solution can have in order to fit into the block weight. - /// - /// This only returns a value between zero and `size.nominators`. - pub fn maximum_voter_for_weight( - _desired_winners: u32, - size: PageSize, - max_weight: Weight, - ) -> u32 { - if size.voters < 1 { - return size.voters - } - - let max_voters = size.voters.max(1); - let mut voters = max_voters; - - // helper closures. - let weight_with = |_active_voters: u32| -> Weight { - Weight::zero() // TODO - }; - - let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { - if current_weight.all_lt(max_weight) { - let next_voters = voters.checked_add(step); - match next_voters { - Some(voters) if voters < max_voters => Ok(voters), - _ => Err(()), - } - } else if current_weight.any_gt(max_weight) { - voters.checked_sub(step).ok_or(()) - } else { - // If any of the constituent weights is equal to the max weight, we're at max - 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 /= 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 < max_voters && weight_with(voters + 1).all_lt(max_weight) { - voters += 1; - } - while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { - voters -= 1; - } - - let final_decision = voters.min(size.voters); - debug_assert!( - weight_with(final_decision).all_lte(max_weight), - "weight_with({}) <= {}", - final_decision, - max_weight, - ); - final_decision - } -} - -/// Errors associated with the off-chain worker miner. -#[derive( - frame_support::DebugNoBound, frame_support::EqNoBound, frame_support::PartialEqNoBound, -)] -pub enum OffchainMinerError { - Miner(MinerError), - PoolSubmissionFailed, - NotUnsignedPhase, - StorageError, - PageOutOfBounds, - Snapshots, -} - -impl From for OffchainMinerError { - fn from(e: MinerError) -> Self { - OffchainMinerError::Miner(e) - } -} - -/// A miner used in the context of the offchain worker for unsigned submissions. -pub(crate) struct OffchainWorkerMiner(sp_std::marker::PhantomData); - -impl OffchainWorkerMiner { - /// The off-chain storage lock to work with unsigned submissions. - pub(crate) const OFFCHAIN_LOCK: &'static [u8] = b"parity/multi-block-unsigned-election/lock"; - - /// The off-chain storage ID prefix for each of the solution's pages. Each page will be - /// prefixed by this ID, followed by the page index. The full page ID for a given index can be - /// generated by [`Self::page_cache_id`]. - pub(crate) const OFFCHAIN_CACHED_SOLUTION: &'static [u8] = - b"parity/multi-block-unsigned-election/solution"; - - /// The off-chain storage ID for the solution's full score. - pub(crate) const OFFCHAIN_CACHED_SCORE: &'static [u8] = - b"parity/multi-block-unsigned-election/score"; - - /// Mine a solution. - /// - /// Mines a new solution with [`crate::Pallet::Pages`] pages and computes the partial score - /// of the page with `page` index. - #[allow(dead_code)] - pub fn mine( - page: PageIndex, - ) -> Result< - (ElectionScore, ElectionScore, ::Solution), - OffchainMinerError, - > { - let reduce = true; - - let (all_voter_pages, all_targets) = Self::fetch_snapshots()?; - let round = crate::Pallet::::current_round(); - let desired_targets = - <::DataProvider as ElectionDataProvider>::desired_targets() - .map_err(|_| MinerError::DataProvider)?; - - let (solution, _trimming_status) = - Miner::::mine_paged_solution_with_snapshot( - &all_voter_pages, - &all_targets, - T::Pages::get(), - round, - desired_targets, - reduce, - )?; - - let partial_solution = solution - .solution_pages - .get(page as usize) - .ok_or(OffchainMinerError::PageOutOfBounds)?; - - let partial_score = Miner::::compute_partial_score( - &all_voter_pages, - &all_targets, - &partial_solution, - desired_targets, - page, - )?; - - Ok((solution.score, partial_score, partial_solution.clone())) - } - - pub(crate) fn fetch_snapshots() -> Result< - (VoterSnapshotPagedOf, TargetSnaphsotOf), - OffchainMinerError, - > { - // prepare range to fetch all pages of the target and voter snapshot. - let paged_range = 0..EPM::::msp() + 1; - - // fetch all pages of the voter snapshot and collect them in a bounded vec. - let all_voter_pages: BoundedVec<_, T::Pages> = paged_range - .map(|page| { - Snapshot::::voters(page) - .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Voters(page))) - }) - .collect::, _>>()? - .try_into() - .expect("range was constructed from the bounded vec bounds; qed."); - - // fetch all pages of the target snapshot and collect them in a bounded vec. - let all_targets = Snapshot::::targets() - .ok_or(MinerError::SnapshotUnAvailable(SnapshotType::Targets))?; - - Ok((all_voter_pages, all_targets)) - } - - /// Fetches from the local storage or mines a new solution. - /// - /// Calculates and returns the partial score of paged solution of the given `page` index. - pub fn fetch_or_mine( - page: PageIndex, - ) -> Result< - (ElectionScore, ElectionScore, ::Solution), - OffchainMinerError, - > { - let cache_id = Self::paged_cache_id(page)?; - let score_storage = StorageValueRef::persistent(&Self::OFFCHAIN_CACHED_SCORE); - let maybe_storage = StorageValueRef::persistent(&cache_id); - - let (full_score, paged_solution, partial_score) = - if let Ok(Some((solution_page, partial_score))) = - maybe_storage.get::<(::Solution, ElectionScore)>() - { - sublog!(debug, "unsigned::ocw-miner", "offchain restoring a solution from cache."); - - let full_score = score_storage - .get() - .map_err(|_| OffchainMinerError::StorageError)? - .ok_or(OffchainMinerError::StorageError)?; - - (full_score, solution_page, partial_score) - } else { - // no solution cached, compute it first. - sublog!(debug, "unsigned::ocw-miner", "offchain miner computing a new solution."); - - // fetch snapshots. - let (all_voter_pages, all_targets) = Self::fetch_snapshots()?; - let round = crate::Pallet::::current_round(); - let desired_targets = - <::DataProvider as ElectionDataProvider>::desired_targets() - .map_err(|_| MinerError::DataProvider)?; - - let reduce = false; // TODO - - let (solution, _trimming_status) = - Miner::::mine_paged_solution_with_snapshot( - &all_voter_pages, - &all_targets, - T::Pages::get(), - round, - desired_targets, - reduce, - )?; - - // caches the solution score. - score_storage - .mutate::<_, (), _>(|_| Ok(solution.score.clone())) - .map_err(|_| OffchainMinerError::StorageError)?; - - let mut solution_page = Default::default(); - let mut partial_score_r: ElectionScore = Default::default(); - - // caches each of the individual pages and their partial score under its own key. - for (idx, paged_solution) in solution.solution_pages.into_iter().enumerate() { - let partial_score = Miner::::compute_partial_score( - &all_voter_pages, - &all_targets, - &paged_solution, - desired_targets, - idx as u32, - )?; - - let cache_id = Self::paged_cache_id(idx as PageIndex)?; - let storage = StorageValueRef::persistent(&cache_id); - storage - .mutate::<_, (), _>(|_| Ok((paged_solution.clone(), partial_score))) - .map_err(|_| OffchainMinerError::StorageError)?; - - // save to return the requested paged solution and partial score. - if idx as PageIndex == page { - solution_page = paged_solution; - partial_score_r = partial_score; - } - } - (solution.score, solution_page, partial_score_r) - }; - - Ok((full_score, partial_score, paged_solution)) - } - - /// Clears all local storage items related to the unsigned off-chain miner. - pub(crate) fn clear_cache() { - let mut score_storage = StorageValueRef::persistent(&Self::OFFCHAIN_CACHED_SCORE); - score_storage.clear(); - - for idx in (0..::Pages::get()).into_iter() { - let cache_id = Self::paged_cache_id(idx as PageIndex) - .expect("page index was calculated based on the msp."); - let mut page_storage = StorageValueRef::persistent(&cache_id); - - page_storage.clear(); - } - - sublog!(debug, "unsigned", "offchain miner cache cleared."); - } - - /// Generate the page cache ID based on the `page` index and the - /// [`Self::OFFCHAIN_CACHED_SOLUTION`] prefix. - fn paged_cache_id(page: PageIndex) -> Result, OffchainMinerError> { - let mut id = Self::OFFCHAIN_CACHED_SOLUTION.to_vec(); - id.push(page.try_into().map_err(|_| OffchainMinerError::PageOutOfBounds)?); - Ok(id) - } - - /// Submits a paged solution through the [`Call::submit_page_unsigned`] callable as an - /// inherent. - pub(crate) fn submit_paged_call( - page: PageIndex, - solution: ::Solution, - partial_score: ElectionScore, - claimed_full_score: ElectionScore, - ) -> Result<(), OffchainMinerError> { - sublog!( - debug, - "unsigned::ocw-miner", - "miner submitting a solution as an unsigned transaction, page: {:?}", - page, - ); - - let call = Call::submit_page_unsigned { page, solution, partial_score, claimed_full_score }; - let xt = T::create_inherent(call.into()); - - frame_system::offchain::SubmitTransaction::>::submit_transaction(xt) - .map(|_| { - sublog!( - debug, - "unsigned::ocw-miner", - "miner submitted a solution as an unsigned transaction, page {:?}", - page - ); - }) - .map_err(|_| OffchainMinerError::PoolSubmissionFailed) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs b/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs deleted file mode 100644 index 8d3b244b588a0..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/unsigned/mod.rs +++ /dev/null @@ -1,357 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Unsigned sub-pallet -//! -//! The main goal of this sub-pallet is to manage the unsigned phase submissions by an off-chain -//! worker. It implements the `offchain_worker` hook which will compute and store -//! in the off-chain cache a paged solution and try to submit it if: -//! -//! - Current phase is [`crate::Phase::Unsigned`]; -//! - The score of the computed solution is better than the minimum score defined by the verifier -//! pallet and the current election score stored by the [`crate::signed::Pallet`]. -//! -//! During the unsigned phase, multiple block builders will collaborate to submit the full -//! solution, one page per block. -//! -//! ## Sync/Async off-chain worker -//! -//! The unsigned phase relies on a mix of sync and async checks to ensure that the paged unsigned -//! submissions (and final solution) are correct, namely: -//! -//! - Synchronous checks: each block builder will compute the *full* election solution. However, -//! only one page -//! is verified through the [Verifier::verify_synchronous] and submitted through the -//! [`Call::submit_page_unsigned`] callable as an inherent. -//! - Asynchronous checks: once all pages are submitted, the [`Call::submit_page_unsigned`] will -//! call [`verifier::AsyncVerifier::force_finalize_verification`] to ensure that the full solution -//! submitted by all the block builders is good. -//! -//! In sum, each submitted page is verified using the synchronous verification implemented by the -//! verifier pallet (i.e. [`verifier::Verifier::verify_synchronous`]). The pages are submitted by -//! order from [`crate::Pallet::msp`] down to [`crate::Pallet::lsp`]. After successfully submitting -//! the last page, the [`verifier::AsyncVerifier::force_finalize_verification`], which will perform -//! the last feasibility checks over the full stored solution. -//! -//! At each block of the unsigned phase, the block builder running the node with the off-chain -//! worker enabled will compute a solution based on the round's snapshot. The solution is pagified -//! and stored in the local cache. -//! -//! The off-chain miner will *always* compute a new solution regardless of whether there -//! is a queued solution for the current era. The solution will be added to the storage through the -//! inherent [`Call::submit_page_unsigned`] only if the computed (total) solution score is strictly -//! better than the current queued solution. - -pub mod miner; -pub mod weights; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -#[cfg(test)] -mod tests; - -use crate::{ - unsigned::{ - miner::{OffchainMinerError, OffchainWorkerMiner}, - weights::WeightInfo, - }, - verifier, Phase, SolutionOf, Verifier, -}; -use frame_election_provider_support::PageIndex; -use frame_support::{ - ensure, - pallet_prelude::{TransactionValidity, ValidTransaction}, - traits::Get, -}; -use frame_system::{ensure_none, offchain::CreateInherent, pallet_prelude::BlockNumberFor}; -use sp_npos_elections::ElectionScore; -use sp_runtime::SaturatedConversion; - -// public re-exports. -pub use pallet::{ - Call, Config, Event, Pallet, __substrate_call_check, __substrate_event_check, - __substrate_validate_unsigned_check, tt_default_parts, tt_default_parts_v2, tt_error_token, -}; - -#[frame_support::pallet] -pub(crate) mod pallet { - - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::OriginFor; - - #[pallet::config] - #[pallet::disable_frame_system_supertrait_check] - pub trait Config: crate::Config + CreateInherent> { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// The off-chain worker interval between retrying to submit a solution. - type OffchainRepeatInterval: Get>; - - /// The priority of the unsigned tx submitted. - type MinerTxPriority: Get; - - /// Maximum length of the solution that the miner is allowed to generate. - /// - /// Solutions are trimmed to respect this. - type MaxLength: Get; - - /// Maximum weight of the solution that the miner is allowed to generate. - /// - /// Solutions are trimmed to respect this. - /// - /// The weight is computed using `solution_weight`. - type MaxWeight: Get; - - /// The weights for this pallet. - type WeightInfo: WeightInfo; - } - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// Unsigned solution submitted successfully. - UnsignedSolutionSubmitted { at: BlockNumberFor, page: PageIndex }, - } - - #[pallet::validate_unsigned] - impl ValidateUnsigned for Pallet { - type Call = Call; - - fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::submit_page_unsigned { page, partial_score, .. } = call { - ValidTransaction::with_tag_prefix("ElectionOffchainWorker") - // priority increases propotional to the `solution.minimal_stake`. - .priority( - T::MinerTxPriority::get() - .saturating_add(partial_score.minimal_stake.saturated_into()), - ) - // deduplicates unsigned solutions since each validator should calculate at most - // one paged solution per block. - .and_provides(page) - // transaction stays in the pool as long as the unsigned phase. - .longevity(T::UnsignedPhase::get().saturated_into::()) - .propagate(false) - .build() - } else { - sublog!(info, "unsigned", "validate_unsigned ERROR"); - InvalidTransaction::Call.into() - } - } - } - - #[pallet::call] - impl Pallet { - /// Submit a paged unsigned solution. - /// - /// The dispatch origin fo this call must be __none__. - /// - /// This submission is checked on the fly. Moreover, this unsigned solution is only - /// validated when submitted to the pool from the **local** node. Effectively, this means - /// that only active validators can submit this transaction when authoring a block (similar - /// to an inherent). - /// - /// To prevent any incorrect solution (and thus wasted time/weight), this transaction will - /// panic if the solution submitted by the validator is invalid in any way, effectively - /// putting their authoring reward at risk. - /// - /// No deposit or reward is associated with this submission. - #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::submit_page_unsigned( - ::MaxBackersPerWinner::get(), - ::MaxWinnersPerPage::get(), - ))] - pub fn submit_page_unsigned( - origin: OriginFor, - page: PageIndex, - solution: SolutionOf, - partial_score: ElectionScore, - claimed_full_score: ElectionScore, - ) -> DispatchResult { - ensure_none(origin)?; - let error_message = "Invalid unsigned submission must produce invalid block and \ - deprive validator from their authoring reward."; - - sublog!( - info, - "unsigned", - "submitting page {:?} with partial score {:?}", - page, - partial_score - ); - - // Check if score is an improvement, the current phase, page index and other paged - // solution metadata checks. - Self::pre_dispatch_checks(page, &claimed_full_score).expect(error_message); - - // The verifier will store the paged solution, if valid. - let _ = ::verify_synchronous( - solution, - partial_score, - page, - ) - .expect(error_message); - - // if all pages have been submitted, request an async verification finalization which - // will work on the queued paged solutions. - if ::next_missing_solution_page().is_none() { - ::force_finalize_verification( - claimed_full_score, - ) - .expect(error_message); - sublog!(info, "unsigned", "validate_unsigned last page verify OK"); - } else { - sublog!(info, "unsigned", "submit_page_unsigned: page {:?} submitted", page); - } - - Self::deposit_event(Event::UnsignedSolutionSubmitted { - at: >::block_number(), - page, - }); - - Ok(()) - } - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(_n: BlockNumberFor) -> Weight { - if crate::Pallet::::current_phase() == Phase::Off { - T::DbWeight::get().reads_writes(1, 1) - } else { - Default::default() - } - } - - /// The off-chain worker implementation - /// - /// The off-chain worker for this pallet will run IFF: - /// - /// - It can obtain the off-chain worker lock; - /// - The current block is part of the unsigned phase; - fn offchain_worker(now: BlockNumberFor) { - use sp_runtime::offchain::storage_lock::{BlockAndTime, StorageLock}; - - let mut lock = - StorageLock::>>::with_block_deadline( - miner::OffchainWorkerMiner::::OFFCHAIN_LOCK, - T::UnsignedPhase::get().saturated_into(), - ); - - if crate::Pallet::::current_phase().is_unsigned() { - match lock.try_lock() { - Ok(_guard) => { - sublog!(info, "unsigned", "obtained offchain lock at {:?}", now); - let _ = Self::do_sync_offchain_worker(now).map_err(|e| { - sublog!(debug, "unsigned", "offchain worker error."); - e - }); - }, - Err(deadline) => { - sublog!( - debug, - "unsigned", - "offchain worker lock not released, deadline is {:?}", - deadline - ); - }, - }; - } - } - - fn integrity_test() { - // TODO - } - - #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - todo!() - } - } -} - -impl Pallet { - /// Perform the off-chain worker workload. - /// - /// If the current block is part of the unsigned phase and there are missing solution pages: - /// - /// 1. Compute or restore a mined solution; - /// 2. Pagify the solution; - /// 3. Calculate the partial score for the page to submit; - /// 4. Verify if the *total* solution is strictly better than the current queued solution or - /// better than the minimum score, of no queued solution exists. - /// 5. Submits the paged solution as an inherent through the [`Call::submit_page_unsigned`] - /// callable. - pub fn do_sync_offchain_worker(_now: BlockNumberFor) -> Result<(), OffchainMinerError> { - let missing_solution_page = ::next_missing_solution_page(); - - match (crate::Pallet::::current_phase(), missing_solution_page) { - (Phase::Unsigned(_), Some(page)) => { - let (full_score, partial_score, partial_solution) = - OffchainWorkerMiner::::fetch_or_mine(page).map_err(|err| { - sublog!(error, "unsigned", "OCW mine error: {:?}", err); - err - })?; - - // submit page only if full score improves the current queued score. - if ::ensure_score_quality(full_score) { - OffchainWorkerMiner::::submit_paged_call( - page, - partial_solution, - partial_score, - full_score, - )?; - } else { - sublog!( - debug, - "unsigned", - "unsigned solution with score {:?} does not improve current queued solution; skip it.", - full_score - ); - } - }, - (Phase::Export(_), _) | (Phase::Unsigned(_), None) => { - // Unsigned phase is over or unsigned solution is no more required, clear the - // cache. - OffchainWorkerMiner::::clear_cache(); - }, - _ => (), // nothing to do here. - } - - Ok(()) - } - - /// Ihnerent pre-dispatch checks. - pub(crate) fn pre_dispatch_checks( - page: PageIndex, - claimed_full_score: &ElectionScore, - ) -> Result<(), ()> { - // timing and metadata checks. - ensure!(crate::Pallet::::current_phase().is_unsigned(), ()); - ensure!(page <= crate::Pallet::::msp(), ()); - - // full solution score check. - ensure!(::ensure_score_quality(*claimed_full_score), ()); - - Ok(()) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs b/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs deleted file mode 100644 index 3464eb0be4536..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/unsigned/tests.rs +++ /dev/null @@ -1,210 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use crate::{mock::*, PagedVoterSnapshot, Phase, Snapshot, TargetSnapshot, Verifier}; - -use frame_election_provider_support::ElectionProvider; -use frame_support::assert_ok; - -mod calls { - use super::*; - - #[test] - fn unsigned_submission_works() { - let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); - ext.execute_with(|| { - // election predicted at 30. - assert_eq!(election_prediction(), 30); - - // no solution available until the unsigned phase. - assert!(::queued_score().is_none()); - assert!(::get_queued_solution(2).is_none()); - - // progress through unsigned phase just before the election. - roll_to_with_ocw(29, Some(pool.clone())); - - // successful submission events for all 3 pages, as expected. - assert_eq!( - unsigned_events(), - [ - Event::UnsignedSolutionSubmitted { at: 19, page: 2 }, - Event::UnsignedSolutionSubmitted { at: 20, page: 1 }, - Event::UnsignedSolutionSubmitted { at: 21, page: 0 } - ] - ); - // now, solution exists. - assert!(::queued_score().is_some()); - assert!(::get_queued_solution(2).is_some()); - assert!(::get_queued_solution(1).is_some()); - assert!(::get_queued_solution(0).is_some()); - - // roll to election prediction bn. - roll_to_with_ocw(election_prediction(), Some(pool.clone())); - - // now in the export phase. - assert!(current_phase().is_export()); - - // thus, elect() works as expected. - assert!(call_elect().is_ok()); - - assert_eq!(current_phase(), Phase::Off); - }) - } - - #[test] - fn unsigned_submission_no_snapshot() { - let (mut ext, pool) = ExtBuilder::default().build_offchainify(1); - ext.execute_with(|| { - // election predicted at 30. - assert_eq!(election_prediction(), 30); - - roll_to_phase_with_ocw(Phase::Signed, Some(pool.clone())); - - // no solution available until the unsigned phase. - assert!(::queued_score().is_none()); - assert!(::get_queued_solution(2).is_none()); - - // but snapshot exists. - assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); - assert!(TargetSnapshot::::get().is_some()); - // so let's clear it. - clear_snapshot(); - assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_none()); - assert!(TargetSnapshot::::get().is_none()); - - // progress through unsigned phase just before the election. - roll_to_with_ocw(29, Some(pool.clone())); - - // snapshot was not available, so unsigned submissions and thus no solution queued. - assert_eq!(unsigned_events().len(), 0); - // no solution available until the unsigned phase. - assert!(::queued_score().is_none()); - assert!(::get_queued_solution(2).is_none()); - - // call elect (which fails) to restart the phase. - assert!(call_elect().is_err()); - assert_eq!(current_phase(), Phase::Off); - - roll_to_phase_with_ocw(Phase::Signed, Some(pool.clone())); - - // snapshot exists now. - assert!(PagedVoterSnapshot::::get(crate::Pallet::::lsp()).is_some()); - assert!(TargetSnapshot::::get().is_some()); - - roll_to_with_ocw(election_prediction() - 1, Some(pool.clone())); - - // successful submission events for all 3 pages, as expected. - assert_eq!( - unsigned_events(), - [ - Event::UnsignedSolutionSubmitted { at: 49, page: 2 }, - Event::UnsignedSolutionSubmitted { at: 50, page: 1 }, - Event::UnsignedSolutionSubmitted { at: 51, page: 0 } - ] - ); - // now, solution exists. - assert!(::queued_score().is_some()); - assert!(::get_queued_solution(2).is_some()); - assert!(::get_queued_solution(1).is_some()); - assert!(::get_queued_solution(0).is_some()); - - // elect() works as expected. - assert_ok!(::elect(2)); - assert_ok!(::elect(1)); - assert_ok!(::elect(0)); - - assert_eq!(current_phase(), Phase::Off); - }) - } -} - -mod miner { - use super::*; - - #[test] - fn snapshot_idx_based_works() { - ExtBuilder::default().build_and_execute(|| { - roll_to_phase(Phase::Signed); - - let mut all_voter_pages = vec![]; - let mut all_target_pages = vec![]; - - for page in (0..Pages::get()).rev() { - all_voter_pages.push(Snapshot::::voters(page).unwrap()); - all_target_pages.push(Snapshot::::targets().unwrap()); - } - }) - } - - #[test] - fn desired_targets_bounds_works() { - ExtBuilder::default() - .max_winners_per_page(3) - .desired_targets(3) - .build_and_execute(|| { - // max winner per page == desired_targets, OK. - compute_snapshot_checked(); - assert_ok!(mine_and_verify_all()); - - // max winner per page > desired_targets, OK. - MaxWinnersPerPage::set(4); - compute_snapshot_checked(); - assert_ok!(mine_and_verify_all()); - - // max winner per page < desired_targets, fails. - MaxWinnersPerPage::set(2); - compute_snapshot_checked(); - assert!(mine_and_verify_all().is_err()); - }) - } - - #[test] - fn fetch_or_mine() { - let (mut ext, _) = ExtBuilder::default().build_offchainify(1); - - ext.execute_with(|| { - let msp = crate::Pallet::::msp(); - assert_eq!(msp, 2); - - // no snapshot available, calling mine_paged_solution should fail. - assert!(::queued_score().is_none()); - assert!(::get_queued_solution(msp).is_none()); - - assert!(OffchainWorkerMiner::::fetch_or_mine(0).is_err()); - compute_snapshot_checked(); - - let (full_score_2, partial_score_2, _) = - OffchainWorkerMiner::::fetch_or_mine(msp).unwrap(); - let (full_score_1, partial_score_1, _) = - OffchainWorkerMiner::::fetch_or_mine(msp - 1).unwrap(); - let (full_score_0, partial_score_0, _) = - OffchainWorkerMiner::::fetch_or_mine(0).unwrap(); - - assert!(full_score_2 == full_score_1 && full_score_2 == full_score_0); - assert!( - full_score_2.sum_stake == full_score_1.sum_stake && - full_score_2.sum_stake == full_score_0.sum_stake - ); - - assert_eq!( - partial_score_0.sum_stake + partial_score_1.sum_stake + partial_score_2.sum_stake, - full_score_0.sum_stake - ); - }) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs b/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs deleted file mode 100644 index a593dfc8c7d9c..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/unsigned/weights.rs +++ /dev/null @@ -1,76 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -pub trait WeightInfo { - fn submit_page_unsigned(v: u32, t: u32) -> Weight; -} - -/// Weight functions for `pallet_epm_unsigned`. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::MinimumScore` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::MinimumScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn submit_page_unsigned(v: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `11869 + t * (10 ±0) + v * (71 ±0)` - // Estimated: `15334 + t * (10 ±0) + v * (71 ±0)` - // Minimum execution time: 1_382_000_000 picoseconds. - Weight::from_parts(3_157_322_580, 0) - .saturating_add(Weight::from_parts(0, 15334)) - // Standard Error: 80_316 - .saturating_add(Weight::from_parts(4_146_169, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 10).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 71).saturating_mul(v.into())) - } -} - - -impl WeightInfo for () { - fn submit_page_unsigned(_v: u32, _t: u32) -> Weight { - Default::default() - } -} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs b/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs deleted file mode 100644 index 8ac6d05250916..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/verifier/benchmarking.rs +++ /dev/null @@ -1,315 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Benchmarking for the Elections Multiblock Verifier sub-pallet. - -use super::*; -use crate::{ - benchmarking::helpers, - signed::pallet::Submissions, - unsigned::miner::OffchainWorkerMiner, - verifier::{AsyncVerifier, Status, Verifier}, - BenchmarkingConfig, ConfigCore, ConfigSigned, ConfigUnsigned, ConfigVerifier, PalletCore, - PalletVerifier, -}; -use frame_support::assert_ok; -use frame_system::RawOrigin; - -use frame_benchmarking::v2::*; - -#[benchmarks( - where T: ConfigCore + ConfigSigned + ConfigUnsigned + ConfigVerifier, -)] -mod benchmarks { - use super::*; - use frame_support::traits::Hooks; - - #[benchmark] - fn on_initialize_ongoing( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - let valid_solution = true; - let submitter = helpers::mine_and_submit::(Some(PalletCore::::msp()), valid_solution) - .map_err(|err| { - log!(error, "error mining and storing paged solutions, {:?}", err); - BenchmarkError::Stop("mine and store error") - })?; - - // page is ready for async verification. - assert!(Submissions::::get_page( - &submitter, - PalletCore::::current_round(), - PalletCore::::msp() - ) - .is_some()); - - // no backings for pages yet in storage. - assert!(PalletVerifier::::pages_backed() == 0); - - // set verifier status to pick first submitted page to verify. - as AsyncVerifier>::set_status( - Status::Ongoing(crate::Pallet::::msp()), - ); - - #[block] - { - PalletVerifier::::on_initialize(0u32.into()); - } - - // backings from submitted and verified page is in storage now - assert!(PalletVerifier::::pages_backed() == 1); - - Ok(()) - } - - #[benchmark] - fn on_initialize_ongoing_failed( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - let valid_solution = false; - let submitter = helpers::mine_and_submit::(Some(PalletCore::::msp()), valid_solution) - .map_err(|err| { - log!(error, "error mining and storing paged solutions, {:?}", err); - BenchmarkError::Stop("mine and store error") - })?; - - // page is ready for async verification. - assert!(Submissions::::get_page( - &submitter, - PalletCore::::current_round(), - PalletCore::::msp() - ) - .is_some()); - - // no backings for pages in storage. - assert!(PalletVerifier::::pages_backed() == 0); - - // set verifier status to pick first submitted page to verify. - as AsyncVerifier>::set_status( - Status::Ongoing(crate::Pallet::::msp()), - ); - - #[block] - { - PalletVerifier::::on_initialize(0u32.into()); - } - - // no backings for pages in storage due to failure. - assert!(PalletVerifier::::pages_backed() == 0); - - Ok(()) - } - - #[benchmark] - fn on_initialize_ongoing_finalize( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - // submit all pages with a valid solution. - let valid_solution = true; - let submitter = helpers::mine_and_submit::(None, valid_solution).map_err(|err| { - log!(error, "error mining and storing paged solutions, {:?}", err); - BenchmarkError::Stop("mine and store error") - })?; - - // all pages are ready for async verification. - for page in 0..T::Pages::get() { - assert!(Submissions::::get_page(&submitter, PalletCore::::current_round(), page) - .is_some()); - } - - // no backings for pages in storage. - assert!(PalletVerifier::::pages_backed() == 0); - // no queued score yet. - assert!( as Verifier>::queued_score().is_none()); - - // process all paged solutions but lsp. - for page in (1..T::Pages::get()).rev() { - as AsyncVerifier>::set_status(Status::Ongoing(page)); - Pallet::::on_initialize(0u32.into()); - } - - assert!(PalletVerifier::::pages_backed() as u32 == T::Pages::get().saturating_sub(1)); - - // set verifier status to pick last submitted page to verify. - as AsyncVerifier>::set_status(Status::Ongoing(PalletCore::::lsp())); - - #[block] - { - PalletVerifier::::on_initialize(0u32.into()); - } - - // OK, so score is queued. - assert!( as Verifier>::queued_score().is_some()); - - Ok(()) - } - - #[benchmark] - fn on_initialize_ongoing_finalize_failed( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - #[block] - { - let _ = 1 + 2; - } - - Ok(()) - } - - #[benchmark] - fn finalize_async_verification( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - #[block] - { - let _ = 1 + 2; - } - - Ok(()) - } - - #[benchmark] - fn verify_sync_paged( - v: Linear< - { ::BenchmarkingConfig::VOTERS_PER_PAGE[0] }, - { ::BenchmarkingConfig::VOTERS_PER_PAGE[1] }, - >, - t: Linear< - { ::BenchmarkingConfig::TARGETS_PER_PAGE[0] }, - { ::BenchmarkingConfig::TARGETS_PER_PAGE[1] }, - >, - ) -> Result<(), BenchmarkError> { - helpers::setup_data_provider::( - ::BenchmarkingConfig::VOTERS.max(v), - ::BenchmarkingConfig::TARGETS.max(t), - ); - - if let Err(err) = helpers::setup_snapshot::(v, t) { - log!(error, "error setting up snapshot: {:?}.", err); - return Err(BenchmarkError::Stop("snapshot error")); - } - - let (_claimed_full_score, partial_score, paged_solution) = - OffchainWorkerMiner::::mine(PalletCore::::msp()).map_err(|err| { - log!(error, "mine error: {:?}", err); - BenchmarkError::Stop("miner error") - })?; - - #[block] - { - assert_ok!(PalletVerifier::::do_verify_sync( - paged_solution, - partial_score, - PalletCore::::msp() - )); - } - - Ok(()) - } - - impl_benchmark_test_suite!( - PalletVerifier, - crate::mock::ExtBuilder::default(), - crate::mock::Runtime, - exec_name = build_and_execute - ); -} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs b/substrate/frame/election-provider-multi-block/src/verifier/impls.rs deleted file mode 100644 index c118debfd9074..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/verifier/impls.rs +++ /dev/null @@ -1,680 +0,0 @@ -// ohis file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use crate::{unsigned::miner, verifier::weights::WeightInfo, MinerSupportsOf, SolutionOf}; -use pallet::*; - -use frame_election_provider_support::PageIndex; -use frame_support::{ - ensure, - pallet_prelude::Weight, - traits::{Defensive, TryCollect}, - BoundedVec, -}; -use sp_runtime::{traits::Zero, Perbill}; -use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; - -#[frame_support::pallet] -pub(crate) mod pallet { - use super::*; - use frame_support::pallet_prelude::{ValueQuery, *}; - use frame_system::pallet_prelude::*; - - #[pallet::config] - #[pallet::disable_frame_system_supertrait_check] - pub trait Config: crate::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Origin that can control this pallet. This must be a *trusted origin* since the - /// actions taken by this origin are not checked (e.g. `set_emergency_solution`). - type ForceOrigin: EnsureOrigin; - - /// Minimum improvement to a solution that defines a new solution as "better". - type SolutionImprovementThreshold: Get; - - /// Something that can provide the solution data to the verifier. - type SolutionDataProvider: crate::verifier::SolutionDataProvider< - Solution = SolutionOf, - >; - - /// The weight information of this pallet. - type WeightInfo: WeightInfo; - } - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// A verificaction failed at the given page. - VerificationFailed(PageIndex, FeasibilityError), - /// The final verifications of the `finalize_verification` failed. If this error happened, - /// all the single pages passed the feasibility checks. - FinalVerificationFailed(FeasibilityError), - /// The given page has been correctly verified, with the number of backers that are part of - /// the page. - Verified(PageIndex, u32), - /// A new solution with the given score has replaced the previous best solution, if any. - Queued(ElectionScore, Option), - /// The solution data was not available for a specific page. - SolutionDataUnavailable(PageIndex), - } - - /// A wrapper type of the storage items related to the queued solution. - /// - /// It manages the following storage types: - /// - /// - [`QueuedSolutionX`]: variant X of the queued solution. - /// - [`QueuedSolutionY`]: variant Y of the queued solution. - /// - [`QueuedValidVariant`]: pointer to which variant is the currently valid. - /// - [`QueuedSolutionScore`]: the soltution score of the current valid variant. - /// - [`QueuedSolutionBackings`]. - /// - /// Note that, as an async verification is progressing, the paged solution is kept in the - /// invalid variant storage. A solution is considered valid only when all the single page and - /// full solution checks have been perform based on the stored [`QueuedSolutionBackings`]. for - /// the corresponding in-verification solution. After the solution verification is successful, - /// the election score can be calculated and stored. - /// - /// ### Invariants - /// - /// - [`QueuedSolutionScore`] must be always the correct queued score of a variant corresponding - /// to the [`QueuedValidVariant`]. - /// - [`QueuedSolution`] must always be [`Config::SolutionImprovementThreshold`] better than - /// [`MininumScore`]. - /// - The [`QueuedSolutionBackings`] are always the backings corresponding to the *invalid* - /// variant. - pub struct QueuedSolution(sp_std::marker::PhantomData); - - impl QueuedSolution { - fn mutate_checked(mutate: impl FnOnce() -> R) -> R { - let r = mutate(); - #[cfg(debug_assertions)] - assert!(Self::sanity_check().is_ok()); - r - } - - /// Clear all relevant data of an invalid solution. - /// - /// This should be called when a solution being verified is deemed infeasible. - pub(crate) fn clear_invalid_and_backings() { - let _ = match Self::invalid() { - SolutionPointer::X => QueuedSolutionX::::clear(u32::MAX, None), - SolutionPointer::Y => QueuedSolutionY::::clear(u32::MAX, None), - }; - let _ = QueuedSolutionBackings::::clear(u32::MAX, None); - } - - /// Clear all relevant storage items. - pub(crate) fn kill() { - Self::mutate_checked(|| { - let _ = QueuedSolutionX::::clear(u32::MAX, None); - let _ = QueuedSolutionY::::clear(u32::MAX, None); - QueuedValidVariant::::kill(); - let _ = QueuedSolutionBackings::::clear(u32::MAX, None); - QueuedSolutionScore::::kill(); - }) - } - - /// Finalize a correct solution. - /// - /// It should be called at the end of the verification process of a valid solution to update - /// the queued solution score and flip the invalid variant. - pub(crate) fn finalize_solution(score: ElectionScore) { - sublog!( - info, - "verifier", - "finalizing verification of a correct solution, replacing old score {:?} with {:?}", - QueuedSolutionScore::::get(), - score - ); - - Self::mutate_checked(|| { - QueuedValidVariant::::mutate(|v| *v = v.other()); - QueuedSolutionScore::::put(score); - }) - } - - /// Write a single page of a valid solution into the `invalid` variant of the storage. - /// - /// It should be called only once the page has been verified to be 100% correct. - pub(crate) fn set_page(page: PageIndex, supports: MinerSupportsOf) { - Self::mutate_checked(|| { - let backings: BoundedVec<_, _> = supports - .iter() - .map(|(x, s)| (x.clone(), PartialBackings {total: s.total, backers: s.voters.len() as u32})) - .try_collect() - .expect("`SupportsOf` is bounded by as Verifier>::MaxWinnersPerPage which is ensured by an integrity test; qed."); - - QueuedSolutionBackings::::insert(page, backings); - - // update the last stored page. - RemainingUnsignedPages::::mutate(|remaining| { - remaining.retain(|p| *p != page); - sublog!(debug, "verifier", "updated remaining pages, current: {:?}", remaining); - }); - - // store the new page into the invalid variant storage type. - match Self::invalid() { - SolutionPointer::X => QueuedSolutionX::::insert(page, supports), - SolutionPointer::Y => QueuedSolutionY::::insert(page, supports), - } - }) - } - - /// Computes the score and the winner count of a stored variant solution. - pub(crate) fn compute_current_score() -> Result<(ElectionScore, u32), FeasibilityError> { - // ensures that all the pages are complete; - if QueuedSolutionBackings::::iter_keys().count() != T::Pages::get() as usize { - return Err(FeasibilityError::Incomplete) - } - - let mut supports: BTreeMap = Default::default(); - for (who, PartialBackings { backers, total }) in - QueuedSolutionBackings::::iter().map(|(_, backings)| backings).flatten() - { - let entry = supports.entry(who).or_default(); - entry.total = entry.total.saturating_add(total); - entry.backers = entry.backers.saturating_add(backers); - - if entry.backers > T::MaxBackersPerWinner::get() { - return Err(FeasibilityError::TooManyBackings) - } - } - - let winners_count = supports.len() as u32; - let score = sp_npos_elections::evaluate_support( - supports.into_iter().map(|(_, backings)| backings), - ); - - Ok((score, winners_count)) - } - - /// Returns the current queued score, if any. - pub(crate) fn queued_score() -> Option { - QueuedSolutionScore::::get() - } - - /// Returns the current *valid* paged queued solution, if any. - pub(crate) fn get_queued_solution( - page: PageIndex, - ) -> Option> { - match Self::valid() { - SolutionPointer::X => QueuedSolutionX::::get(page), - SolutionPointer::Y => QueuedSolutionY::::get(page), - } - } - - /// Returns the pointer for the valid solution storage. - pub(crate) fn valid() -> SolutionPointer { - QueuedValidVariant::::get() - } - - /// Returns the pointer for the invalid solution storage. - pub(crate) fn invalid() -> SolutionPointer { - Self::valid().other() - } - - #[allow(dead_code)] - pub(crate) fn sanity_check() -> Result<(), &'static str> { - // TODO(gpestana) - Ok(()) - } - } - - /// Supports of the solution of the variant X. - /// - /// A potential valid or invalid solution may be stored in this variant during the round. - #[pallet::storage] - pub type QueuedSolutionX = - StorageMap<_, Twox64Concat, PageIndex, MinerSupportsOf>; - - /// Supports of the solution of the variant Y. - /// - /// A potential valid or invalid solution may be stored in this variant during the round. - #[pallet::storage] - pub type QueuedSolutionY = - StorageMap<_, Twox64Concat, PageIndex, MinerSupportsOf>; - - /// The `(amount, count)` of backings, keyed by page. - /// - /// This is stored to facilitate the `MaxBackersPerWinner` check at the end of an async - /// verification. Once the solution is valid (i.e. verified), the solution backings are not - /// useful anymore and can be cleared. - #[pallet::storage] - pub(crate) type QueuedSolutionBackings = StorageMap< - _, - Twox64Concat, - PageIndex, - BoundedVec<(T::AccountId, PartialBackings), T::MaxWinnersPerPage>, - >; - - /// The score of the current valid solution. - #[pallet::storage] - type QueuedSolutionScore = StorageValue<_, ElectionScore>; - - /// Pointer for the storage variant (X or Y) that stores the current valid variant. - #[pallet::storage] - type QueuedValidVariant = StorageValue<_, SolutionPointer, ValueQuery>; - - /// The minimum score that each solution must have to be considered feasible. - #[pallet::storage] - pub(crate) type MinimumScore = StorageValue<_, ElectionScore>; - - /// Current status of the verification process. - #[pallet::storage] - pub(crate) type VerificationStatus = StorageValue<_, Status, ValueQuery>; - - // For unsigned page solutions only. - #[pallet::storage] - pub(crate) type RemainingUnsignedPages = - StorageValue<_, BoundedVec, ValueQuery>; - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(n: BlockNumberFor) -> Weight { - Self::do_on_initialize(n) - } - - fn integrity_test() { - // TODO(gpestana): add more integrity tests related to queued solution et al. - assert_eq!(T::MaxWinnersPerPage::get(), ::MaxWinnersPerPage::get()); - assert_eq!( - T::MaxBackersPerWinner::get(), - ::MaxBackersPerWinner::get() - ); - } - - #[cfg(feature = "try-runtime")] - fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { - Self::do_try_state() - } - } -} - -impl Verifier for Pallet { - type AccountId = T::AccountId; - type Solution = SolutionOf; - type MaxWinnersPerPage = T::MaxWinnersPerPage; - type MaxBackersPerWinner = T::MaxBackersPerWinner; - - fn set_minimum_score(score: ElectionScore) { - MinimumScore::::put(score); - } - - fn queued_score() -> Option { - QueuedSolution::::queued_score() - } - - fn ensure_score_quality(claimed_score: ElectionScore) -> bool { - Self::ensure_score_quality(claimed_score).is_ok() - } - - fn get_queued_solution(page_index: PageIndex) -> Option> { - QueuedSolution::::get_queued_solution(page_index) - } - - fn next_missing_solution_page() -> Option { - let next_missing = RemainingUnsignedPages::::get().last().copied(); - sublog!(debug, "verifier", "next missing page: {:?}", next_missing); - - next_missing - } - - fn kill() { - QueuedSolution::::kill(); - >::put(Status::Nothing); - } - - fn verify_synchronous( - partial_solution: Self::Solution, - partial_score: ElectionScore, - page: PageIndex, - ) -> Result, FeasibilityError> { - let maybe_current_score = Self::queued_score(); - match Self::do_verify_sync(partial_solution, partial_score, page) { - Ok(supports) => { - sublog!( - trace, - "verifier", - "queued sync solution with score {:?} (page {:?})", - partial_score, - page - ); - Self::deposit_event(Event::::Verified(page, supports.len() as u32)); - Self::deposit_event(Event::::Queued(partial_score, maybe_current_score)); - Ok(supports) - }, - Err(err) => { - sublog!( - trace, - "verifier", - "sync verification failed with {:?} (page: {:?})", - err, - page - ); - Self::deposit_event(Event::::VerificationFailed(page, err.clone())); - Err(err) - }, - } - } - - fn feasibility_check( - solution: Self::Solution, - page: PageIndex, - ) -> Result, FeasibilityError> { - let targets = - crate::Snapshot::::targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - - // prepare range to fetch all pages of the target and voter snapshot. - let paged_range = 0..crate::Pallet::::msp() + 1; - - // fetch all pages of the voter snapshot and collect them in a bounded vec. - let all_voter_pages: BoundedVec<_, T::Pages> = paged_range - .map(|page| { - crate::Snapshot::::voters(page).ok_or(FeasibilityError::SnapshotUnavailable) - }) - .collect::, _>>()? - .try_into() - .expect("range was constructed from the bounded vec bounds; qed."); - - let desired_targets = - crate::Snapshot::::desired_targets().ok_or(FeasibilityError::SnapshotUnavailable)?; - - miner::Miner::::feasibility_check_partial( - &all_voter_pages, - &targets, - solution, - desired_targets, - page, - ) - } -} - -impl AsyncVerifier for Pallet { - type SolutionDataProvider = T::SolutionDataProvider; - - fn force_finalize_verification(claimed_score: ElectionScore) -> Result<(), FeasibilityError> { - Self::finalize_async_verification(claimed_score) - } - - fn status() -> Status { - VerificationStatus::::get() - } - - fn start() -> Result<(), &'static str> { - if let Status::Nothing = Self::status() { - let claimed_score = Self::SolutionDataProvider::get_score().unwrap_or_default(); - - if Self::ensure_score_quality(claimed_score).is_err() { - Self::deposit_event(Event::::VerificationFailed( - crate::Pallet::::msp(), - FeasibilityError::ScoreTooLow, - )); - // report to the solution data provider that the page verification failed. - T::SolutionDataProvider::report_result(VerificationResult::Rejected); - // despite the verification failed, this was a successful `start` operation. - Ok(()) - } else { - VerificationStatus::::put(Status::Ongoing(crate::Pallet::::msp())); - Ok(()) - } - } else { - sublog!(warn, "verifier", "tries to start election while ongoing, ignored."); - Err("verification ongoing") - } - } - - fn stop() { - sublog!(warn, "verifier", "stop signal received. clearing everything."); - QueuedSolution::::clear_invalid_and_backings(); - - // if a verification is ongoing, signal the solution rejection to the solution data - // provider and reset the current status. - VerificationStatus::::mutate(|status| { - if matches!(status, Status::Ongoing(_)) { - T::SolutionDataProvider::report_result(VerificationResult::Rejected); - }; - *status = Status::Nothing; - }); - } - - // Sets current verifications status. - #[cfg(any(test, feature = "runtime-benchmarks"))] - fn set_status(status: Status) { - VerificationStatus::::put(status); - } -} - -impl Pallet { - fn do_on_initialize(_now: crate::BlockNumberFor) -> Weight { - let max_backers_winner = T::MaxBackersPerWinner::get(); - let max_winners_page = T::MaxWinnersPerPage::get(); - - match crate::Pallet::::current_phase() { - // reset remaining unsigned pages after snapshot is created. - crate::Phase::Snapshot(page) if page == crate::Pallet::::lsp() => { - RemainingUnsignedPages::::mutate(|remaining| { - *remaining = BoundedVec::truncate_from( - (crate::Pallet::::lsp()..crate::Pallet::::msp() + 1) - .collect::>(), - ); - }); - - sublog!( - debug, - "verifier", - "reset remaining unsgined pages to {:?}", - RemainingUnsignedPages::::get() - ); - }, - _ => (), - } - - if let Status::Ongoing(current_page) = >::get() { - let maybe_page_solution = - ::get_paged_solution(current_page); - - if maybe_page_solution.is_none() { - sublog!( - error, - "verifier", - "T::SolutionDataProvider failed to deliver page {} at {:?}.", - current_page, - crate::Pallet::::current_phase(), - ); - // reset election data and notify the `T::SolutionDataProvider`. - QueuedSolution::::clear_invalid_and_backings(); - VerificationStatus::::put(Status::Nothing); - T::SolutionDataProvider::report_result(VerificationResult::DataUnavailable); - - Self::deposit_event(Event::::SolutionDataUnavailable(current_page)); - - return ::WeightInfo::on_initialize_ongoing_failed( - max_backers_winner, - max_winners_page, - ); - } - - let page_solution = maybe_page_solution.expect("page solution checked to exist; qed."); - let maybe_supports = Self::feasibility_check(page_solution, current_page); - - // TODO: can refator out some of these code blocks to clean up the code. - let weight_consumed = match maybe_supports { - Ok(supports) => { - Self::deposit_event(Event::::Verified(current_page, supports.len() as u32)); - QueuedSolution::::set_page(current_page, supports); - - if current_page > crate::Pallet::::lsp() { - // election didn't finish, tick forward. - VerificationStatus::::put(Status::Ongoing( - current_page.saturating_sub(1), - )); - ::WeightInfo::on_initialize_ongoing( - max_backers_winner, - max_winners_page, - ) - } else { - // last page, finalize everything. At this point, the solution data - // provider should have a score ready for us. Otherwise, a default score - // will reset the whole election which is the desired behaviour. - let claimed_score = - T::SolutionDataProvider::get_score().defensive_unwrap_or_default(); - - // reset the election status. - VerificationStatus::::put(Status::Nothing); - - match Self::finalize_async_verification(claimed_score) { - Ok(_) => { - T::SolutionDataProvider::report_result(VerificationResult::Queued); - ::WeightInfo::on_initialize_ongoing_finalize( - max_backers_winner, - max_winners_page, - ) - }, - Err(_) => { - T::SolutionDataProvider::report_result( - VerificationResult::Rejected, - ); - // kill the solution in case of error. - QueuedSolution::::clear_invalid_and_backings(); - ::WeightInfo::on_initialize_ongoing_finalize_failed( - max_backers_winner, - max_winners_page, - ) - }, - } - } - }, - Err(err) => { - // the paged solution is invalid. - Self::deposit_event(Event::::VerificationFailed(current_page, err)); - VerificationStatus::::put(Status::Nothing); - QueuedSolution::::clear_invalid_and_backings(); - T::SolutionDataProvider::report_result(VerificationResult::Rejected); - - // TODO: may need to be a differnt another branch. - ::WeightInfo::on_initialize_ongoing_finalize_failed( - max_backers_winner, - max_winners_page, - ) - }, - }; - - weight_consumed - } else { - // nothing to do yet. - // TOOD(return weight reads=1) - Default::default() - } - } - - pub(crate) fn do_verify_sync( - partial_solution: SolutionOf, - partial_score: ElectionScore, - page: PageIndex, - ) -> Result, FeasibilityError> { - let _ = Self::ensure_score_quality(partial_score)?; - let supports = Self::feasibility_check(partial_solution.clone(), page)?; - - // TODO: implement fn evaluate on `BondedSupports`; remove extra clone. - let real_score = sp_npos_elections::evaluate_support( - supports.clone().into_iter().map(|(_, backings)| backings), - ); - ensure!(real_score == partial_score, FeasibilityError::InvalidScore); - - // queue valid solution of single page. - QueuedSolution::::set_page(page, supports.clone()); - - Ok(supports) - } - - pub(crate) fn finalize_async_verification( - claimed_score: ElectionScore, - ) -> Result<(), FeasibilityError> { - let outcome = QueuedSolution::::compute_current_score() - .and_then(|(final_score, winner_count)| { - let desired_targets = crate::Snapshot::::desired_targets().unwrap_or_default(); - - match (final_score == claimed_score, winner_count <= desired_targets) { - (true, true) => { - QueuedSolution::::finalize_solution(final_score); - Self::deposit_event(Event::::Queued( - final_score, - QueuedSolution::::queued_score(), - )); - - Ok(()) - }, - (false, true) => Err(FeasibilityError::InvalidScore), - (true, false) => Err(FeasibilityError::WrongWinnerCount), - (false, false) => Err(FeasibilityError::InvalidScore), - } - }) - .map_err(|err| { - sublog!(warn, "verifier", "finalizing the solution was invalid due to {:?}", err); - Self::deposit_event(Event::::VerificationFailed(Zero::zero(), err.clone())); - err - }); - - sublog!(debug, "verifier", "finalize verification outcome: {:?}", outcome); - outcome - } - - /// Checks if `score` improves the current queued score by `T::SolutionImprovementThreshold` and - /// that it is higher than `MinimumScore`. - pub fn ensure_score_quality(score: ElectionScore) -> Result<(), FeasibilityError> { - let is_improvement = ::queued_score().map_or(true, |best_score| { - score.strict_threshold_better(best_score, T::SolutionImprovementThreshold::get()) - }); - ensure!(is_improvement, FeasibilityError::ScoreTooLow); - - let is_greater_than_min_trusted = MinimumScore::::get() - .map_or(true, |min_score| score.strict_threshold_better(min_score, Perbill::zero())); - - ensure!(is_greater_than_min_trusted, FeasibilityError::ScoreTooLow); - Ok(()) - } - - /// Returns the number backings/pages verified and stored. - #[cfg(any(test, feature = "runtime-benchmarks"))] - #[allow(dead_code)] - pub(crate) fn pages_backed() -> usize { - QueuedSolutionBackings::::iter_keys().count() - } -} - -#[cfg(feature = "try-runtime")] -impl Pallet { - pub(crate) fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { - Self::check_variants() - } - - /// Invariants: - /// - /// 1. The valid and invalid solution pointers are always different. - fn check_variants() -> Result<(), sp_runtime::TryRuntimeError> { - ensure!( - QueuedSolution::::valid() != QueuedSolution::::invalid(), - "valid and invalid solution pointers are the same" - ); - Ok(()) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs b/substrate/frame/election-provider-multi-block/src/verifier/mod.rs deleted file mode 100644 index 47f73bbed861b..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/verifier/mod.rs +++ /dev/null @@ -1,291 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 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. - -//! # Verifier sub-pallet -//! -//! This pallet implements the NPoS solution verification logic. It supports both synchronous and -//! asynchronous verification of paged solutions. Moreover, it manages and ultimately stores -//! the best correct solution in a round, which can be requested by the election provider at the -//! time of the election. -//! -//! The paged solution data to be verified async is retrieved through the -//! [`Config::SolutionDataProvider`] implementor which most likely is the signed pallet. -//! -//! ## Feasibility check -//! -//! The goal of the feasibility of a solution is to ensure that a provided -//! [`crate::Config::Solution`] is correct based on the voter and target snapshots of a given round -//! kept by the parent pallet. The correctness of a solution is defined as: -//! -//! - The edges of a solution (voter -> targets) match the expected by the current snapshot. This -//! check can be performed at the page level. -//! - The total number of winners in the solution is sufficient. This check can only be performed -//! when the full paged solution is available;; -//! - The election score is higher than the expected minimum score. This check can only be performed -//! when the full paged solution is available;; -//! - All of the bounds of the election are respected, namely: -//! * [`Verifier::MaxBackersPerWinner`] - which set the total max of voters are backing a target, -//! per election. This check can only be performed when the full paged solution is available; -//! * [`Verifier::MaxWinnersPerPage`] - which ensure that a paged solution has a bound on the -//! number of targets. This check can be performed at the page level. -//! -//! Some checks can be performed at the page level (e.g. correct edges check) while others can only -//! be performed when the full solution is available. -//! -//! ## Sync and Async verification modes -//! -//! 1. Single-page, synchronous verification. This mode is used when a single page needs to be -//! verified on the fly, e.g. unsigned submission. -//! 2. Multi-page, asynchronous verification. This mode is used in the context of the multi-paged -//! signed solutions. -//! -//! The [`crate::verifier::Verifier`] and [`crate::verifier::AsyncVerifier`] traits define the -//! interface of each of the verification modes and this pallet implements both traits. -//! -//! ## Queued solution -//! -//! Once a solution has been succefully verified, it is stored in a queue. This pallet implements -//! the [`SolutionDataProvider`] trait which allows the parent pallet to request a correct -//! solution for the current round. - -mod impls; -pub mod weights; - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; - -#[cfg(test)] -mod tests; - -use crate::{PageIndex, SupportsOf}; -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::traits::Get; -use sp_npos_elections::{ElectionScore, ExtendedBalance}; -use sp_runtime::RuntimeDebug; - -// public re-exports. -pub use impls::pallet::{ - Call, Config, Event, Pallet, __substrate_call_check, __substrate_event_check, tt_default_parts, - tt_default_parts_v2, tt_error_token, -}; - -/// Errors related to the solution feasibility checks. -#[derive(Debug, Eq, PartialEq, codec::Encode, codec::Decode, scale_info::TypeInfo, Clone)] -pub enum FeasibilityError { - /// Election score is too low to be accepted. - ScoreTooLow, - /// Ongoing verification was not completed. - Incomplete, - /// Solution exceeds the number of backers per winner for at least one winner. - TooManyBackings, - /// Solution exceeds the number of winners. - WrongWinnerCount, - /// Snapshot is not available. - SnapshotUnavailable, - /// A voter is invalid. - InvalidVoter, - /// A vote is invalid. - InvalidVote, - /// Solution with an invalid score. - InvalidScore, - /// Internal election error. - #[codec(skip)] - NposElection(sp_npos_elections::Error), -} - -impl From for FeasibilityError { - fn from(err: sp_npos_elections::Error) -> Self { - FeasibilityError::NposElection(err) - } -} - -/// The status of this pallet. -/// -/// This pallet is either processing an async verification or doing nothing. A single page -/// verification can only be done while the pallet has status [`Status::Nothing`]. -#[derive(Encode, Decode, scale_info::TypeInfo, Clone, Copy, MaxEncodedLen, RuntimeDebug)] -pub enum Status { - /// A paged solution is ongoing and the next page to be verified is indicated in the inner - /// value. - Ongoing(PageIndex), - /// Nothing is happening. - Nothing, -} - -impl Default for Status { - fn default() -> Self { - Status::Nothing - } -} - -/// Pointer to the current valid solution of `QueuedSolution`. -#[derive(Encode, Decode, scale_info::TypeInfo, Clone, Copy, MaxEncodedLen, Debug, PartialEq)] -pub enum SolutionPointer { - /// Solution pointer variant `X`. - X, - /// Solution pointer variant `Y`. - Y, -} - -impl Default for SolutionPointer { - fn default() -> Self { - SolutionPointer::X - } -} - -impl SolutionPointer { - /// Returns the other variant of the current solution pointer in storage. - pub fn other(&self) -> SolutionPointer { - match *self { - SolutionPointer::X => SolutionPointer::Y, - SolutionPointer::Y => SolutionPointer::X, - } - } -} - -/// A type that represents a *partial* backing of a winner. It does not contain the -/// supports normally associated with a list of backings. -#[derive(Debug, Default, Encode, Decode, MaxEncodedLen, scale_info::TypeInfo)] -pub struct PartialBackings { - /// Total backing of a particular winner. - total: ExtendedBalance, - /// Number of backers. - backers: u32, -} - -impl sp_npos_elections::Backings for PartialBackings { - /// Returns the total backings of the winner. - fn total(&self) -> ExtendedBalance { - self.total - } -} - -/// The interface of something that can verify solutions for election in a multi-block context. -pub trait Verifier { - /// The account ID type. - type AccountId; - - /// The solution type; - type Solution; - - /// Maximum number of winners that a page supports. - /// - /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. - type MaxWinnersPerPage: Get; - - /// Maximum number of backers that each winner can have. - type MaxBackersPerWinner: Get; - - /// Sets the minimum score that an election must have from now on. - fn set_minimum_score(score: ElectionScore); - - /// Fetches the current queued election score, if any. - /// - /// Returns `None` if not score is queued. - fn queued_score() -> Option; - - /// Check if a claimed score improves the current queued score or if it is higher than a - /// potential minimum score. - fn ensure_score_quality(claimed_score: ElectionScore) -> bool; - - /// Returns the next missing solution page. - fn next_missing_solution_page() -> Option; - - /// Clears all the storage items related to the verifier pallet. - fn kill(); - - /// Get a single page of the best verified solutions, if any. - fn get_queued_solution(page_index: PageIndex) -> Option>; - - /// Perform the feasibility check on a given single-page solution. - /// - /// This will perform: - /// 1. feasibility-check - /// 2. claimed score is correct and it is an improvements - /// 3. check if bounds are correct - /// 4. store the solution if all checks pass - fn verify_synchronous( - partial_solution: Self::Solution, - claimed_score: ElectionScore, - page: PageIndex, - ) -> Result, FeasibilityError>; - - /// Just perform a single-page feasibility-check, based on the standards of this pallet. - /// - /// No score check is part of this. - fn feasibility_check( - partial_solution: Self::Solution, - page: PageIndex, - ) -> Result, FeasibilityError>; -} - -/// Something that can verify a solution asynchronously. -pub trait AsyncVerifier: Verifier { - /// The data provider that can provide the candidate solution to verify. The result of the - /// verification is returned back to this entity. - type SolutionDataProvider: SolutionDataProvider; - - /// Forces finalizing the async verification. - fn force_finalize_verification(claimed_score: ElectionScore) -> Result<(), FeasibilityError>; - - /// Returns the status of the current verification. - fn status() -> Status; - - /// Start a verification process. - fn start() -> Result<(), &'static str>; // new error type? - - /// Stop the verification. - /// - /// An implementation must ensure that all related state and storage items are cleaned. - fn stop(); - - /// Sets current status. Only used for benchmarks and tests. - #[cfg(any(test, feature = "runtime-benchmarks"))] - fn set_status(status: Status); -} - -/// Encapsulates the result of the verification of a candidate solution. -#[derive(Clone, Copy, RuntimeDebug)] -#[cfg_attr(test, derive(PartialEq, Eq))] -pub enum VerificationResult { - /// Solution is valid and is queued. - Queued, - /// Solution is rejected, for whichever of the multiple reasons that it could be. - Rejected, - /// The data needed (solution pages or the score) was unavailable. This should rarely happen. - DataUnavailable, -} - -/// Something that provides paged solution data for the verifier. -/// -/// This can be implemented by [`crate::signed::Pallet`] where signed solutions are queued and -/// sorted based on the solution's score. -pub trait SolutionDataProvider { - // The solution type. - type Solution; - - /// Returns the `page`th page of the current best solution that the data provider has in store, - /// if it exists. Otherwise it returns `None`. - fn get_paged_solution(page: PageIndex) -> Option; - - /// Get the claimed score of the current best solution. - fn get_score() -> Option; - - /// Hook to report back the results of the verification of the current candidate solution that - /// is being exposed via [`Self::get_paged_solution`] and [`Self::get_score`]. - fn report_result(result: VerificationResult); -} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/tests.rs b/substrate/frame/election-provider-multi-block/src/verifier/tests.rs deleted file mode 100644 index f0e3663883271..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/verifier/tests.rs +++ /dev/null @@ -1,162 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::{ - mock::*, - verifier::{impls::pallet::*, *}, - Phase, -}; -use frame_support::{assert_err, assert_noop, assert_ok}; -use sp_npos_elections::ElectionScore; -use sp_runtime::Perbill; - -#[test] -fn ensure_score_quality_works() { - ExtBuilder::default() - .solution_improvements_threshold(Perbill::from_percent(10)) - .build_and_execute(|| { - assert_eq!(MinimumScore::::get(), Default::default()); - assert!( as Verifier>::queued_score().is_none()); - - // if minimum score is not set and there's no queued score, any score has quality. - assert_ok!(Pallet::::ensure_score_quality(ElectionScore { - minimal_stake: 1, - sum_stake: 1, - sum_stake_squared: 1 - })); - - // if minimum score is set, the score being evaluated must be higher than the minimum - // score. - MinimumScore::::set( - ElectionScore { minimal_stake: 10, sum_stake: 20, sum_stake_squared: 300 }.into(), - ); - - // score is not higher than minimum score. - assert_err!( - Pallet::::ensure_score_quality(ElectionScore { - minimal_stake: 1, - sum_stake: 1, - sum_stake_squared: 1, - }), - FeasibilityError::ScoreTooLow - ); - - // if score improves the current one by the minimum solution improvement, we're gold. - assert_ok!(Pallet::::ensure_score_quality(ElectionScore { - minimal_stake: 11, - sum_stake: 22, - sum_stake_squared: 300 - })); - }) -} - -mod solution { - use super::*; - - #[test] - fn variant_flipping_works() { - ExtBuilder::default().build_and_execute(|| { - assert!(QueuedSolution::::valid() != QueuedSolution::::invalid()); - - let valid_before = QueuedSolution::::valid(); - let invalid_before = valid_before.other(); - - let mock_score = ElectionScore { minimal_stake: 10, ..Default::default() }; - - // queue solution and flip variant. - QueuedSolution::::finalize_solution(mock_score); - - // solution has been queued - assert_eq!(QueuedSolution::::queued_score().unwrap(), mock_score); - // variant has flipped. - assert_eq!(QueuedSolution::::valid(), invalid_before); - assert_eq!(QueuedSolution::::invalid(), valid_before); - }) - } -} - -mod feasibility_check { - use super::*; - - #[test] - fn winner_indices_page_in_bounds() { - ExtBuilder::default().pages(1).desired_targets(2).build_and_execute(|| { - roll_to_phase(Phase::Signed); - let mut solution = mine_full(1).unwrap(); - assert_eq!(crate::Snapshot::::targets().unwrap().len(), 8); - - // swap all votes from 3 to 4 to invalidate index 4. - solution.solution_pages[0] - .votes1 - .iter_mut() - .filter(|(_, t)| *t == TargetIndex::from(3u16)) - .for_each(|(_, t)| *t += 1); - - assert_noop!( - VerifierPallet::feasibility_check(solution.solution_pages[0].clone(), 0), - FeasibilityError::InvalidVote, - ); - }) - } -} - -mod sync_verifier { - use super::*; - - #[test] - fn sync_verifier_simple_works() { - ExtBuilder::default().build_and_execute(|| {}) - } - - #[test] - fn next_missing_solution_works() { - ExtBuilder::default().build_and_execute(|| { - let supports: SupportsOf> = Default::default(); - let msp = crate::Pallet::::msp(); - assert!(msp == ::Pages::get() - 1 && msp == 2); - - // run to snapshot phase to reset `RemainingUnsignedPages`. - roll_to_phase(Phase::Snapshot(crate::Pallet::::lsp())); - - // msp page is the next missing. - assert_eq!(::next_missing_solution_page(), Some(msp)); - - // X is the current valid solution, let's work with it. - assert_eq!(QueuedSolution::::valid(), SolutionPointer::X); - - // set msp and check the next missing page again. - QueuedSolution::::set_page(msp, supports.clone()); - assert_eq!(::next_missing_solution_page(), Some(msp - 1)); - - QueuedSolution::::set_page(msp - 1, supports.clone()); - assert_eq!(::next_missing_solution_page(), Some(0)); - - // set last page, missing page after is None as solution is complete. - QueuedSolution::::set_page(0, supports.clone()); - assert_eq!(::next_missing_solution_page(), None); - }) - } -} - -mod async_verifier { - use super::*; - - #[test] - fn async_verifier_simple_works() { - ExtBuilder::default().build_and_execute(|| {}) - } -} diff --git a/substrate/frame/election-provider-multi-block/src/verifier/weights.rs b/substrate/frame/election-provider-multi-block/src/verifier/weights.rs deleted file mode 100644 index ba9968ec1407b..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/verifier/weights.rs +++ /dev/null @@ -1,240 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -pub trait WeightInfo { - fn on_initialize_ongoing(v: u32, t: u32) -> Weight; - fn on_initialize_ongoing_failed(v: u32, t: u32) -> Weight; - fn on_initialize_ongoing_finalize(v: u32, t: u32) -> Weight; - fn on_initialize_ongoing_finalize_failed(v: u32, t: u32) -> Weight; - fn finalize_async_verification(v: u32, t: u32, ) -> Weight; - fn verify_sync_paged(v: u32, t: u32, ) -> Weight; -} - -/// Weight functions for `pallet_epm_verifier`. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) - /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:0) - /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:0) - /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn on_initialize_ongoing(v: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `12992 + t * (26 ±0) + v * (80 ±0)` - // Estimated: `15414 + t * (27 ±1) + v * (80 ±2)` - // Minimum execution time: 2_036_000_000 picoseconds. - Weight::from_parts(2_036_000_000, 0) - .saturating_add(Weight::from_parts(0, 15414)) - // Standard Error: 3_307_370 - .saturating_add(Weight::from_parts(20_614_626, 0).saturating_mul(v.into())) - // Standard Error: 1_618_727 - .saturating_add(Weight::from_parts(1_324_037, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 27).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 80).saturating_mul(v.into())) - } - /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) - /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:1) - /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:1) - /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SubmissionMetadataStorage` (r:1 w:1) - /// Proof: `ElectionSignedPallet::SubmissionMetadataStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn on_initialize_ongoing_failed(v: u32, _t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + t * (4 ±0) + v * (112 ±0)` - // Estimated: `7604 + v * (108 ±2)` - // Minimum execution time: 1_034_000_000 picoseconds. - Weight::from_parts(1_576_541_397, 0) - .saturating_add(Weight::from_parts(0, 7604)) - // Standard Error: 296_982 - .saturating_add(Weight::from_parts(3_076_310, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(4)) - .saturating_add(Weight::from_parts(0, 108).saturating_mul(v.into())) - } - /// Storage: `ElectionVerifierPallet::VerificationStatus` (r:1 w:1) - /// Proof: `ElectionVerifierPallet::VerificationStatus` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SortedScores` (r:1 w:0) - /// Proof: `ElectionSignedPallet::SortedScores` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionSignedPallet::SubmissionStorage` (r:1 w:0) - /// Proof: `ElectionSignedPallet::SubmissionStorage` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:1) - /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:3 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn on_initialize_ongoing_finalize(v: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0 + t * (41 ±0) + v * (125 ±0)` - // Estimated: `79043 + t * (10 ±8) + v * (85 ±17)` - // Minimum execution time: 1_724_000_000 picoseconds. - Weight::from_parts(1_466_010_752, 0) - .saturating_add(Weight::from_parts(0, 79043)) - // Standard Error: 199_409 - .saturating_add(Weight::from_parts(3_322_580, 0).saturating_mul(v.into())) - // Standard Error: 128_785 - .saturating_add(Weight::from_parts(128_906, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(6)) - .saturating_add(Weight::from_parts(0, 10).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 85).saturating_mul(v.into())) - } - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn on_initialize_ongoing_finalize_failed(_v: u32, _t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_659_677, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn finalize_async_verification(v: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_354_301, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_197 - .saturating_add(Weight::from_parts(907, 0).saturating_mul(v.into())) - // Standard Error: 1_419 - .saturating_add(Weight::from_parts(65, 0).saturating_mul(t.into())) - } - /// Storage: `ElectionVerifierPallet::QueuedSolutionScore` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedSolutionScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::MinimumScore` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::MinimumScore` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ValidatorCount` (r:1 w:0) - /// Proof: `Staking::ValidatorCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `ElectionVerifierPallet::QueuedValidVariant` (r:1 w:0) - /// Proof: `ElectionVerifierPallet::QueuedValidVariant` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionY` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionY` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::LastStoredPage` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::LastStoredPage` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionVerifierPallet::QueuedSolutionBackings` (r:0 w:1) - /// Proof: `ElectionVerifierPallet::QueuedSolutionBackings` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - /// The range of component `t` is `[512, 2048]`. - fn verify_sync_paged(v: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `15968 + t * (24 ±0) + v * (73 ±0)` - // Estimated: `18127 + t * (25 ±2) + v * (72 ±3)` - // Minimum execution time: 1_403_000_000 picoseconds. - Weight::from_parts(1_403_000_000, 0) - .saturating_add(Weight::from_parts(0, 18127)) - // Standard Error: 3_979_877 - .saturating_add(Weight::from_parts(24_084_766, 0).saturating_mul(v.into())) - // Standard Error: 1_947_873 - .saturating_add(Weight::from_parts(1_727_080, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 25).saturating_mul(t.into())) - .saturating_add(Weight::from_parts(0, 72).saturating_mul(v.into())) - } -} - -impl WeightInfo for () { - fn on_initialize_ongoing(_v: u32, _t: u32) -> Weight { - Default::default() - } - - fn on_initialize_ongoing_failed(_v: u32, _t: u32) -> Weight { - Default::default() - } - - fn on_initialize_ongoing_finalize(_v: u32, _t: u32) -> Weight { - Default::default() - } - - fn on_initialize_ongoing_finalize_failed(_v: u32, _t: u32) -> Weight { - Default::default() - } - - fn finalize_async_verification(_v: u32, _t: u32, ) -> Weight { - Default::default() - } - - fn verify_sync_paged(_v: u32, _t: u32, ) -> Weight { - Default::default() - } -} - diff --git a/substrate/frame/election-provider-multi-block/src/weights.rs b/substrate/frame/election-provider-multi-block/src/weights.rs deleted file mode 100644 index f11e82e578b3f..0000000000000 --- a/substrate/frame/election-provider-multi-block/src/weights.rs +++ /dev/null @@ -1,179 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::Weight}; -use core::marker::PhantomData; - -pub trait WeightInfo { - fn create_voters_snapshot_paged(t: u32) -> Weight; - fn create_targets_snapshot_paged(v: u32) -> Weight; - fn on_initialize_start_signed() -> Weight; - fn on_initialize_do_nothing() -> Weight; - fn on_phase_transition() -> Weight; - fn on_initialize_start_export() -> Weight; -} - -/// Weight functions for `pallet_epm_core`. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `Staking::CounterForValidators` (r:1 w:0) - /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::TargetSnapshotStatus` (r:1 w:1) - /// Proof: `Staking::TargetSnapshotStatus` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:2049 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiBlock::PagedTargetSnapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiBlock::PagedTargetSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `t` is `[512, 2048]`. - fn create_targets_snapshot_paged(t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1041 + t * (46 ±0)` - // Estimated: `3510 + t * (2520 ±0)` - // Minimum execution time: 47_198_000_000 picoseconds. - Weight::from_parts(3_209_333_333, 0) - .saturating_add(Weight::from_parts(0, 3510)) - // Standard Error: 1_207_323 - .saturating_add(Weight::from_parts(86_960_937, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(2)) - .saturating_add(Weight::from_parts(0, 2520).saturating_mul(t.into())) - } - /// Storage: `VoterList::CounterForListNodes` (r:1 w:0) - /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::VoterSnapshotStatus` (r:1 w:1) - /// Proof: `Staking::VoterSnapshotStatus` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListBags` (r:200 w:0) - /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) - /// Storage: `VoterList::ListNodes` (r:1025 w:0) - /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) - /// Storage: `Staking::Bonded` (r:1024 w:0) - /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) - /// Storage: `Staking::Ledger` (r:1024 w:0) - /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) - /// Storage: `Staking::Nominators` (r:1024 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) - /// Storage: `Staking::Validators` (r:1000 w:0) - /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) - /// Storage: `Staking::MinimumActiveStake` (r:0 w:1) - /// Proof: `Staking::MinimumActiveStake` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiBlock::PagedVoterSnapshot` (r:0 w:1) - /// Proof: `ElectionProviderMultiBlock::PagedVoterSnapshot` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[32, 1024]`. - fn create_voters_snapshot_paged(v: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `73175 + v * (946 ±0)` - // Estimated: `512390 + v * (3566 ±0)` - // Minimum execution time: 13_398_000_000 picoseconds. - Weight::from_parts(4_906_354_838, 0) - .saturating_add(Weight::from_parts(0, 512390)) - // Standard Error: 534_281 - .saturating_add(Weight::from_parts(260_582_661, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(208)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(v.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(Weight::from_parts(0, 3566).saturating_mul(v.into())) - } - /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ElectionDataLock` (r:0 w:1) - /// Proof: `Staking::ElectionDataLock` (`max_values`: Some(1), `max_size`: Some(0), added: 495, mode: `MaxEncodedLen`) - fn on_initialize_start_signed() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 66_000_000 picoseconds. - Weight::from_parts(66_000_000, 0) - .saturating_add(Weight::from_parts(0, 1561)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:1) - /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ElectionProviderMultiBlock::Round` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::Round` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn on_phase_transition() -> Weight { - // Proof Size summary in bytes: - // Measured: `76` - // Estimated: `1561` - // Minimum execution time: 62_000_000 picoseconds. - Weight::from_parts(62_000_000, 0) - .saturating_add(Weight::from_parts(0, 1561)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - fn on_initialize_start_export() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(3_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - } - /// Storage: `Staking::CurrentEra` (r:1 w:0) - /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::CurrentPlannedSession` (r:1 w:0) - /// Proof: `Staking::CurrentPlannedSession` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasStartSessionIndex` (r:1 w:0) - /// Proof: `Staking::ErasStartSessionIndex` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) - /// Storage: `Staking::ForceEra` (r:1 w:0) - /// Proof: `Staking::ForceEra` (`max_values`: Some(1), `max_size`: Some(1), added: 496, mode: `MaxEncodedLen`) - /// Storage: `ElectionProviderMultiBlock::CurrentPhase` (r:1 w:0) - /// Proof: `ElectionProviderMultiBlock::CurrentPhase` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn on_initialize_do_nothing() -> Weight { - // Proof Size summary in bytes: - // Measured: `502` - // Estimated: `3481` - // Minimum execution time: 111_000_000 picoseconds. - Weight::from_parts(111_000_000, 0) - .saturating_add(Weight::from_parts(0, 3481)) - .saturating_add(T::DbWeight::get().reads(5)) - } -} - -impl WeightInfo for () { - fn create_voters_snapshot_paged(_v: u32) -> Weight { - Default::default() - } - - fn create_targets_snapshot_paged(_t: u32) -> Weight { - Default::default() - } - - fn on_initialize_start_signed() -> Weight { - Default::default() - } - - fn on_initialize_do_nothing() -> Weight { - Default::default() - } - - fn on_phase_transition() -> Weight { - Default::default() - } - - fn on_initialize_start_export() -> Weight { - Default::default() - } -} From 103465354869dbb626b77da376c85b5947ef7eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 24 Oct 2024 11:39:30 +0200 Subject: [PATCH 21/95] nit fix in bags list remote tests --- prdoc/pr_6034.prdoc | 2 ++ substrate/frame/bags-list/remote-tests/src/snapshot.rs | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index ba3d14326509f..e440c79bd3258 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -21,3 +21,5 @@ crates: bump: major - name: sp-staking bump: major +- name: pallet-bags-list-remote-tests + bump: patch diff --git a/substrate/frame/bags-list/remote-tests/src/snapshot.rs b/substrate/frame/bags-list/remote-tests/src/snapshot.rs index cb23fc6f5817d..0d9740addb54a 100644 --- a/substrate/frame/bags-list/remote-tests/src/snapshot.rs +++ b/substrate/frame/bags-list/remote-tests/src/snapshot.rs @@ -22,7 +22,10 @@ use frame_election_provider_support::{ }; use frame_support::traits::PalletInfoAccess; use remote_externalities::{Builder, Mode, OnlineConfig}; -use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; +use sp_runtime::{ + traits::{Block as BlockT, Zero}, + DeserializeOwned, +}; /// Execute create a snapshot from pallet-staking. pub async fn execute(voter_limit: Option, currency_unit: u64, ws_url: String) @@ -70,8 +73,9 @@ where Some(v) => DataProviderBounds { count: Some(CountBound(v as u32)), size: None }, }; + // single page voter snapshot, thus page index == 0. let voters = - as ElectionDataProvider>::electing_voters(bounds) + as ElectionDataProvider>::electing_voters(bounds, Zero::zero()) .unwrap(); let mut voters_nominator_only = voters From 724896096a42eabf165e84ad5496e42046da8b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 24 Oct 2024 11:43:47 +0200 Subject: [PATCH 22/95] nit fix prdoc --- prdoc/pr_6034.prdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index e440c79bd3258..420fd5ca36742 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -21,5 +21,5 @@ crates: bump: major - name: sp-staking bump: major -- name: pallet-bags-list-remote-tests - bump: patch + - name: pallet-bags-list-remote-tests + bump: minor From a92d44a9fd112ca5611df2b2eab0c0c193a4e36b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 25 Oct 2024 15:33:46 +0200 Subject: [PATCH 23/95] Addresses PR reviews (removes all paged types/configs from epm and nits) --- substrate/frame/delegated-staking/src/mock.rs | 1 - .../election-provider-multi-phase/src/lib.rs | 70 +++++++++---------- .../election-provider-multi-phase/src/mock.rs | 13 ++-- .../src/signed.rs | 4 +- .../src/unsigned.rs | 15 ++-- .../election-provider-support/src/lib.rs | 6 +- substrate/frame/fast-unstake/src/mock.rs | 1 - substrate/frame/staking/src/pallet/mod.rs | 2 +- 8 files changed, 49 insertions(+), 63 deletions(-) diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index 396c8bf053dbb..a7363698e0747 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -111,7 +111,6 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; - type MaxValidatorSet = ConstU32<100>; type EventListeners = (Pools, DelegatedStaking); } diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 0c1c7f048474f..049bcbabce6a7 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -191,10 +191,15 @@ //! //! ## Multi-page election support //! -//! Even though the [`frame_election_provider_support::ElectionDataProvider`] and -//! [`frame_election_provider_support::ElectionProvider`] traits support multi-paged election, this -//! pallet only supports a single page election flow. Thus, [`Config::Pages`] must be always set to -//! one, which is asserted by the [`frame_support::traits::Hooks::integrity_test`]. +//! The [`frame_election_provider_support::ElectionDataProvider`] and +//! [`frame_election_provider_support::ElectionProvider`] traits used by this pallet support a +//! multi page election. +//! +//! However, this pallet is meant to be used only in the context of a single-page election and data +//! provider and all the relevant trait implementation ad configurations reflect that assumption. +//! +//! If external callers request the election of a page index higher than 0, the election will fail +//! with [`ElectionError::MultiPageNotSupported`]. //! //! ## Future Plans //! @@ -246,7 +251,6 @@ use frame_election_provider_support::{ InstantElectionProvider, NposSolution, PageIndex, TryIntoBoundedSupports, }; use frame_support::{ - defensive_assert, dispatch::DispatchClass, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, @@ -442,18 +446,18 @@ impl Default for RawSolution { DefaultNoBound, scale_info::TypeInfo, )] -#[scale_info(skip_type_params(AccountId, MaxWinnersPerPage, MaxBackersPerWinner))] -pub struct ReadySolution +#[scale_info(skip_type_params(AccountId, MaxWinners, MaxBackersPerWinner))] +pub struct ReadySolution where AccountId: IdentifierT, - MaxWinnersPerPage: Get, + MaxWinners: Get, MaxBackersPerWinner: Get, { /// The final supports of the solution. /// /// This is target-major vector, storing each winners, total backing, and each individual /// backer. - pub supports: BoundedSupports, + pub supports: BoundedSupports, /// The score of the solution. /// /// This is needed to potentially challenge the solution. @@ -504,6 +508,9 @@ pub enum ElectionError { DataProvider(&'static str), /// An error nested in the fallback. Fallback(FallbackErrorOf), + /// An error occurred when requesting an election result. The caller expects a mulit-paged + /// election, which this pallet does not support. + MultiPageNotSupported, /// No solution has been queued. NothingQueued, } @@ -624,7 +631,7 @@ pub mod pallet { type MinerConfig: crate::unsigned::MinerConfig< AccountId = Self::AccountId, MaxVotesPerVoter = ::MaxVotesPerVoter, - MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxWinners = Self::MaxWinners, MaxBackersPerWinner = Self::MaxBackersPerWinner, >; @@ -662,28 +669,22 @@ pub mod pallet { #[pallet::constant] type SignedDepositWeight: Get>; - /// Maximum number of winners that a page supports. + /// Maximum number of winners that an electio supports. /// /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. - type MaxWinnersPerPage: Get; + type MaxWinners: Get; - /// Maximum number of voters that can support a single target, across ALL the solution - /// pages. Thus, this can only be verified when processing the last solution page. + /// Maximum number of voters that can support a winner target in an election solution. /// /// This limit must be set so that the memory limits of the rest of the system are /// respected. type MaxBackersPerWinner: Get; - /// Number of pages. - type Pages: Get; - /// Something that calculates the signed deposit base based on the signed submissions queue /// size. type SignedDepositBase: Convert>; /// The maximum number of electing voters and electable targets to put in the snapshot. - /// At the moment, snapshots are only over a single block, but once multi-block elections - /// are introduced they will take place over multiple blocks. type ElectionBounds: Get; /// Handler for the slashed deposits. @@ -704,7 +705,7 @@ pub mod pallet { BlockNumber = BlockNumberFor, DataProvider = Self::DataProvider, MaxBackersPerWinner = Self::MaxBackersPerWinner, - MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxWinnersPerPage = Self::MaxWinners, >; /// Configuration of the governance-only fallback. @@ -715,7 +716,7 @@ pub mod pallet { AccountId = Self::AccountId, BlockNumber = BlockNumberFor, DataProvider = Self::DataProvider, - MaxWinnersPerPage = Self::MaxWinnersPerPage, + MaxWinnersPerPage = Self::MaxWinners, MaxBackersPerWinner = Self::MaxBackersPerWinner, >; @@ -753,7 +754,7 @@ pub mod pallet { #[pallet::constant_name(MinerMaxWinners)] fn max_winners() -> u32 { - ::MaxWinnersPerPage::get() + ::MaxWinners::get() } } @@ -895,9 +896,6 @@ pub mod pallet { // `SignedMaxSubmissions` is a red flag that the developer does not understand how to // configure this pallet. assert!(T::SignedMaxSubmissions::get() >= T::SignedMaxRefunds::get()); - - // This pallet only supports single-page elections. - assert!(T::Pages::get() == 1u32); } #[cfg(feature = "try-runtime")] @@ -1001,7 +999,7 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; ensure!(CurrentPhase::::get().is_emergency(), Error::::CallNotAllowed); - // bound supports with T::MaxWinnersPerPage. + // bound supports with T::MaxWinners. let supports: BoundedSupports<_, _, _> = supports.try_into_bounded_supports().map_err(|_| Error::::TooManyWinners)?; @@ -1283,7 +1281,7 @@ pub mod pallet { /// Always sorted by score. #[pallet::storage] pub type QueuedSolution = - StorageValue<_, ReadySolution>; + StorageValue<_, ReadySolution>; /// Snapshot data of the round. /// @@ -1416,7 +1414,7 @@ impl Pallet { /// /// Always sorted by score. pub fn queued_solution( - ) -> Option> { + ) -> Option> { QueuedSolution::::get() } @@ -1602,10 +1600,8 @@ impl Pallet { pub fn feasibility_check( raw_solution: RawSolution>, compute: ElectionCompute, - ) -> Result< - ReadySolution, - FeasibilityError, - > { + ) -> Result, FeasibilityError> + { let desired_targets = DesiredTargets::::get().ok_or(FeasibilityError::SnapshotUnavailable)?; @@ -1686,7 +1682,7 @@ impl Pallet { /// record the weight of the given `supports`. fn weigh_supports( - supports: &BoundedSupports, + supports: &BoundedSupports, ) { let active_voters = supports .iter() @@ -1783,14 +1779,14 @@ impl ElectionProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; type Error = ElectionError; - type MaxWinnersPerPage = T::MaxWinnersPerPage; + type MaxWinnersPerPage = T::MaxWinners; type MaxBackersPerWinner = T::MaxBackersPerWinner; - type Pages = T::Pages; + type Pages = sp_core::ConstU32<1>; type DataProvider = T::DataProvider; fn elect(page: PageIndex) -> Result, Self::Error> { - // this pallet **MUST** only by used in the single-block mode. - defensive_assert!(page.is_zero()); + // Note: this pallet **MUST** only by used in the single-block mode. + ensure!(page.is_zero(), ElectionError::::WrongPageIndex); match Self::do_elect() { Ok(bounded_supports) => { diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 948f19b418528..4f2c38681d421 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -295,7 +295,7 @@ parameter_types! { pub static MaxElectableTargets: TargetIndex = TargetIndex::max_value(); #[derive(Debug)] - pub static MaxWinnersPerPage: u32 = 200; + pub static MaxWinners: u32 = 200; #[derive(Debug)] pub static MaxBackersPerWinner: u32 = 200; pub static Pages: u32 = 1; @@ -312,7 +312,7 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; type WeightInfo = (); - type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxWinnersPerPage = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; type Bounds = OnChainElectionsBounds; } @@ -322,9 +322,9 @@ impl ElectionProvider for MockFallback { type AccountId = AccountId; type BlockNumber = BlockNumber; type Error = &'static str; - type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxWinnersPerPage = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; - type Pages = Pages; + type Pages = ConstU32<1>; type DataProvider = StakingMock; fn elect(_remaining: PageIndex) -> Result, Self::Error> { @@ -375,7 +375,7 @@ impl MinerConfig for Runtime { type MaxLength = MinerMaxLength; type MaxWeight = MinerMaxWeight; type MaxVotesPerVoter = ::MaxVotesPerVoter; - type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxWinners = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; type Solution = TestNposSolution; @@ -418,8 +418,7 @@ impl crate::Config for Runtime { type GovernanceFallback = frame_election_provider_support::onchain::OnChainExecution; type ForceOrigin = frame_system::EnsureRoot; - type Pages = Pages; - type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxWinners = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; type MinerConfig = Self; type Solver = SequentialPhragmen, Balancing>; diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index ef1538b1e4d39..7fe8f5920b14e 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -490,7 +490,7 @@ impl Pallet { /// /// Infallible pub fn finalize_signed_phase_accept_solution( - ready_solution: ReadySolution, + ready_solution: ReadySolution, who: &T::AccountId, deposit: BalanceOf, call_fee: BalanceOf, @@ -665,7 +665,7 @@ mod tests { ExtBuilder::default().build_and_execute(|| { // given desired_targets bigger than MaxWinners DesiredTargets::set(4); - MaxWinnersPerPage::set(3); + MaxWinners::set(3); // snapshot not created because data provider returned an unexpected number of // desired_targets diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 1389a5babd9d1..1113c0bc8a96b 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -430,7 +430,7 @@ pub trait MinerConfig { /// The weight is computed using `solution_weight`. type MaxWeight: Get; /// The maximum number of winners that can be elected per page (and overall). - type MaxWinnersPerPage: Get; + type MaxWinners: Get; /// The maximum number of backers (edges) per winner in the last solution. type MaxBackersPerWinner: Get; /// Something that can compute the weight of a solution. @@ -751,10 +751,8 @@ impl Miner { snapshot: RoundSnapshot>, current_round: u32, minimum_untrusted_score: Option, - ) -> Result< - ReadySolution, - FeasibilityError, - > { + ) -> Result, FeasibilityError> + { let RawSolution { solution, score, round } = raw_solution; let RoundSnapshot { voters: snapshot_voters, targets: snapshot_targets } = snapshot; @@ -766,10 +764,7 @@ impl Miner { ensure!(winners.len() as u32 == desired_targets, FeasibilityError::WrongWinnerCount); // Fail early if targets requested by data provider exceed maximum winners supported. - ensure!( - desired_targets <= T::MaxWinnersPerPage::get(), - FeasibilityError::TooManyDesiredTargets - ); + ensure!(desired_targets <= T::MaxWinners::get(), FeasibilityError::TooManyDesiredTargets); // Ensure that the solution's score can pass absolute min-score. let submitted_score = raw_solution.score; @@ -826,7 +821,7 @@ impl Miner { let known_score = supports.evaluate(); ensure!(known_score == score, FeasibilityError::InvalidScore); - // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinnersPerPage`. + // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. let supports = supports .try_into_bounded_supports() .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 56217c3d3052c..1358cbf1a166e 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -58,14 +58,13 @@ //! does not receive election data as an input. All value and type parameter must be provided by the //! [`ElectionDataProvider`] trait, even if the election happens immediately. //! -//! ## Multi-page election +//! ## Multi-page election support //! //! Both [`ElectionDataProvider`] and [`ElectionProvider`] traits are parameterized by page, //! supporting an election to be performed over multiple pages. This enables the //! [`ElectionDataProvider`] implementor to provide all the election data over multiple pages. //! Similarly [`ElectionProvider::elect`] is parameterized by page index. -//! -//! ## [`LockableElectionDataProvider`] for multi-page election +////! ## [`LockableElectionDataProvider`] for multi-page election //! //! The [`LockableElectionDataProvider`] trait exposes a way for election data providers to lock //! and unlock election data mutations. This is an useful trait to ensure that the results of @@ -330,7 +329,6 @@ pub trait ElectionDataProvider { /// Returns the possible targets for the election associated with page `page`, i.e. the targets /// that could become elected, thus "electable". /// - /// TODO(gpestana): remove self-weighing and return the weight. /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. fn electable_targets( diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index c0c23af51fb53..33f1369cb8fe2 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -118,7 +118,6 @@ impl pallet_staking::Config for Runtime { type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; type TargetList = pallet_staking::UseValidatorsMap; - type MaxValidatorSet = ConstU32<100>; } parameter_types! { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index f03b110c64db2..73f442723d585 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -234,7 +234,6 @@ pub mod pallet { /// The absolute maximum of next winner validators this pallet should return. #[pallet::constant] - #[pallet::no_default] type MaxValidatorSet: Get; /// Something that provides a best-effort sorted list of voters aka electing nominators, @@ -345,6 +344,7 @@ pub mod pallet { type NextNewSession = (); type MaxExposurePageSize = ConstU32<64>; type MaxUnlockingChunks = ConstU32<32>; + type MaxValidatorSet = ConstU32<100>; type MaxControllersInDeprecationBatch = ConstU32<100>; type EventListeners = (); type DisablingStrategy = crate::UpToLimitDisablingStrategy; From 3d1a3301fb2f5a11daac9a0c279f3f39fd518fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 25 Oct 2024 17:16:31 +0200 Subject: [PATCH 24/95] improve memory efficiency of try into bounded supports; tests --- .../election-provider-multi-phase/src/lib.rs | 25 ++++++++++++++++++- .../election-provider-support/src/lib.rs | 24 ++++++++++++------ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 049bcbabce6a7..40fa163a0aa63 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1786,7 +1786,7 @@ impl ElectionProvider for Pallet { fn elect(page: PageIndex) -> Result, Self::Error> { // Note: this pallet **MUST** only by used in the single-block mode. - ensure!(page.is_zero(), ElectionError::::WrongPageIndex); + ensure!(page.is_zero(), ElectionError::::MultiPageNotSupported); match Self::do_elect() { Ok(bounded_supports) => { @@ -2490,6 +2490,29 @@ mod tests { }) } + #[test] + fn try_elect_multi_page_fails() { + ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + roll_to_signed(); + assert!(Snapshot::::get().is_some()); + + // submit solution and assert it is queued and ready for elect to be called. + let (solution, _, _) = MultiPhase::mine_solution().unwrap(); + assert_ok!(MultiPhase::submit( + crate::mock::RuntimeOrigin::signed(99), + Box::new(solution), + )); + roll_to(30); + assert!(QueuedSolution::::get().is_some()); + + // single page elect call works as expected. + assert_ok!(MultiPhase::elect(SINGLE_PAGE)); + + // however, multi page calls will fail. + assert!(MultiPhase::elect(10).is_err()); + }) + } + #[test] fn fallback_strategy_works() { ExtBuilder::default().onchain_fallback(true).build_and_execute(|| { diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 1358cbf1a166e..bfd29225fc6d6 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -871,13 +871,23 @@ impl, BInner: Get> TryIntoBoundedSupports for sp_npos_elections::Supports { fn try_into_bounded_supports(self) -> Result, ()> { - let inner_bounded_supports = self - .into_iter() - .map(|(a, s)| s.try_into().map(|s| (a, s))) - .collect::, _>>() - .map_err(|_| ())?; - let outer_bounded_supports: BoundedVec<_, BOuter> = - inner_bounded_supports.try_into().map_err(|_| ())?; + // optimization note: pre-allocate outer bounded vec. + let mut outer_bounded_supports = BoundedVec::< + (AccountId, BoundedSupport), + BOuter, + >::with_bounded_capacity( + self.len().min(BOuter::get() as usize) + ); + + // optimization note: avoid intermediate allocations. + self.into_iter() + .map(|(account, support)| (account, support.try_into().map_err(|_| ()))) + .try_for_each(|(account, maybe_bounded_supports)| { + outer_bounded_supports + .try_push((account, maybe_bounded_supports?)) + .map_err(|_| ()) + })?; + Ok(outer_bounded_supports.into()) } } From 1757c91631f31291f962b279366208dd312c043e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 28 Oct 2024 14:57:43 +0100 Subject: [PATCH 25/95] a few nits in the staking pallet; handles exposures better (do not leave exposure gaps in pages) --- substrate/frame/staking/src/lib.rs | 117 ++++++++---- substrate/frame/staking/src/mock.rs | 3 +- substrate/frame/staking/src/pallet/impls.rs | 197 +++++++------------- substrate/frame/staking/src/pallet/mod.rs | 88 ++++----- substrate/frame/staking/src/tests.rs | 114 +++++++---- substrate/primitives/staking/src/lib.rs | 52 +++++- 6 files changed, 319 insertions(+), 252 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index bf8417d1ac74d..890007ec92ba8 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -352,10 +352,12 @@ macro_rules! log { /// config. pub type MaxWinnersOf = ::MaxValidatorSet; -/// Maximum number of exposures (validators) that each page of [`Config::ElectionProvider`] might -/// might return. -pub type MaxExposuresPerPageOf = - <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage; +/// Maximum number of exposures that can fit into an exposure page, as defined by this pallet's +/// config. +/// TODO: needed? maybe use the type directly. +pub type MaxExposuresPerPageOf = ::MaxExposurePageSize; + +pub type MaxWinnersPerPageOf

=

::MaxWinnersPerPage; /// Maximum number of nominations per nominator. pub type MaxNominationsOf = @@ -787,6 +789,8 @@ impl EraInfo { } /// Store exposure for elected validators at start of an era. - pub fn set_exposure( + /// + /// If the exposure does not exist yet for the tuple (era, validator), it sets it. Otherwise, + /// it updates the existing record by ensuring *intermediate* exposure pages are filled up with + /// `T::MaxExposurePageSize` number of backiers per page. + pub fn upsert_exposure( era: EraIndex, validator: &T::AccountId, - exposure: Exposure>, + mut exposure: Exposure>, ) { let page_size = T::MaxExposurePageSize::get().defensive_max(1); - let nominator_count = exposure.others.len(); - // expected page count is the number of nominators divided by the page size, rounded up. - let expected_page_count = nominator_count - .defensive_saturating_add((page_size as usize).defensive_saturating_sub(1)) - .saturating_div(page_size as usize); - - let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); - defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); - - // insert or update validator's overview. - let append_from = ErasStakersOverview::::mutate(era, &validator, |stored| { - if let Some(stored_overview) = stored { - let append_from = stored_overview.page_count; - *stored = Some(stored_overview.merge(exposure_metadata)); - append_from - } else { - *stored = Some(exposure_metadata); - Zero::zero() - } - }); - - exposure_pages.iter().enumerate().for_each(|(idx, paged_exposure)| { - let append_at = (append_from + idx as u32) as Page; - >::insert((era, &validator, append_at), &paged_exposure); - }); - } + if let Some(stored_overview) = ErasStakersOverview::::get(era, &validator) { + let exposures_append = exposure.split_others(stored_overview.last_page_empty_slots); + let last_page_idx = stored_overview.page_count.saturating_sub(1); + + let last_page_idx = ErasStakersOverview::::mutate(era, &validator, |stored| { + // new metadata is updated based on 3 different set of exposures: the + // current one, the exposure split to be "fitted" into the current last page and + // the exposure set that will be appended from the new page onwards. + let new_metadata = + stored.defensive_unwrap_or_default().update_with::( + [&exposures_append, &exposure] + .iter() + .fold(Default::default(), |total, expo| { + total.saturating_add(expo.total.saturating_sub(expo.own)) + }), + [&exposures_append, &exposure] + .iter() + .fold(Default::default(), |count, expo| { + count.saturating_add(expo.others.len() as u32) + }), + ); + *stored = new_metadata.into(); + + last_page_idx + }); - /// Store total exposure for all the elected validators in the era. - pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf) { - >::insert(era, total_stake); + // fill up last page with exposures. + let mut last_page = + ErasStakersPaged::::get((era, validator, last_page_idx)).unwrap_or_default(); + + last_page.page_total = last_page + .page_total + .saturating_add(exposures_append.total) + .saturating_sub(exposures_append.own); + last_page.others.extend(exposures_append.others); + ErasStakersPaged::::insert((era, &validator, last_page_idx), last_page); + + // now handle the remainig exposures and append the exposure pages. The metadata update + // has been already handled above. + let (_, exposure_pages) = exposure.into_pages(page_size); + + exposure_pages.iter().enumerate().for_each(|(idx, paged_exposure)| { + let append_at = + (last_page_idx.saturating_add(1).saturating_add(idx as u32)) as Page; + >::insert((era, &validator, append_at), &paged_exposure); + }); + } else { + // expected page count is the number of nominators divided by the page size, rounded up. + let expected_page_count = exposure + .others + .len() + .defensive_saturating_add((page_size as usize).defensive_saturating_sub(1)) + .saturating_div(page_size as usize); + + // no exposures yet for this (era, validator) tuple, calculate paged exposure pages and + // metadata from a blank slate. + let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size); + defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count"); + + // insert metadata. + ErasStakersOverview::::insert(era, &validator, exposure_metadata); + + // insert or update validator's overview. + exposure_pages.iter().enumerate().for_each(|(idx, paged_exposure)| { + let append_at = idx as Page; + >::insert((era, &validator, append_at), &paged_exposure); + }); + }; } + /// Update the total exposure for all the elected validators in the era. pub(crate) fn add_total_stake(era: EraIndex, stake: BalanceOf) { >::mutate(era, |total_stake| { *total_stake += stake; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index e9a761a59a81b..1734395fb6e86 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -20,7 +20,8 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, - onchain, BoundedSupports, SequentialPhragmen, Support, TryIntoBoundedSupports, VoteWeight, + onchain, BoundedSupports, ElectionProvider, SequentialPhragmen, Support, + TryIntoBoundedSupports, VoteWeight, }; use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index ea6fd4915d00a..a566d7fd90acc 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -17,9 +17,6 @@ //! Implementations for the Staking FRAME Pallet. -// TODO: remove -#![allow(dead_code)] - use frame_election_provider_support::{ bounds::{CountBound, SizeBound}, data_provider, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, @@ -56,7 +53,7 @@ use sp_staking::{ use crate::{ asset, election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, - LedgerIntegrityState, MaxExposuresPerPageOf, MaxNominationsOf, MaxWinnersOf, Nominations, + LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, MaxWinnersPerPageOf, Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, SnapshotStatus, StakingLedger, ValidatorPrefs, }; @@ -485,10 +482,6 @@ impl Pallet { Self::set_force_era(Forcing::NotForcing); } - //TODO: we may want to keep track of the past 1/N era's stashes - // reset electable stashes. - ElectableStashes::::kill(); - maybe_new_era_validators } else { // Set initial era. @@ -618,33 +611,12 @@ impl Pallet { /// * Bump the current era storage (which holds the latest planned era). /// * Store start session index for the new planned era. /// * Clean old era information. - /// * Store staking information for the new planned era /// - /// Returns the new validator set. - pub fn trigger_new_era( - start_session_index: SessionIndex, - exposures: BoundedVec< - (T::AccountId, Exposure>), - MaxExposuresPerPageOf, - >, - ) -> BoundedVec> { - // Increment or set current era. - let new_planned_era = CurrentEra::::mutate(|s| { - *s = Some(s.map(|s| s + 1).unwrap_or(0)); - s.unwrap() - }); - ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); - - // Clean old era information. - if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { - Self::clear_era_information(old_era); - } - - // Set staking information for the new era. - Self::store_stakers_info(exposures, new_planned_era) - } - - pub fn trigger_new_era_paged(start_session_index: SessionIndex) { + /// Note: staking information for the new planned era has been processed and stored during the + /// `elect_paged(page_index)` calls. + /// + /// The new validator set for this era is stored under [`ElectableStashes`]. + pub fn trigger_new_era(start_session_index: SessionIndex) { // Increment or set current era. let new_planned_era = CurrentEra::::mutate(|s| { *s = Some(s.map(|s| s + 1).unwrap_or(0)); @@ -660,7 +632,9 @@ impl Pallet { /// Potentially plan a new era. /// - /// Get election result from `T::ElectionProvider`. + /// The election results are either fetched directly from an election provider if it is the + /// "genesis" election or from a cached set of winners. + /// /// In case election result has more than [`MinimumValidatorCount`] validator trigger a new era. /// /// In case a new era is planned, the new validator set is returned. @@ -669,23 +643,29 @@ impl Pallet { is_genesis: bool, ) -> Option>> { let validators: BoundedVec> = if is_genesis { - // genesis election only use the lsp of the election result. + // genesis election only uses one election result page. let result = ::elect(Zero::zero()).map_err(|e| { log!(warn, "genesis election provider failed due to {:?}", e); Self::deposit_event(Event::StakingElectionFailed); }); - let (_, planned_era) = ElectingStartedAt::::get().unwrap_or_default(); let exposures = Self::collect_exposures(result.ok().unwrap_or_default()); - Self::store_stakers_info_paged(exposures.clone(), planned_era); - exposures - .into_iter() + let validators = exposures + .iter() .map(|(validator, _)| validator) + .cloned() .try_collect() - .unwrap_or_default() + .unwrap_or_default(); + + // set stakers info for genesis era (0). + Self::store_stakers_info(exposures.into_inner(), Zero::zero()); + + validators } else { - ElectableStashes::::get() + // note: exposures have already been processed and stored for each of the election + // solution page at the time of `elect_paged(page_index)`. + ElectableStashes::::take() }; log!(info, "electable validators for session {:?}: {:?}", start_session_index, validators); @@ -717,114 +697,72 @@ impl Pallet { } Self::deposit_event(Event::StakersElected); - Self::trigger_new_era_paged(start_session_index); + Self::trigger_new_era(start_session_index); + Some(validators) } /// Paginated elect. /// - /// TODO: rust-docs + /// Fetches the election page with index `page` from the election provider. + /// + /// The results from the elect call shold be stored in the `ElectableStashes` storage. In + /// addition, it stores stakers' information for next planned era based on the paged solution + /// data returned. pub(crate) fn do_elect_paged(page: PageIndex) { let paged_result = match ::elect(page) { Ok(result) => result, Err(e) => { - log!(warn, "electiong provider page failed due to {:?} (page: {})", e, page); - // TODO: be resilient here, not all pages need to be submitted successfuly for an - // election to be OK, provided that the election score is good enough. + log!(warn, "election provider page failed due to {:?} (page: {})", e, page); Self::deposit_event(Event::StakingElectionFailed); return }, }; - let new_planned_era = CurrentEra::::get().unwrap_or_default().saturating_add(1); - let stashes = - Self::store_stakers_info_paged(Self::collect_exposures(paged_result), new_planned_era); + // preparing the next era. Note: we expect elect paged to be called *only* during a + // non-genesis era, thus current era should be set by now. + let planning_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); + + let stashes = Self::store_stakers_info( + Self::collect_exposures(paged_result).into_inner(), + planning_era, + ); ElectableStashes::::mutate(|v| { - // TODO: be even more defensive and handle potential error? (should not happen if page - // bounds and T::MaxValidatorSet configs are in sync). + // TODO: dedup duplicate validator IDs, isntead of try_extend. let _ = (*v).try_extend(stashes.into_iter()).defensive(); }); } /// Process the output of a paged election. /// - /// Store staking information for the new planned era - pub fn store_stakers_info_paged( - exposures: BoundedVec< - (T::AccountId, Exposure>), - MaxExposuresPerPageOf, - >, - new_planned_era: EraIndex, - ) -> BoundedVec> { - // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. - let mut total_stake: BalanceOf = Zero::zero(); - let mut elected_stashes = Vec::with_capacity(exposures.len()); - - exposures.into_iter().for_each(|(stash, exposure)| { - // build elected stash - elected_stashes.push(stash.clone()); - // accumulate total stake - total_stake = total_stake.saturating_add(exposure.total); - // store staker exposure for this era - EraInfo::::set_exposure(new_planned_era, &stash, exposure); - }); - - // TODO: correct?? - let elected_stashes: BoundedVec<_, MaxExposuresPerPageOf> = elected_stashes - .try_into() - .expect("elected_stashes.len() always equal to exposures.len(); qed"); - - EraInfo::::add_total_stake(new_planned_era, total_stake); - - // Collect the pref of all winners. - for stash in &elected_stashes { - let pref = Self::validators(stash); - >::insert(&new_planned_era, stash, pref); - } - - if new_planned_era > 0 { - log!( - info, - "updated validator set (current size {:?}) for era {:?}", - elected_stashes.len(), - new_planned_era, - ); - } - - elected_stashes - } - - /// Process the output of the election. - /// - /// Store staking information for the new planned era + /// Store staking information for the new planned era of a single election page. pub fn store_stakers_info( - exposures: BoundedVec< - (T::AccountId, Exposure>), - MaxExposuresPerPageOf, - >, + exposures: Vec<(T::AccountId, Exposure>)>, new_planned_era: EraIndex, - ) -> BoundedVec> { - // Populate elected stash, stakers, exposures, and the snapshot of validator prefs. - let mut total_stake: BalanceOf = Zero::zero(); - let mut elected_stashes = Vec::with_capacity(exposures.len()); + ) -> BoundedVec> { + // populate elected stash, stakers, exposures, and the snapshot of validator prefs. + let mut total_stake_page: BalanceOf = Zero::zero(); + let mut elected_stashes_page = Vec::with_capacity(exposures.len()); exposures.into_iter().for_each(|(stash, exposure)| { - // build elected stash - elected_stashes.push(stash.clone()); - // accumulate total stake - total_stake = total_stake.saturating_add(exposure.total); - // store staker exposure for this era - EraInfo::::set_exposure(new_planned_era, &stash, exposure); + // build elected stash. + elected_stashes_page.push(stash.clone()); + // accumulate total stake. + total_stake_page = total_stake_page.saturating_add(exposure.total); + // set or update staker exposure for this era. + EraInfo::::upsert_exposure(new_planned_era, &stash, exposure); }); - let elected_stashes: BoundedVec<_, MaxExposuresPerPageOf> = elected_stashes - .try_into() - .expect("elected_stashes.len() always equal to exposures.len(); qed"); + let elected_stashes: BoundedVec<_, MaxWinnersPerPageOf> = + elected_stashes_page + .try_into() + .expect("elected_stashes.len() always equal to exposures.len(); qed"); - EraInfo::::set_total_stake(new_planned_era, total_stake); + // adds to total stake in this era. + EraInfo::::add_total_stake(new_planned_era, total_stake_page); - // Collect the pref of all winners. + // collect or update the pref of all winners. for stash in &elected_stashes { let pref = Self::validators(stash); >::insert(&new_planned_era, stash, pref); @@ -833,7 +771,7 @@ impl Pallet { if new_planned_era > 0 { log!( info, - "new validator set of size {:?} has been processed for era {:?}", + "updated validator set with {:?} validators for era {:?}", elected_stashes.len(), new_planned_era, ); @@ -844,10 +782,15 @@ impl Pallet { /// Consume a set of [`BoundedSupports`] from [`sp_npos_elections`] and collect them into a /// [`Exposure`]. + /// + /// Returns vec of all the exposures of a validator in `paged_supports`, bounded by the number + /// of max winners per page returned by the election provider. fn collect_exposures( supports: BoundedSupportsOf, - ) -> BoundedVec<(T::AccountId, Exposure>), MaxExposuresPerPageOf> - { + ) -> BoundedVec< + (T::AccountId, Exposure>), + MaxWinnersPerPageOf, + > { let total_issuance = asset::total_issuance::(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -975,7 +918,7 @@ impl Pallet { stash: T::AccountId, exposure: Exposure>, ) { - EraInfo::::set_exposure(current_era, &stash, exposure); + EraInfo::::upsert_exposure(current_era, &stash, exposure); } #[cfg(feature = "runtime-benchmarks")] @@ -1341,7 +1284,6 @@ impl Pallet { } } -// TODO(gpestana): add unit tests. impl LockableElectionDataProvider for Pallet { fn set_lock() -> data_provider::Result<()> { match ElectionDataLock::::get() { @@ -2084,7 +2026,7 @@ impl StakingInterface for Pallet { .map(|(who, value)| IndividualExposure { who: who.clone(), value: *value }) .collect::>(); let exposure = Exposure { total: Default::default(), own: Default::default(), others }; - EraInfo::::set_exposure(*current_era, stash, exposure); + EraInfo::::upsert_exposure(*current_era, stash, exposure); } fn set_current_era(era: EraIndex) { @@ -2341,6 +2283,7 @@ impl Pallet { own: Zero::zero(), nominator_count: 0, page_count: 0, + last_page_empty_slots: Default::default(), }; ErasStakersPaged::::iter_prefix((era,)) @@ -2359,6 +2302,8 @@ impl Pallet { own: metadata.own, nominator_count: metadata.nominator_count + expo.others.len() as u32, page_count: metadata.page_count + 1, + last_page_empty_slots: (T::MaxExposurePageSize::get() + .saturating_sub(expo.others.len() as u32)), }, ); diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 73f442723d585..13d0352423bc3 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -232,7 +232,10 @@ pub mod pallet { #[pallet::constant] type MaxExposurePageSize: Get; - /// The absolute maximum of next winner validators this pallet should return. + /// The absolute maximum of winner validators this pallet should return. + /// + /// As this pallet supports multi-block election, the set of winner validators *per + /// election* is bounded by this type. #[pallet::constant] type MaxValidatorSet: Get; @@ -742,8 +745,8 @@ pub mod pallet { /// Voter snapshot progress status. /// - /// If the status is `Ongoing`, it keeps track of the last voter account returned in the - /// snapshot. + /// If the status is `Ongoing`, it keeps a cursor of the last voter retrieved to proceed when + /// creating the next snapshot page. #[pallet::storage] pub(crate) type VoterSnapshotStatus = StorageValue<_, SnapshotStatus, ValueQuery>; @@ -756,25 +759,23 @@ pub mod pallet { pub(crate) type TargetSnapshotStatus = StorageValue<_, SnapshotStatus, ValueQuery>; - /// Keeps track of an ongoing multi-page election solution request and the block the first paged - /// was requested, if any. In addition, it also keeps track of the current era that is being - /// plannet. + /// Keeps track of an ongoing multi-page election solution request. + /// + /// Stores the block number of when the first election page was requested. `None` indicates + /// that the election results haven't started to be fetched. #[pallet::storage] - pub(crate) type ElectingStartedAt = - StorageValue<_, (BlockNumberFor, EraIndex), OptionQuery>; + pub(crate) type ElectingStartedAt = StorageValue<_, BlockNumberFor, OptionQuery>; - // TODO: - // * maybe use pallet-paged-list? (https://paritytech.github.io/polkadot-sdk/master/pallet_paged_list/index.html) + /// A bounded list of the "electable" stashes that resulted from a successful election. #[pallet::storage] pub(crate) type ElectableStashes = StorageValue<_, BoundedVec, ValueQuery>; - /// Lock for election data provider. + /// Lock state for election data mutations. /// - /// While the lock is set, the data to build a snapshot is frozen, i.e. the returned data from - /// `ElectionDataProvider` implementation will not change. + /// While the lock is set, there should be no mutations on the ledgers/staking data, ensuring + /// that the data provided to [`Config::ElectionDataProvider`] is stable during all pages. #[pallet::storage] - #[pallet::getter(fn election_data_lock)] pub(crate) type ElectionDataLock = StorageValue<_, (), OptionQuery>; #[pallet::genesis_config] @@ -840,6 +841,11 @@ pub mod pallet { ), _ => Ok(()), }); + assert!( + ValidatorCount::::get() <= + ::MaxWinnersPerPage::get() * + ::Pages::get() + ); } // all voters are reported to the `VoterList`. @@ -1017,51 +1023,41 @@ pub mod pallet { #[pallet::hooks] impl Hooks> for Pallet { /// Start fetching the election pages `Pages` blocks before the election prediction, so - /// that the `ElectableStashes` is ready with all the pages on time. + /// that the `ElectableStashes` has been populated with all validators from all pages at + /// the time of the election. fn on_initialize(now: BlockNumberFor) -> Weight { let pages: BlockNumberFor = <::ElectionProvider as ElectionProvider>::Pages::get().into(); - if let Some((started_at, planning_era)) = ElectingStartedAt::::get() { - let remaining_pages = + // election ongoing, fetch the next page. + if let Some(started_at) = ElectingStartedAt::::get() { + let next_page = pages.saturating_sub(One::one()).saturating_sub(now.saturating_sub(started_at)); - if remaining_pages == Zero::zero() { + // note: this pallet is expected to fetch all the solution pages starting from the + // most significant one through to the page 0. Fetching page zero is an indication + // that all the solution pages have been fetched. + if next_page == Zero::zero() { + crate::log!(trace, "elect(): finished fetching all paged solutions."); Self::do_elect_paged(Zero::zero()); - // last page, reset elect status and update era. - crate::log!(info, "elect(): finished fetching all paged solutions."); - CurrentEra::::set(Some(planning_era)); ElectingStartedAt::::kill(); } else { - crate::log!( - info, - "elect(): progressing with calling elect, remaining pages {:?}.", - remaining_pages - ); - Self::do_elect_paged(remaining_pages.saturated_into::()); + crate::log!(trace, "elect(): progressing, {:?} remaining pages.", next_page); + Self::do_elect_paged(next_page.saturated_into::()); } } else { + // election isn't ongoing yet, check if it should start. let next_election = ::next_election_prediction(now); if now == (next_election.saturating_sub(pages)) { - // start calling elect. crate::log!( - info, - "elect(): next election in {:?} pages, start fetching solution pages.", - pages, + trace, + "elect(): start fetching solution pages. expected pages: {}", + pages ); - Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)); - // set `ElectingStartedAt` only in multi-paged election. - if pages > One::one() { - ElectingStartedAt::::set(Some(( - now, - CurrentEra::::get().unwrap_or_default().saturating_add(1), - ))); - } else { - crate::log!(info, "elect(): finished fetching the single paged solution."); - } + Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)); } }; @@ -1099,7 +1095,15 @@ pub mod pallet { "As per documentation, slash defer duration ({}) should be less than bonding duration ({}).", T::SlashDeferDuration::get(), T::BondingDuration::get(), - ) + ); + + // TODO: needed and true? test it! + // The max exposure page size should not be larger than the max winners per page + // returned by the election provider. + assert!( + ::MaxExposurePageSize::get() <= + <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get() + ); } #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index a153f065ed19d..f66b4dcee597d 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -1314,6 +1314,7 @@ fn bond_extra_and_withdraw_unbonded_works() { legacy_claimed_rewards: bounded_vec![], } ); + assert_eq!( Staking::eras_stakers(active_era(), &11), Exposure { total: 1000, own: 1000, others: vec![] } @@ -1864,7 +1865,11 @@ fn reward_to_stake_works() { let _ = asset::set_stakeable_balance::(&20, 1000); // Bypass logic and change current exposure - EraInfo::::set_exposure(0, &21, Exposure { total: 69, own: 69, others: vec![] }); + EraInfo::::upsert_exposure( + 0, + &21, + Exposure { total: 69, own: 69, others: vec![] }, + ); >::insert( &20, StakingLedgerInspect { @@ -2334,7 +2339,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); - EraInfo::::set_exposure(0, &11, exposure); + EraInfo::::upsert_exposure(0, &11, exposure); ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(asset::total_balance::(&11), stake * 2); @@ -2346,7 +2351,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::Staked).unwrap(); // Override exposure of 11 - EraInfo::::set_exposure( + EraInfo::::upsert_exposure( 0, &11, Exposure { @@ -6932,7 +6937,7 @@ fn test_runtime_api_pending_rewards() { >::insert(0, validator_one, exposure.clone()); >::insert(0, validator_two, exposure.clone()); // add paged exposure for third validator - EraInfo::::set_exposure(0, &validator_three, exposure); + EraInfo::::upsert_exposure(0, &validator_three, exposure); // add some reward to be distributed ErasValidatorReward::::insert(0, 1000); @@ -8450,7 +8455,7 @@ pub mod multi_page_staking { } #[test] - fn collect_exposures_multi_page_elect_works() { + fn store_stakers_info_multi_page_elect_works() { ExtBuilder::default().exposures_page_size(2).build_and_execute(|| { assert_eq!(MaxExposurePageSize::get(), 2); @@ -8485,63 +8490,96 @@ pub mod multi_page_staking { let exposures_page_one = bounded_vec![(1, exposure_one), (2, exposure_two),]; let exposures_page_two = bounded_vec![(1, exposure_three),]; + // stores exposure page with exposures of validator 1 and 2, returns exposed validator + // account id. assert_eq!( - Pallet::::store_stakers_info_paged(exposures_page_one, current_era()) - .to_vec(), + Pallet::::store_stakers_info(exposures_page_one, current_era()).to_vec(), vec![1, 2] ); + // Stakers overview OK for validator 1 and 2. + assert_eq!( + ErasStakersOverview::::get(0, &1).unwrap(), + PagedExposureMetadata { + total: 1700, + own: 1000, + nominator_count: 3, + page_count: 2, + last_page_empty_slots: 1, + }, + ); assert_eq!( - Pallet::::store_stakers_info_paged(exposures_page_two, current_era()) - .to_vec(), + ErasStakersOverview::::get(0, &2).unwrap(), + PagedExposureMetadata { + total: 2000, + own: 1000, + nominator_count: 2, + page_count: 1, + last_page_empty_slots: 0, + }, + ); + + // stores exposure page with exposures of validator 1, returns exposed validator + // account id. + assert_eq!( + Pallet::::store_stakers_info(exposures_page_two, current_era()).to_vec(), vec![1] ); // Stakers overview OK for validator 1. assert_eq!( ErasStakersOverview::::get(0, &1).unwrap(), - PagedExposureMetadata { total: 2200, own: 1000, nominator_count: 5, page_count: 3 }, - ); - // Stakers overview OK for validator 2. - assert_eq!( - ErasStakersOverview::::get(0, &2).unwrap(), - PagedExposureMetadata { total: 2000, own: 1000, nominator_count: 2, page_count: 1 }, + PagedExposureMetadata { + total: 2200, + own: 1000, + nominator_count: 5, + page_count: 3, + last_page_empty_slots: 1, + }, ); // validator 1 has 3 paged exposures. + assert!( + ErasStakersPaged::::iter_prefix_values((0, &1)).count() as u32 == + EraInfo::::get_page_count(0, &1) && + EraInfo::::get_page_count(0, &1) == 3 + ); assert!(ErasStakersPaged::::get((0, &1, 0)).is_some()); assert!(ErasStakersPaged::::get((0, &1, 1)).is_some()); assert!(ErasStakersPaged::::get((0, &1, 2)).is_some()); assert!(ErasStakersPaged::::get((0, &1, 3)).is_none()); - assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &1)).count(), 3); // validator 2 has 1 paged exposures. assert!(ErasStakersPaged::::get((0, &2, 0)).is_some()); assert!(ErasStakersPaged::::get((0, &2, 1)).is_none()); assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &2)).count(), 1); - // exposures of validator 1. + // exposures of validator 1 are the expected: assert_eq!( - ErasStakersPaged::::iter_prefix_values((0, &1)).collect::>(), - vec![ - ExposurePage { - page_total: 100, - others: vec![IndividualExposure { who: 103, value: 100 }] - }, - ExposurePage { - page_total: 500, - others: vec![ - IndividualExposure { who: 110, value: 250 }, - IndividualExposure { who: 111, value: 250 } - ] - }, - ExposurePage { - page_total: 600, - others: vec![ - IndividualExposure { who: 101, value: 500 }, - IndividualExposure { who: 102, value: 100 } - ] - }, - ], + ErasStakersPaged::::get((0, &1, 0)).unwrap(), + ExposurePage { + page_total: 600, + others: vec![ + IndividualExposure { who: 101, value: 500 }, + IndividualExposure { who: 102, value: 100 } + ] + }, + ); + assert_eq!( + ErasStakersPaged::::get((0, &1, 1)).unwrap(), + ExposurePage { + page_total: 350, + others: vec![ + IndividualExposure { who: 103, value: 100 }, + IndividualExposure { who: 110, value: 250 } + ] + } + ); + assert_eq!( + ErasStakersPaged::::get((0, &1, 2)).unwrap(), + ExposurePage { + page_total: 250, + others: vec![IndividualExposure { who: 111, value: 250 }] + } ); // exposures of validator 2. diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 191c1c3d8a312..0efb21070e20e 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -381,7 +381,26 @@ impl< Balance: HasCompact + AtLeast32BitUnsigned + Copy + codec::MaxEncodedLen, > Exposure { - /// Splits an `Exposure` into `PagedExposureMetadata` and multiple chunks of + /// Splits self into two where the returned partial `Exposure` has max of `n_others` individual + /// exposures while the remaining exposures are left in `self`. + pub fn split_others(&mut self, n_others: u32) -> Self { + let head_others: Vec<_> = + self.others.drain(..(n_others as usize).min(self.others.len())).collect(); + + let total_others_head: Balance = head_others + .iter() + .fold(Zero::zero(), |acc: Balance, o| acc.saturating_add(o.value)); + + self.total = self.total.saturating_sub(total_others_head); + + Self { + total: total_others_head.saturating_add(self.own), + own: self.own, + others: head_others, + } + } + + /// Converts an `Exposure` into `PagedExposureMetadata` and multiple chunks of /// `IndividualExposure` with each chunk having maximum of `page_size` elements. pub fn into_pages( self, @@ -390,6 +409,7 @@ impl< let individual_chunks = self.others.chunks(page_size as usize); let mut exposure_pages: Vec> = Vec::with_capacity(individual_chunks.len()); + let mut total_chunks_last_page = Default::default(); for chunk in individual_chunks { let mut page_total: Balance = Zero::zero(); @@ -403,6 +423,7 @@ impl< }) } + total_chunks_last_page = others.len() as u32; exposure_pages.push(ExposurePage { page_total, others }); } @@ -412,6 +433,7 @@ impl< own: self.own, nominator_count: self.others.len() as u32, page_count: exposure_pages.len() as Page, + last_page_empty_slots: page_size.saturating_sub(total_chunks_last_page), }, exposure_pages, ) @@ -477,6 +499,8 @@ pub struct PagedExposureMetadata { pub nominator_count: u32, /// Number of pages of nominators. pub page_count: Page, + /// Number of empty slots in the last page. + pub last_page_empty_slots: u32, } impl PagedExposureMetadata @@ -485,22 +509,30 @@ where + codec::MaxEncodedLen + sp_std::ops::Add + sp_std::ops::Sub + + sp_runtime::Saturating + PartialEq + Copy + sp_runtime::traits::Debug, { - /// Merge a paged exposure metadata page into self and return the result. - pub fn merge(self, other: Self) -> Self { - // TODO(gpestana): re-enable assert. - //debug_assert!(self.own == other.own); + /// Consomes self and returns the result of the metadata updated with `other_balances` and + /// of adding `other_num` nominators to the metadata. + /// + /// `Max` is a getter of the maximum number of nominators per page. + pub fn update_with>( + self, + others_balance: Balance, + others_num: u32, + ) -> Self { + let new_nominator_count = self.nominator_count.saturating_add(others_num); + let new_page_count = + new_nominator_count.saturating_add(Max::get()).saturating_div(Max::get()); Self { - total: self.total + other.total - self.own, + total: self.total.saturating_add(others_balance), own: self.own, - nominator_count: self.nominator_count + other.nominator_count, - // TODO(gpestana): merge the pages efficiently so that we make sure all the slots in the - // page are filled. - page_count: self.page_count + other.page_count, + nominator_count: new_nominator_count, + page_count: new_page_count, + last_page_empty_slots: Max::get().saturating_sub(new_nominator_count % Max::get()), } } } From 7022467bca3f75f8fa16ca19092eba0c2273f12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 1 Nov 2024 12:49:15 +0100 Subject: [PATCH 26/95] updates electable stashes to allow for multiple adds across pages --- substrate/frame/staking/src/mock.rs | 9 ++++-- substrate/frame/staking/src/pallet/impls.rs | 35 ++++++++++++++++++--- substrate/frame/staking/src/pallet/mod.rs | 14 ++------- substrate/frame/staking/src/tests.rs | 30 ++++++++++++++++++ 4 files changed, 71 insertions(+), 17 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 1734395fb6e86..67540c25f7bdc 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -209,6 +209,7 @@ parameter_types! { pub static MaxValidatorSet: u32 = 100; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static AbsoluteMaxNominations: u32 = 16; + pub static MaxWinnersPerPage: u32 = u32::MAX; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -229,7 +230,7 @@ impl onchain::Config for OnChainSeqPhragmen { type WeightInfo = (); type Bounds = ElectionsBounds; type MaxBackersPerWinner = ConstU32<{ u32::MAX }>; - type MaxWinnersPerPage = ConstU32<{ u32::MAX }>; + type MaxWinnersPerPage = MaxWinnersPerPage; } pub struct MockReward {} @@ -431,6 +432,10 @@ impl ExtBuilder { self.balance_factor = factor; self } + pub fn max_validator_set(self, max: u32) -> Self { + MaxValidatorSet::set(max); + self + } pub fn try_state(self, enable: bool) -> Self { SkipTryStateCheck::set(!enable); self @@ -941,8 +946,8 @@ pub(crate) fn to_bounded_supports( supports: Vec<(AccountId, Support)>, ) -> BoundedSupports< AccountId, - <::ElectionProvider as ElectionProvider>::MaxBackersPerWinner, <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage, + <::ElectionProvider as ElectionProvider>::MaxBackersPerWinner, > { supports.try_into_bounded_supports().unwrap() } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index a566d7fd90acc..d889da7cbca24 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -666,6 +666,11 @@ impl Pallet { // note: exposures have already been processed and stored for each of the election // solution page at the time of `elect_paged(page_index)`. ElectableStashes::::take() + .into_inner() + .into_iter() + .collect::>() + .try_into() + .expect("same bounds, will fit; qed.") }; log!(info, "electable validators for session {:?}: {:?}", start_session_index, validators); @@ -728,10 +733,12 @@ impl Pallet { planning_era, ); - ElectableStashes::::mutate(|v| { - // TODO: dedup duplicate validator IDs, isntead of try_extend. - let _ = (*v).try_extend(stashes.into_iter()).defensive(); - }); + match Self::add_electables(stashes) { + Ok(_) => (), + Err(_) => { + defensive!("electable stashes exceeded limit, unexpected."); + }, + } } /// Process the output of a paged election. @@ -823,6 +830,26 @@ impl Pallet { .expect("we only map through support vector which cannot change the size; qed") } + /// Adds a new set of stashes to the electable stashes. + /// + /// Deduplicates stashes in place and returns an error if the bounds are exceeded. + pub(crate) fn add_electables( + stashes: BoundedVec>, + ) -> Result<(), ()> { + let mut storage_stashes = ElectableStashes::::get(); + for stash in stashes.into_iter() { + storage_stashes.try_insert(stash).map_err(|_| { + // add as many stashes as possible. + ElectableStashes::::set(storage_stashes.clone()); + () + })?; + } + + ElectableStashes::::set(storage_stashes); + + Ok(()) + } + /// Remove all associated data of a stash account from the staking system. /// /// Assumes storage is upgraded before calling. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 13d0352423bc3..54a6983573945 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -27,7 +27,7 @@ use frame_support::{ InspectLockableCurrency, LockableCurrency, OnUnbalanced, UnixTime, }, weights::Weight, - BoundedVec, + BoundedBTreeSet, BoundedVec, }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ @@ -769,7 +769,7 @@ pub mod pallet { /// A bounded list of the "electable" stashes that resulted from a successful election. #[pallet::storage] pub(crate) type ElectableStashes = - StorageValue<_, BoundedVec, ValueQuery>; + StorageValue<_, BoundedBTreeSet, ValueQuery>; /// Lock state for election data mutations. /// @@ -1061,7 +1061,7 @@ pub mod pallet { } }; - // TODO: benchmarls of fetching/ not fetching election page on_initialize. + // TODO: benchmark on_initialize // return the weight of the on_finalize. T::DbWeight::get().reads(1) @@ -1096,14 +1096,6 @@ pub mod pallet { T::SlashDeferDuration::get(), T::BondingDuration::get(), ); - - // TODO: needed and true? test it! - // The max exposure page size should not be larger than the max winners per page - // returned by the election provider. - assert!( - ::MaxExposurePageSize::get() <= - <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get() - ); } #[cfg(feature = "try-runtime")] diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index f66b4dcee597d..7b7f420e70456 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8374,6 +8374,36 @@ pub mod multi_page_staking { use super::*; use frame_election_provider_support::ElectionDataProvider; + #[test] + fn add_electable_stashes_work() { + ExtBuilder::default().max_validator_set(5).build_and_execute(|| { + assert_eq!(MaxValidatorSet::get(), 5); + assert!(ElectableStashes::::get().is_empty()); + + // adds stashes without duplicates, do not overflow bounds. + assert_ok!(Staking::add_electables(bounded_vec![1, 2, 3])); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3] + ); + + // adds with duplicates which are deduplicated implicitly, no not overflow bounds. + assert_ok!(Staking::add_electables(bounded_vec![1, 2, 4])); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4] + ); + + // adds stashes so that bounds are overflown, fails and internal state changes so that + // all slots are filled. + assert!(Staking::add_electables(bounded_vec![6, 7, 8, 9, 10]).is_err()); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4, 6] + ); + }) + } + #[test] fn multi_page_target_snapshot_works() { ExtBuilder::default().nominate(true).build_and_execute(|| { From b49684e1acaa9765306239964ad876f64da4495b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 1 Nov 2024 13:30:25 +0100 Subject: [PATCH 27/95] Adds staking pallet rustdocs; nits --- substrate/frame/staking/src/lib.rs | 34 ++++++++++++++++++--- substrate/frame/staking/src/pallet/impls.rs | 19 +++++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 890007ec92ba8..1923dda09e8cc 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -143,6 +143,34 @@ //! The pallet implement the trait `SessionManager`. Which is the only API to query new validator //! set and allowing these validator set to be rewarded once their era is ended. //! +//! ## Multi-page election support +//! +//! > Unless explicitly stated on the contrary, one page is the equivalent of one block. "Pages" and +//! "blocks" are used interchangibly across the documentation. +//! +//! The pallet supports a multi-page election. In a multi-block election, some key parts of the +//! staking pallet progress over multi pages. Most notably: +//! 1. **Snapshot creation**: Both the voter and target snapshots are created over multi blocks. The +//! [`frame_election_provider_support::ElectionDataProvider`] trait supports that functionality +//! by parameterizing the electin voters and electable targets by the page index. +//! 2. **Election**: The election is multi-block, where a set of supports is fetched per page/block. +//! This pallet keeps track of the elected stashes and their exposures as the paged election is +//! called. The [`frame_election_provider_support::ElectionProvider`] trait supports this +//! functionaluty by parameterizing the elect call with the page index. +//! +//! ### Prepare an election ahead of time with `on_initialize` +//! +//! This pallet is expected to have a set of winners ready and their exposures collected and stored +//! at the time of a predicted election. In order to ensure that, it starts to fetch the paged +//! results of an election from the [`frame_election_provider_support::ElectionProvider`] `N` pages +//! ahead of the next election prediction. +//! +//! As the pages of winners are fetched, their exposures and era info are processed and stored so +//! that all the data is ready at the time of the next election. +//! +//! Even though this pallet supports mulit-page elections, it also can be used in a single page +//! context provided that the configs are set accordingly. +//! //! ## Interface //! //! ### Dispatchable Functions @@ -352,11 +380,7 @@ macro_rules! log { /// config. pub type MaxWinnersOf = ::MaxValidatorSet; -/// Maximum number of exposures that can fit into an exposure page, as defined by this pallet's -/// config. -/// TODO: needed? maybe use the type directly. -pub type MaxExposuresPerPageOf = ::MaxExposurePageSize; - +/// Alias for the maximum number of winners per page, as expected by the election provider. pub type MaxWinnersPerPageOf

=

::MaxWinnersPerPage; /// Maximum number of nominations per nominator. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d889da7cbca24..af8a7d12590dd 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -837,15 +837,14 @@ impl Pallet { stashes: BoundedVec>, ) -> Result<(), ()> { let mut storage_stashes = ElectableStashes::::get(); - for stash in stashes.into_iter() { - storage_stashes.try_insert(stash).map_err(|_| { - // add as many stashes as possible. - ElectableStashes::::set(storage_stashes.clone()); - () - })?; - } + for stash in stashes.into_iter() { + storage_stashes.try_insert(stash).map_err(|_| { + // add as many stashes as possible before returning err. + ElectableStashes::::set(storage_stashes.clone()); + })?; + } - ElectableStashes::::set(storage_stashes); + ElectableStashes::::set(storage_stashes); Ok(()) } @@ -1312,6 +1311,10 @@ impl Pallet { } impl LockableElectionDataProvider for Pallet { + // TODO: currently, setting the lock in the election data provider is a noop. Implement the + // logic that freezes and/or buffers the mutations to ledgers while the lock is set *before* + // the multi-page election is enabled. + // Tracking issue . fn set_lock() -> data_provider::Result<()> { match ElectionDataLock::::get() { Some(_) => Err("lock already set"), From 7851c6e7da7f3628969fd5a1db733fbbee5a9503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 5 Nov 2024 15:00:39 +0100 Subject: [PATCH 28/95] Refactors the snapshot cursors of staking pallet and adds more tests --- substrate/frame/staking/src/lib.rs | 6 +- substrate/frame/staking/src/pallet/impls.rs | 128 +++++++------ substrate/frame/staking/src/tests.rs | 190 +++++++++++++------- 3 files changed, 204 insertions(+), 120 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 1923dda09e8cc..fa2a7564ebd14 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -148,8 +148,8 @@ //! > Unless explicitly stated on the contrary, one page is the equivalent of one block. "Pages" and //! "blocks" are used interchangibly across the documentation. //! -//! The pallet supports a multi-page election. In a multi-block election, some key parts of the -//! staking pallet progress over multi pages. Most notably: +//! The pallet supports a multi-page election. In a multi-page election, some key actions of the +//! staking pallet progress over multi pages/blocks. Most notably: //! 1. **Snapshot creation**: Both the voter and target snapshots are created over multi blocks. The //! [`frame_election_provider_support::ElectionDataProvider`] trait supports that functionality //! by parameterizing the electin voters and electable targets by the page index. @@ -482,7 +482,7 @@ pub struct UnlockChunk { /// Status of a paged snapshot progress. #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum SnapshotStatus { - /// Paged snapshot is in progress, the `AccountId` was the last staker iterated. + /// Paged snapshot is in progress, the `AccountId` was the last staker iterated in the list. Ongoing(AccountId), /// All the stakers in the system have been consumed since the snapshot started. Consumed, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index af8a7d12590dd..090c521ddefb2 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -952,18 +952,19 @@ impl Pallet { SlashRewardFraction::::put(fraction); } - /// Get all of the voters that are eligible for the npos election. + /// Get all the voters associated with `page` that are eligible for the npos election. /// - /// `maybe_max_len` can imposes a cap on the number of voters returned; + /// `maybe_max_len` can impose a cap on the number of voters returned per page. /// /// Sets `MinimumActiveStake` to the minimum active nominator stake in the returned set of /// nominators. /// + /// Note: in the context of the multi-page snapshot, we expect the *order* of `VoterList` and + /// `TargetList` not to change while the pages are being processed. This should be ensured by + /// the pallet, (e.g. using [`frame_election_provider_support::LockableElectionDataProvider`]). + /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_voters( - bounds: DataProviderBounds, - remaining_pages: PageIndex, - ) -> Vec> { + pub fn get_npos_voters(bounds: DataProviderBounds, page: PageIndex) -> Vec> { let mut voters_size_tracker: StaticTracker = StaticTracker::default(); let final_predicted_len = { @@ -982,13 +983,13 @@ impl Pallet { let mut min_active_stake = u64::MAX; let mut sorted_voters = match VoterSnapshotStatus::::get() { - // snapshot continues, start from last iterated voter in the list. - SnapshotStatus::Ongoing(start_at) => - T::VoterList::iter_from(&start_at).unwrap_or_else(|_| T::TargetList::iter()), - // all the voters have been consumed, return an empty iterator. - SnapshotStatus::Consumed => Box::new(vec![].into_iter()), - // start the snapshot processing, start from the beginning. + // start the snapshot procssing from the beginning. SnapshotStatus::Waiting => T::VoterList::iter(), + // snapshot continues, start from the last iterated voter in the list. + SnapshotStatus::Ongoing(account_id) => T::VoterList::iter_from(&account_id) + .defensive_unwrap_or(Box::new(vec![].into_iter())), + // all voters have been consumed already, return an empty iterator. + SnapshotStatus::Consumed => Box::new(vec![].into_iter()), }; while all_voters.len() < final_predicted_len as usize && @@ -1063,20 +1064,30 @@ impl Pallet { } } - match (remaining_pages, VoterSnapshotStatus::::get()) { - // last page requested, reset. - (0, _) => VoterSnapshotStatus::::set(SnapshotStatus::Waiting), - // all voters have been consumed, do nothing. - (_, SnapshotStatus::Consumed) => {}, - (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { - if let Some(last) = all_voters.last().map(|(x, _, _)| x).cloned() { - VoterSnapshotStatus::::set(SnapshotStatus::Ongoing(last)); - } else { - // no more to consume, next pages will be empty. - VoterSnapshotStatus::::set(SnapshotStatus::Consumed); - } - }, - }; + // update the voter snapshot status. + VoterSnapshotStatus::::mutate(|status| { + match (page, status.clone()) { + // last page, reset status for next round. + (0, _) => *status = SnapshotStatus::Waiting, + + (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { + let maybe_last = all_voters.last().map(|(x, _, _)| x).cloned(); + + if let Some(ref last) = maybe_last { + if maybe_last == T::VoterList::iter().last() { + // all voters in the voter list have been consumed. + *status = SnapshotStatus::Consumed; + } else { + *status = SnapshotStatus::Ongoing(last.clone()); + } + } else { + debug_assert!(*status == SnapshotStatus::Consumed); + } + }, + // do nothing. + (_, SnapshotStatus::Consumed) => (), + } + }); // all_voters should have not re-allocated. debug_assert!(all_voters.capacity() == final_predicted_len as usize); @@ -1099,13 +1110,14 @@ impl Pallet { all_voters } - /// Get the targets for an upcoming npos election. + /// Get all the targets associated with `page` that are eligible for the npos election. + /// + /// Note: in the context of the multi-page snapshot, we expect the *order* of `VoterList` and + /// `TargetList` not to change while the pages are being processed. This should be ensured by + /// the pallet, (e.g. using [`frame_election_provider_support::LockableElectionDataProvider`]). /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets( - bounds: DataProviderBounds, - remaining_pages: PageIndex, - ) -> Vec { + pub fn get_npos_targets(bounds: DataProviderBounds, page: PageIndex) -> Vec { let mut targets_size_tracker: StaticTracker = StaticTracker::default(); let final_predicted_len = { @@ -1115,15 +1127,16 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; + let mut targets_taken = 0u32; let mut targets_iter = match TargetSnapshotStatus::::get() { + // start the snapshot processing, start from the beginning. + SnapshotStatus::Waiting => T::TargetList::iter(), // snapshot continues, start from last iterated target in the list. SnapshotStatus::Ongoing(start_at) => - T::TargetList::iter_from(&start_at).unwrap_or_else(|_| T::TargetList::iter()), + T::TargetList::iter_from(&start_at).unwrap_or(Box::new(vec![].into_iter())), // all the targets have been consumed, return an empty iterator. SnapshotStatus::Consumed => Box::new(vec![].into_iter()), - // start the snapshot processing, start from the beginning. - SnapshotStatus::Waiting => T::TargetList::iter(), }; while all_targets.len() < final_predicted_len as usize && @@ -1147,23 +1160,34 @@ impl Pallet { if Validators::::contains_key(&target) { all_targets.push(target); + targets_taken.saturating_inc(); } } - match (remaining_pages, TargetSnapshotStatus::::get()) { - // last page requested, reset. - (0, _) => TargetSnapshotStatus::::set(SnapshotStatus::Waiting), - // all targets have been consumed, do nothing. - (_, SnapshotStatus::Consumed) => {}, - (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { - if let Some(last) = all_targets.last().cloned() { - TargetSnapshotStatus::::set(SnapshotStatus::Ongoing(last)); - } else { - // no more to consume, next pages will be empty. - TargetSnapshotStatus::::set(SnapshotStatus::Consumed); - } - }, - }; + // update the target snapshot status. + TargetSnapshotStatus::::mutate(|status| { + match (page, status.clone()) { + // last page, reset status for next round. + (0, _) => *status = SnapshotStatus::Waiting, + + (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { + let maybe_last = all_targets.last().map(|x| x).cloned(); + + if let Some(ref last) = maybe_last { + if maybe_last == T::TargetList::iter().last() { + // all targets in the target list have been consumed. + *status = SnapshotStatus::Consumed; + } else { + *status = SnapshotStatus::Ongoing(last.clone()); + } + } else { + debug_assert!(*status == SnapshotStatus::Consumed); + } + }, + // do nothing. + (_, SnapshotStatus::Consumed) => (), + } + }); Self::register_weight(T::WeightInfo::get_npos_targets(all_targets.len() as u32)); log!(info, "generated {} npos targets", all_targets.len()); @@ -1342,9 +1366,9 @@ impl ElectionDataProvider for Pallet { fn electing_voters( bounds: DataProviderBounds, - remaining_pages: PageIndex, + page: PageIndex, ) -> data_provider::Result>> { - let voters = Self::get_npos_voters(bounds, remaining_pages); + let voters = Self::get_npos_voters(bounds, page); debug_assert!(!bounds.exhausted( SizeBound(voters.encoded_size() as u32).into(), @@ -1356,9 +1380,9 @@ impl ElectionDataProvider for Pallet { fn electable_targets( bounds: DataProviderBounds, - remaining: PageIndex, + page: PageIndex, ) -> data_provider::Result> { - let targets = Self::get_npos_targets(bounds, remaining); + let targets = Self::get_npos_targets(bounds, page); // We can't handle this case yet -- return an error. WIP to improve handling this case in // . if bounds.exhausted(None, CountBound(targets.len() as u32).into()) { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 7b7f420e70456..572c1734d5033 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8406,82 +8406,142 @@ pub mod multi_page_staking { #[test] fn multi_page_target_snapshot_works() { - ExtBuilder::default().nominate(true).build_and_execute(|| { - let bounds = ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; + ExtBuilder::default() + .nominate(true) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(101, StakerStatus::Idle) + .build_and_execute(|| { + // all registered validators. + assert_eq!( + ::TargetList::iter().collect::>(), + vec![51, 31, 41, 21, 11] + ); - // fetch from page 3 to 0. - assert_eq!( - ::electable_targets(bounds, 3).unwrap(), - vec![31, 21] - ); - assert_eq!( - ::electable_targets(bounds, 2).unwrap(), - vec![11] - ); - // all targets consumed now, thus remaining calls are empty vecs. - assert!(::electable_targets(bounds, 1) - .unwrap() - .is_empty()); - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); - - assert!(::electable_targets(bounds, 0) - .unwrap() - .is_empty()); - - // once we reach page 0, the status reset. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); - // and requesting a nsew snapshot can restart - assert_eq!( - ::electable_targets(bounds, 1).unwrap(), - vec![31, 21] - ); - }) + // 2 targets per page. + let bounds = + ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; + + let mut all_targets = vec![]; + + let targets_page_3 = + ::electable_targets(bounds, 3).unwrap(); + all_targets.extend(targets_page_3.clone()); + + // result is expected: 2 most significant targets in the target list. + assert_eq!(targets_page_3, vec![51, 31]); + + // target snapshot status updated as expecteed: snapshot is ongoing, last target ID + // returned was 31 as there has been 2 targets comndumed already. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(31)); + + let targets_page_2 = + ::electable_targets(bounds, 2).unwrap(); + all_targets.extend(targets_page_2.clone()); + + assert_eq!(targets_page_2, vec![41, 21]); + // 4 targets consumed since the beginning. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(21)); + + let targets_page_1 = + ::electable_targets(bounds, 1).unwrap(); + all_targets.extend(targets_page_1.clone()); + + // did not fullfill the bounds because there were not enough targets in the list. + assert_eq!(targets_page_1, vec![11]); + + // all targets have been consumed in the list. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); + + // all targets in the list have been consumed, it should return an empty set of + // targets. + assert!(::electable_targets(bounds, 0) + .unwrap() + .is_empty()); + + // all pages have been requested, thus in waiting status, prepared for + // electable targets requests for a new snapshot. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); + + // now request 1 page with bounds where all registerd targets fit. u32::MAX + // emulates a no bounds request. + let bounds = + ElectionBoundsBuilder::default().targets_count(u32::MAX.into()).build().targets; + + let single_page_targets = + ::electable_targets(bounds, 0).unwrap(); + + // complete set of paged targets is the same as single page, no bounds set of + // targets. + assert_eq!(all_targets, single_page_targets); + }) } #[test] fn multi_page_voter_snapshot_works() { - ExtBuilder::default().nominate(true).build_and_execute(|| { - let bounds = ElectionBoundsBuilder::default().voters_count(3.into()).build().voters; + ExtBuilder::default() + .nominate(true) + .set_status(51, StakerStatus::Validator) + .set_status(41, StakerStatus::Nominator(vec![51])) + .set_status(101, StakerStatus::Validator) + .build_and_execute(|| { + let bounds = ElectionBoundsBuilder::default().voters_count(3.into()).build().voters; - // fetch from page 3 to 0. - assert_eq!( - ::electing_voters(bounds, 3) + assert_eq!( + ::VoterList::iter().collect::>(), + vec![11, 21, 31, 41, 51, 101], + ); + + let mut all_voters = vec![]; + + let voters_page_3 = ::electing_voters(bounds, 3) .unwrap() - .iter() - .map(|(x, _, _)| *x) - .collect::>(), - vec![11, 21, 31] - ); - assert_eq!( - ::electing_voters(bounds, 2) + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + all_voters.extend(voters_page_3.clone()); + + assert_eq!(voters_page_3, vec![11, 21, 31]); + + let voters_page_2 = ::electing_voters(bounds, 2) .unwrap() - .iter() - .map(|(x, _, _)| *x) - .collect::>(), - vec![101] - ); - // all voters consumed now, thus remaining calls are empty vecs. - assert!(::electing_voters(bounds, 1) - .unwrap() - .is_empty()); - assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Consumed); + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + all_voters.extend(voters_page_2.clone()); - assert!(::electing_voters(bounds, 0) - .unwrap() - .is_empty()); + assert_eq!(voters_page_2, vec![41, 51, 101]); - // once we reach page 0, the status reset. - assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); - // and requesting a nsew snapshot can restart - assert_eq!( - ::electing_voters(bounds, 1) + // all voters in the list have been consumed. + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Consumed); + + // thus page 1 and 0 are empty. + assert!(::electing_voters(bounds, 1) .unwrap() - .iter() - .map(|(x, _, _)| *x) - .collect::>(), - vec![11, 21, 31] - ); - }) + .is_empty()); + assert!(::electing_voters(bounds, 0) + .unwrap() + .is_empty()); + + // last page has been requested, reset the snapshot status to waiting. + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); + + // now request 1 page with bounds where all registerd voters fit. u32::MAX + // emulates a no bounds request. + let bounds = + ElectionBoundsBuilder::default().voters_count(u32::MAX.into()).build().targets; + + let single_page_voters = + ::electing_voters(bounds, 0) + .unwrap() + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + + // complete set of paged voters is the same as single page, no bounds set of + // voters. + assert_eq!(all_voters, single_page_voters); + }) } #[test] From 3ff9914932d1c079dd9b6903bd0dbea38190dc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 7 Nov 2024 12:25:46 +0100 Subject: [PATCH 29/95] Adds e2e tests to staking pallet --- substrate/frame/staking/src/lib.rs | 2 + substrate/frame/staking/src/mock.rs | 90 ++- substrate/frame/staking/src/pallet/impls.rs | 7 + substrate/frame/staking/src/pallet/mod.rs | 6 +- substrate/frame/staking/src/tests.rs | 317 --------- .../frame/staking/src/tests_paged_election.rs | 620 ++++++++++++++++++ 6 files changed, 713 insertions(+), 329 deletions(-) create mode 100644 substrate/frame/staking/src/tests_paged_election.rs diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index fa2a7564ebd14..74ced178ad6c6 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -322,6 +322,8 @@ pub mod testing_utils; pub(crate) mod mock; #[cfg(test)] mod tests; +#[cfg(test)] +mod tests_paged_election; pub mod asset; pub mod election_size_tracker; diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 67540c25f7bdc..7ca5f4b6453c7 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -20,8 +20,8 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, - onchain, BoundedSupports, ElectionProvider, SequentialPhragmen, Support, - TryIntoBoundedSupports, VoteWeight, + onchain, BoundedSupports, BoundedSupportsOf, ElectionProvider, PageIndex, SequentialPhragmen, + Support, TryIntoBoundedSupports, VoteWeight, }; use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, @@ -36,7 +36,7 @@ use sp_io; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ offence::{OffenceDetails, OnOffenceHandler}, - OnStakingUpdate, + OnStakingUpdate, StakingInterface, }; pub(crate) const INIT_TIMESTAMP: u64 = 30_000; @@ -209,7 +209,7 @@ parameter_types! { pub static MaxValidatorSet: u32 = 100; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static AbsoluteMaxNominations: u32 = 16; - pub static MaxWinnersPerPage: u32 = u32::MAX; + pub static MaxWinnersPerPage: u32 = 10_000; } type VoterBagsListInstance = pallet_bags_list::Instance1; @@ -222,6 +222,67 @@ impl pallet_bags_list::Config for Test { type Score = VoteWeight; } +// multi-page types and controller. +parameter_types! { + // default is single page EP. + pub static Pages: PageIndex = 1; + pub static MaxBackersPerWinner: u32 = 10_000; +} + +// An election provider wrapper that allows testing with single and multi page modes. +pub struct SingleOrMultipageElectionProvider(core::marker::PhantomData); +impl< + // single page EP. + SP: ElectionProvider< + AccountId = AccountId, + MaxWinnersPerPage = MaxWinnersPerPage, + MaxBackersPerWinner = ConstU32<{ u32::MAX }>, + Error = onchain::Error, + >, + > ElectionProvider for SingleOrMultipageElectionProvider +{ + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type MaxWinnersPerPage = MaxWinnersPerPage; + type MaxBackersPerWinner = ConstU32<{ u32::MAX }>; + type Pages = Pages; + type DataProvider = Staking; + type Error = onchain::Error; + + fn elect(page: PageIndex) -> Result, Self::Error> { + if Pages::get() == 1 { + SP::elect(page) + } else { + // will take first `MaxWinnersPerPage` in the validator set as winners. in this mock + // impl, we return a random nominator exposure per winner/page. + let supports: Vec<(AccountId, Support)> = Validators::::iter_keys() + .filter(|x| Staking::status(x) == Ok(StakerStatus::Validator)) + .take(Self::MaxWinnersPerPage::get() as usize) + .map(|v| { + ( + v, + Support { + total: (100 + page).into(), + voters: vec![(page as AccountId, (100 + page).into())], + }, + ) + }) + .collect::>(); + + Ok(to_bounded_supports(supports)) + } + } + fn msp() -> PageIndex { + SP::msp() + } + fn lsp() -> PageIndex { + SP::lsp() + } + fn ongoing() -> bool { + SP::ongoing() + } +} + pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Test; @@ -279,8 +340,9 @@ impl crate::pallet::pallet::Config for Test { type NextNewSession = Session; type MaxExposurePageSize = MaxExposurePageSize; type MaxValidatorSet = MaxValidatorSet; - type ElectionProvider = onchain::OnChainExecution; - type GenesisElectionProvider = Self::ElectionProvider; + type ElectionProvider = + SingleOrMultipageElectionProvider>; + type GenesisElectionProvider = onchain::OnChainExecution; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. type VoterList = VoterBagsList; type TargetList = UseValidatorsMap; @@ -432,8 +494,12 @@ impl ExtBuilder { self.balance_factor = factor; self } - pub fn max_validator_set(self, max: u32) -> Self { - MaxValidatorSet::set(max); + pub fn multi_page_election_provider(self, pages: PageIndex) -> Self { + Pages::set(pages); + self + } + pub fn max_winners_per_page(self, max: u32) -> Self { + MaxWinnersPerPage::set(max); self } pub fn try_state(self, enable: bool) -> Self { @@ -474,6 +540,7 @@ impl ExtBuilder { (71, self.balance_factor * 2000), (80, self.balance_factor), (81, self.balance_factor * 2000), + (91, self.balance_factor * 2000), // This allows us to have a total_payout different from 0. (999, 1_000_000_000_000), ], @@ -727,6 +794,13 @@ pub(crate) fn validator_controllers() -> Vec { .collect() } +pub(crate) fn era_exposures(era: u32) -> Vec<(AccountId, Exposure)> { + validator_controllers() + .into_iter() + .map(|v| (v, Staking::eras_stakers(era, &v))) + .collect::>() +} + pub(crate) fn on_offence_in_era( offenders: &[OffenceDetails< AccountId, diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 090c521ddefb2..d062537e2fe18 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -75,6 +75,11 @@ use sp_runtime::TryRuntimeError; const NPOS_MAX_ITERATIONS_COEFFICIENT: u32 = 2; impl Pallet { + /// Fetches the number of pages configured by the election provider. + pub fn election_pages() -> u32 { + <::ElectionProvider as ElectionProvider>::Pages::get() + } + /// Fetches the ledger associated with a controller or stash account, if any. pub fn ledger(account: StakingAccount) -> Result, Error> { StakingLedger::::get(account) @@ -628,6 +633,8 @@ impl Pallet { if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { Self::clear_era_information(old_era); } + // Including electing targets of previous era. + ElectingStartedAt::::kill(); } /// Potentially plan a new era. diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 54a6983573945..0d32370e172a7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1026,8 +1026,7 @@ pub mod pallet { /// that the `ElectableStashes` has been populated with all validators from all pages at /// the time of the election. fn on_initialize(now: BlockNumberFor) -> Weight { - let pages: BlockNumberFor = - <::ElectionProvider as ElectionProvider>::Pages::get().into(); + let pages: BlockNumberFor = Self::election_pages().into(); // election ongoing, fetch the next page. if let Some(started_at) = ElectingStartedAt::::get() { @@ -1040,8 +1039,6 @@ pub mod pallet { if next_page == Zero::zero() { crate::log!(trace, "elect(): finished fetching all paged solutions."); Self::do_elect_paged(Zero::zero()); - - ElectingStartedAt::::kill(); } else { crate::log!(trace, "elect(): progressing, {:?} remaining pages.", next_page); Self::do_elect_paged(next_page.saturated_into::()); @@ -1057,6 +1054,7 @@ pub mod pallet { pages ); + ElectingStartedAt::::set(Some(now)); Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)); } }; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 572c1734d5033..3398161f42aeb 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -8369,320 +8369,3 @@ mod byzantine_threshold_disabling_strategy { }); } } - -pub mod multi_page_staking { - use super::*; - use frame_election_provider_support::ElectionDataProvider; - - #[test] - fn add_electable_stashes_work() { - ExtBuilder::default().max_validator_set(5).build_and_execute(|| { - assert_eq!(MaxValidatorSet::get(), 5); - assert!(ElectableStashes::::get().is_empty()); - - // adds stashes without duplicates, do not overflow bounds. - assert_ok!(Staking::add_electables(bounded_vec![1, 2, 3])); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3] - ); - - // adds with duplicates which are deduplicated implicitly, no not overflow bounds. - assert_ok!(Staking::add_electables(bounded_vec![1, 2, 4])); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3, 4] - ); - - // adds stashes so that bounds are overflown, fails and internal state changes so that - // all slots are filled. - assert!(Staking::add_electables(bounded_vec![6, 7, 8, 9, 10]).is_err()); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3, 4, 6] - ); - }) - } - - #[test] - fn multi_page_target_snapshot_works() { - ExtBuilder::default() - .nominate(true) - .set_status(41, StakerStatus::Validator) - .set_status(51, StakerStatus::Validator) - .set_status(101, StakerStatus::Idle) - .build_and_execute(|| { - // all registered validators. - assert_eq!( - ::TargetList::iter().collect::>(), - vec![51, 31, 41, 21, 11] - ); - - // 2 targets per page. - let bounds = - ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; - - let mut all_targets = vec![]; - - let targets_page_3 = - ::electable_targets(bounds, 3).unwrap(); - all_targets.extend(targets_page_3.clone()); - - // result is expected: 2 most significant targets in the target list. - assert_eq!(targets_page_3, vec![51, 31]); - - // target snapshot status updated as expecteed: snapshot is ongoing, last target ID - // returned was 31 as there has been 2 targets comndumed already. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(31)); - - let targets_page_2 = - ::electable_targets(bounds, 2).unwrap(); - all_targets.extend(targets_page_2.clone()); - - assert_eq!(targets_page_2, vec![41, 21]); - // 4 targets consumed since the beginning. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(21)); - - let targets_page_1 = - ::electable_targets(bounds, 1).unwrap(); - all_targets.extend(targets_page_1.clone()); - - // did not fullfill the bounds because there were not enough targets in the list. - assert_eq!(targets_page_1, vec![11]); - - // all targets have been consumed in the list. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); - - // all targets in the list have been consumed, it should return an empty set of - // targets. - assert!(::electable_targets(bounds, 0) - .unwrap() - .is_empty()); - - // all pages have been requested, thus in waiting status, prepared for - // electable targets requests for a new snapshot. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); - - // now request 1 page with bounds where all registerd targets fit. u32::MAX - // emulates a no bounds request. - let bounds = - ElectionBoundsBuilder::default().targets_count(u32::MAX.into()).build().targets; - - let single_page_targets = - ::electable_targets(bounds, 0).unwrap(); - - // complete set of paged targets is the same as single page, no bounds set of - // targets. - assert_eq!(all_targets, single_page_targets); - }) - } - - #[test] - fn multi_page_voter_snapshot_works() { - ExtBuilder::default() - .nominate(true) - .set_status(51, StakerStatus::Validator) - .set_status(41, StakerStatus::Nominator(vec![51])) - .set_status(101, StakerStatus::Validator) - .build_and_execute(|| { - let bounds = ElectionBoundsBuilder::default().voters_count(3.into()).build().voters; - - assert_eq!( - ::VoterList::iter().collect::>(), - vec![11, 21, 31, 41, 51, 101], - ); - - let mut all_voters = vec![]; - - let voters_page_3 = ::electing_voters(bounds, 3) - .unwrap() - .into_iter() - .map(|(a, _, _)| a) - .collect::>(); - all_voters.extend(voters_page_3.clone()); - - assert_eq!(voters_page_3, vec![11, 21, 31]); - - let voters_page_2 = ::electing_voters(bounds, 2) - .unwrap() - .into_iter() - .map(|(a, _, _)| a) - .collect::>(); - all_voters.extend(voters_page_2.clone()); - - assert_eq!(voters_page_2, vec![41, 51, 101]); - - // all voters in the list have been consumed. - assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Consumed); - - // thus page 1 and 0 are empty. - assert!(::electing_voters(bounds, 1) - .unwrap() - .is_empty()); - assert!(::electing_voters(bounds, 0) - .unwrap() - .is_empty()); - - // last page has been requested, reset the snapshot status to waiting. - assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); - - // now request 1 page with bounds where all registerd voters fit. u32::MAX - // emulates a no bounds request. - let bounds = - ElectionBoundsBuilder::default().voters_count(u32::MAX.into()).build().targets; - - let single_page_voters = - ::electing_voters(bounds, 0) - .unwrap() - .into_iter() - .map(|(a, _, _)| a) - .collect::>(); - - // complete set of paged voters is the same as single page, no bounds set of - // voters. - assert_eq!(all_voters, single_page_voters); - }) - } - - #[test] - fn store_stakers_info_multi_page_elect_works() { - ExtBuilder::default().exposures_page_size(2).build_and_execute(|| { - assert_eq!(MaxExposurePageSize::get(), 2); - - let exposure_one = Exposure { - total: 1000 + 700, - own: 1000, - others: vec![ - IndividualExposure { who: 101, value: 500 }, - IndividualExposure { who: 102, value: 100 }, - IndividualExposure { who: 103, value: 100 }, - ], - }; - - let exposure_two = Exposure { - total: 1000 + 1000, - own: 1000, - others: vec![ - IndividualExposure { who: 104, value: 500 }, - IndividualExposure { who: 105, value: 500 }, - ], - }; - - let exposure_three = Exposure { - total: 1000 + 500, - own: 1000, - others: vec![ - IndividualExposure { who: 110, value: 250 }, - IndividualExposure { who: 111, value: 250 }, - ], - }; - - let exposures_page_one = bounded_vec![(1, exposure_one), (2, exposure_two),]; - let exposures_page_two = bounded_vec![(1, exposure_three),]; - - // stores exposure page with exposures of validator 1 and 2, returns exposed validator - // account id. - assert_eq!( - Pallet::::store_stakers_info(exposures_page_one, current_era()).to_vec(), - vec![1, 2] - ); - // Stakers overview OK for validator 1 and 2. - assert_eq!( - ErasStakersOverview::::get(0, &1).unwrap(), - PagedExposureMetadata { - total: 1700, - own: 1000, - nominator_count: 3, - page_count: 2, - last_page_empty_slots: 1, - }, - ); - assert_eq!( - ErasStakersOverview::::get(0, &2).unwrap(), - PagedExposureMetadata { - total: 2000, - own: 1000, - nominator_count: 2, - page_count: 1, - last_page_empty_slots: 0, - }, - ); - - // stores exposure page with exposures of validator 1, returns exposed validator - // account id. - assert_eq!( - Pallet::::store_stakers_info(exposures_page_two, current_era()).to_vec(), - vec![1] - ); - - // Stakers overview OK for validator 1. - assert_eq!( - ErasStakersOverview::::get(0, &1).unwrap(), - PagedExposureMetadata { - total: 2200, - own: 1000, - nominator_count: 5, - page_count: 3, - last_page_empty_slots: 1, - }, - ); - - // validator 1 has 3 paged exposures. - assert!( - ErasStakersPaged::::iter_prefix_values((0, &1)).count() as u32 == - EraInfo::::get_page_count(0, &1) && - EraInfo::::get_page_count(0, &1) == 3 - ); - assert!(ErasStakersPaged::::get((0, &1, 0)).is_some()); - assert!(ErasStakersPaged::::get((0, &1, 1)).is_some()); - assert!(ErasStakersPaged::::get((0, &1, 2)).is_some()); - assert!(ErasStakersPaged::::get((0, &1, 3)).is_none()); - - // validator 2 has 1 paged exposures. - assert!(ErasStakersPaged::::get((0, &2, 0)).is_some()); - assert!(ErasStakersPaged::::get((0, &2, 1)).is_none()); - assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &2)).count(), 1); - - // exposures of validator 1 are the expected: - assert_eq!( - ErasStakersPaged::::get((0, &1, 0)).unwrap(), - ExposurePage { - page_total: 600, - others: vec![ - IndividualExposure { who: 101, value: 500 }, - IndividualExposure { who: 102, value: 100 } - ] - }, - ); - assert_eq!( - ErasStakersPaged::::get((0, &1, 1)).unwrap(), - ExposurePage { - page_total: 350, - others: vec![ - IndividualExposure { who: 103, value: 100 }, - IndividualExposure { who: 110, value: 250 } - ] - } - ); - assert_eq!( - ErasStakersPaged::::get((0, &1, 2)).unwrap(), - ExposurePage { - page_total: 250, - others: vec![IndividualExposure { who: 111, value: 250 }] - } - ); - - // exposures of validator 2. - assert_eq!( - ErasStakersPaged::::iter_prefix_values((0, &2)).collect::>(), - vec![ExposurePage { - page_total: 1000, - others: vec![ - IndividualExposure { who: 104, value: 500 }, - IndividualExposure { who: 105, value: 500 } - ] - }], - ); - }) - } -} diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs new file mode 100644 index 0000000000000..064aabdd5d964 --- /dev/null +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -0,0 +1,620 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{mock::*, *}; +use frame_support::{assert_ok, testing_prelude::*}; +use substrate_test_utils::assert_eq_uvec; + +use frame_election_provider_support::{ + bounds::ElectionBoundsBuilder, ElectionDataProvider, SortedListProvider, +}; +use sp_staking::StakingInterface; + +#[test] +fn add_electable_stashes_work() { + ExtBuilder::default().build_and_execute(|| { + MaxValidatorSet::set(5); + assert_eq!(MaxValidatorSet::get(), 5); + assert!(ElectableStashes::::get().is_empty()); + + // adds stashes without duplicates, do not overflow bounds. + assert_ok!(Staking::add_electables(bounded_vec![1, 2, 3])); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3] + ); + + // adds with duplicates which are deduplicated implicitly, no not overflow bounds. + assert_ok!(Staking::add_electables(bounded_vec![1, 2, 4])); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4] + ); + + // adds stashes so that bounds are overflown, fails and internal state changes so that + // all slots are filled. + assert!(Staking::add_electables(bounded_vec![6, 7, 8, 9, 10]).is_err()); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4, 6] + ); + }) +} + +mod paged_on_initialize { + use super::*; + + #[test] + fn single_page_election_works() { + ExtBuilder::default() + // set desired targets to 3. + .validator_count(3) + .build_and_execute(|| { + // single page election provider. + assert_eq!( + <::ElectionProvider as ElectionProvider>::Pages::get(), + 1 + ); + + let next_election = ::next_election_prediction( + System::block_number(), + ); + + // single page. + let pages: BlockNumber = Staking::election_pages().into(); + assert_eq!(pages, 1); + + // genesis validators. + assert_eq!(current_era(), 0); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31]); + + // force unstake of 31 to ensure the election results of the next era are + // different than genesis. + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 31, 0)); + + let expected_elected = Validators::::iter_keys() + .filter(|x| Staking::status(x) == Ok(StakerStatus::Validator)) + .collect::>(); + // use all registered validators as potential targets. + ValidatorCount::::set(expected_elected.len() as u32); + assert_eq!(expected_elected.len(), 2); + + // 1. election prep hasn't started yet, election cursor and electable stashes are + // not + // set yet. + run_to_block(next_election - pages - 1); + assert_eq!(ElectingStartedAt::::get(), None); + assert!(ElectableStashes::::get().is_empty()); + + // 2. starts preparing election at the (election_prediction - n_pages) block. + run_to_block(next_election - pages); + + // electing started at cursor is set once the election starts to be prepared. + assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + // now the electable stashes have been fetched and stored. + assert_eq_uvec!( + ElectableStashes::::get().into_iter().collect::>(), + expected_elected + ); + + // era is still 0. + assert_eq!(current_era(), 0); + + // 3. progress to election block, which matches with era rotation. + run_to_block(next_election); + assert_eq!(current_era(), 1); + // clears out election metadata for era. + assert!(ElectingStartedAt::::get().is_none()); + assert!(ElectableStashes::::get().into_iter().collect::>().is_empty()); + + // era progresseed and electable stashes have been served to session pallet. + assert_eq_uvec!(Session::validators(), vec![11, 21, 31]); + + // 4. in the next era, the validator set does not include 31 anymore which was + // unstaked. + start_active_era(2); + assert_eq_uvec!(Session::validators(), vec![11, 21]); + }) + } + + #[test] + fn single_page_election_era_transition_exposures_work() { + ExtBuilder::default() + // set desired targets to 3. + .validator_count(3) + .build_and_execute(|| { + // single page election provider. + assert_eq!( + <::ElectionProvider as ElectionProvider>::Pages::get(), + 1 + ); + + assert_eq!(current_era(), 0); + + // 3 sessions per era. + assert_eq!(SessionsPerEra::get(), 3); + + // genesis validators and exposures. + assert_eq!(current_era(), 0); + assert_eq_uvec!(validator_controllers(), vec![11, 21, 31]); + assert_eq!( + era_exposures(current_era()), + vec![ + ( + 11, + Exposure { + total: 1125, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 125 }] + } + ), + ( + 21, + Exposure { + total: 1375, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 375 }] + } + ), + (31, Exposure { total: 500, own: 500, others: vec![] }) + ] + ); + + start_session(1); + assert_eq!(current_era(), 0); + // election haven't started yet. + assert_eq!(ElectingStartedAt::::get(), None); + assert!(ElectableStashes::::get().is_empty()); + + // progress to era rotation session. + start_session(SessionsPerEra::get()); + assert_eq!(current_era(), 1); + assert_eq_uvec!(Session::validators(), vec![11, 21, 31]); + assert_eq!( + era_exposures(current_era()), + vec![ + ( + 11, + Exposure { + total: 1125, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 125 }] + } + ), + ( + 21, + Exposure { + total: 1375, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 375 }] + } + ), + (31, Exposure { total: 500, own: 500, others: vec![] }) + ] + ); + + // force unstake validator 31 for next era. + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 31, 0)); + + // progress session and rotate era. + start_session(SessionsPerEra::get() * 2); + assert_eq!(current_era(), 2); + assert_eq_uvec!(Session::validators(), vec![11, 21]); + + assert_eq!( + era_exposures(current_era()), + vec![ + ( + 11, + Exposure { + total: 1125, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 125 }] + } + ), + ( + 21, + Exposure { + total: 1375, + own: 1000, + others: vec![IndividualExposure { who: 101, value: 375 }] + } + ), + ] + ); + }) + } + + #[test] + fn multi_page_election_works() { + ExtBuilder::default() + .add_staker(61, 61, 10, StakerStatus::Validator) + .add_staker(71, 71, 10, StakerStatus::Validator) + .add_staker(81, 81, 10, StakerStatus::Validator) + .add_staker(91, 91, 10, StakerStatus::Validator) + .multi_page_election_provider(3) + .max_winners_per_page(5) + .build_and_execute(|| { + // election provider has 3 pages. + let pages: BlockNumber = + <::ElectionProvider as ElectionProvider>::Pages::get().into(); + assert_eq!(pages, 3); + // 5 max winners per page. + let max_winners_page = <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get(); + assert_eq!(max_winners_page, 5); + + // genesis era. + assert_eq!(current_era(), 0); + + // confirm the genesis validators. + assert_eq!(Session::validators(), vec![11, 21]); + + let next_election = ::next_election_prediction( + System::block_number(), + ); + assert_eq!(next_election, 10); + + let expected_elected = Validators::::iter_keys() + .filter(|x| Staking::status(x) == Ok(StakerStatus::Validator)) + // mock multi page election provider takes first `max_winners_page` + // validators as winners. + .take(max_winners_page as usize) + .collect::>(); + // adjust desired targets to number of winners per page. + ValidatorCount::::set(expected_elected.len() as u32); + assert_eq!(expected_elected.len(), 5); + + // 1. election prep hasn't started yet, election cursor and electable stashes are not + // set yet. + run_to_block(next_election - pages - 1); + assert_eq!(ElectingStartedAt::::get(), None); + assert!(ElectableStashes::::get().is_empty()); + + // 2. starts preparing election at the (election_prediction - n_pages) block. + // fetches msp (i.e. 2). + run_to_block(next_election - pages); + + // electing started at cursor is set once the election starts to be prepared. + assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + // now the electable stashes started to be fetched and stored. + assert_eq_uvec!( + ElectableStashes::::get().into_iter().collect::>(), + expected_elected + ); + + // 3. progress one block to fetch page 1. + run_to_block(System::block_number() + 1); + // the electable stashes remain the same. + assert_eq_uvec!( + ElectableStashes::::get().into_iter().collect::>(), + expected_elected + ); + // election cursor reamins unchanged during intermediate pages. + assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + + // 4. progress one block to fetch lsp (i.e. 0). + run_to_block(System::block_number() + 1); + // the electable stashes remain the same. + assert_eq_uvec!( + ElectableStashes::::get().into_iter().collect::>(), + expected_elected + ); + // upon fetchin page 0, the electing started at will remain in storage until the + // era rotates. + assert_eq!(current_era(), 0); + assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + + // 5. rotate era. + start_active_era(current_era() + 1); + // the new era validators are the expected elected stashes. + assert_eq_uvec!(Session::validators(), expected_elected); + // and all the metadata has been cleared up and ready for the next election. + assert!(ElectingStartedAt::::get().is_none()); + assert!(ElectableStashes::::get().is_empty()); + }) + } +} + +mod paged_snapshot { + use super::*; + + #[test] + fn target_snapshot_works() { + ExtBuilder::default() + .nominate(true) + .set_status(41, StakerStatus::Validator) + .set_status(51, StakerStatus::Validator) + .set_status(101, StakerStatus::Idle) + .build_and_execute(|| { + // all registered validators. + assert_eq!( + ::TargetList::iter().collect::>(), + vec![51, 31, 41, 21, 11] + ); + + // 2 targets per page. + let bounds = + ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; + + let mut all_targets = vec![]; + + let targets_page_3 = + ::electable_targets(bounds, 3).unwrap(); + all_targets.extend(targets_page_3.clone()); + + // result is expected: 2 most significant targets in the target list. + assert_eq!(targets_page_3, vec![51, 31]); + + // target snapshot status updated as expecteed: snapshot is ongoing, last target ID + // returned was 31 as there has been 2 targets comndumed already. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(31)); + + let targets_page_2 = + ::electable_targets(bounds, 2).unwrap(); + all_targets.extend(targets_page_2.clone()); + + assert_eq!(targets_page_2, vec![41, 21]); + // 4 targets consumed since the beginning. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(21)); + + let targets_page_1 = + ::electable_targets(bounds, 1).unwrap(); + all_targets.extend(targets_page_1.clone()); + + // did not fullfill the bounds because there were not enough targets in the list. + assert_eq!(targets_page_1, vec![11]); + + // all targets have been consumed in the list. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); + + // all targets in the list have been consumed, it should return an empty set of + // targets. + assert!(::electable_targets(bounds, 0) + .unwrap() + .is_empty()); + + // all pages have been requested, thus in waiting status, prepared for + // electable targets requests for a new snapshot. + assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); + + // now request 1 page with bounds where all registerd targets fit. u32::MAX + // emulates a no bounds request. + let bounds = + ElectionBoundsBuilder::default().targets_count(u32::MAX.into()).build().targets; + + let single_page_targets = + ::electable_targets(bounds, 0).unwrap(); + + // complete set of paged targets is the same as single page, no bounds set of + // targets. + assert_eq!(all_targets, single_page_targets); + }) + } + + #[test] + fn voter_snapshot_works() { + ExtBuilder::default() + .nominate(true) + .set_status(51, StakerStatus::Validator) + .set_status(41, StakerStatus::Nominator(vec![51])) + .set_status(101, StakerStatus::Validator) + .build_and_execute(|| { + let bounds = ElectionBoundsBuilder::default().voters_count(3.into()).build().voters; + + assert_eq!( + ::VoterList::iter().collect::>(), + vec![11, 21, 31, 41, 51, 101], + ); + + let mut all_voters = vec![]; + + let voters_page_3 = ::electing_voters(bounds, 3) + .unwrap() + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + all_voters.extend(voters_page_3.clone()); + + assert_eq!(voters_page_3, vec![11, 21, 31]); + + let voters_page_2 = ::electing_voters(bounds, 2) + .unwrap() + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + all_voters.extend(voters_page_2.clone()); + + assert_eq!(voters_page_2, vec![41, 51, 101]); + + // all voters in the list have been consumed. + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Consumed); + + // thus page 1 and 0 are empty. + assert!(::electing_voters(bounds, 1) + .unwrap() + .is_empty()); + assert!(::electing_voters(bounds, 0) + .unwrap() + .is_empty()); + + // last page has been requested, reset the snapshot status to waiting. + assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); + + // now request 1 page with bounds where all registerd voters fit. u32::MAX + // emulates a no bounds request. + let bounds = + ElectionBoundsBuilder::default().voters_count(u32::MAX.into()).build().targets; + + let single_page_voters = + ::electing_voters(bounds, 0) + .unwrap() + .into_iter() + .map(|(a, _, _)| a) + .collect::>(); + + // complete set of paged voters is the same as single page, no bounds set of + // voters. + assert_eq!(all_voters, single_page_voters); + }) + } +} + +mod paged_exposures { + use super::*; + + #[test] + fn store_stakers_info_elect_works() { + ExtBuilder::default().exposures_page_size(2).build_and_execute(|| { + assert_eq!(MaxExposurePageSize::get(), 2); + + let exposure_one = Exposure { + total: 1000 + 700, + own: 1000, + others: vec![ + IndividualExposure { who: 101, value: 500 }, + IndividualExposure { who: 102, value: 100 }, + IndividualExposure { who: 103, value: 100 }, + ], + }; + + let exposure_two = Exposure { + total: 1000 + 1000, + own: 1000, + others: vec![ + IndividualExposure { who: 104, value: 500 }, + IndividualExposure { who: 105, value: 500 }, + ], + }; + + let exposure_three = Exposure { + total: 1000 + 500, + own: 1000, + others: vec![ + IndividualExposure { who: 110, value: 250 }, + IndividualExposure { who: 111, value: 250 }, + ], + }; + + let exposures_page_one = bounded_vec![(1, exposure_one), (2, exposure_two),]; + let exposures_page_two = bounded_vec![(1, exposure_three),]; + + // stores exposure page with exposures of validator 1 and 2, returns exposed validator + // account id. + assert_eq!( + Pallet::::store_stakers_info(exposures_page_one, current_era()).to_vec(), + vec![1, 2] + ); + // Stakers overview OK for validator 1 and 2. + assert_eq!( + ErasStakersOverview::::get(0, &1).unwrap(), + PagedExposureMetadata { + total: 1700, + own: 1000, + nominator_count: 3, + page_count: 2, + last_page_empty_slots: 1, + }, + ); + assert_eq!( + ErasStakersOverview::::get(0, &2).unwrap(), + PagedExposureMetadata { + total: 2000, + own: 1000, + nominator_count: 2, + page_count: 1, + last_page_empty_slots: 0, + }, + ); + + // stores exposure page with exposures of validator 1, returns exposed validator + // account id. + assert_eq!( + Pallet::::store_stakers_info(exposures_page_two, current_era()).to_vec(), + vec![1] + ); + + // Stakers overview OK for validator 1. + assert_eq!( + ErasStakersOverview::::get(0, &1).unwrap(), + PagedExposureMetadata { + total: 2200, + own: 1000, + nominator_count: 5, + page_count: 3, + last_page_empty_slots: 1, + }, + ); + + // validator 1 has 3 paged exposures. + assert!( + ErasStakersPaged::::iter_prefix_values((0, &1)).count() as u32 == + EraInfo::::get_page_count(0, &1) && + EraInfo::::get_page_count(0, &1) == 3 + ); + assert!(ErasStakersPaged::::get((0, &1, 0)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 1)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 2)).is_some()); + assert!(ErasStakersPaged::::get((0, &1, 3)).is_none()); + + // validator 2 has 1 paged exposures. + assert!(ErasStakersPaged::::get((0, &2, 0)).is_some()); + assert!(ErasStakersPaged::::get((0, &2, 1)).is_none()); + assert_eq!(ErasStakersPaged::::iter_prefix_values((0, &2)).count(), 1); + + // exposures of validator 1 are the expected: + assert_eq!( + ErasStakersPaged::::get((0, &1, 0)).unwrap(), + ExposurePage { + page_total: 600, + others: vec![ + IndividualExposure { who: 101, value: 500 }, + IndividualExposure { who: 102, value: 100 } + ] + }, + ); + assert_eq!( + ErasStakersPaged::::get((0, &1, 1)).unwrap(), + ExposurePage { + page_total: 350, + others: vec![ + IndividualExposure { who: 103, value: 100 }, + IndividualExposure { who: 110, value: 250 } + ] + } + ); + assert_eq!( + ErasStakersPaged::::get((0, &1, 2)).unwrap(), + ExposurePage { + page_total: 250, + others: vec![IndividualExposure { who: 111, value: 250 }] + } + ); + + // exposures of validator 2. + assert_eq!( + ErasStakersPaged::::iter_prefix_values((0, &2)).collect::>(), + vec![ExposurePage { + page_total: 1000, + others: vec![ + IndividualExposure { who: 104, value: 500 }, + IndividualExposure { who: 105, value: 500 } + ] + }], + ); + }) + } +} From bc7b20018444092d80004b73f74915e8fc30c4e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 7 Nov 2024 13:55:22 +0100 Subject: [PATCH 30/95] adds exposure collection checks to multi page election tests --- .../frame/staking/src/tests_paged_election.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 064aabdd5d964..08e2910493677 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -295,6 +295,13 @@ mod paged_on_initialize { ElectableStashes::::get().into_iter().collect::>(), expected_elected ); + // exposures have been collected for all validators in the page. + // note that the mock election provider adds one exposures per winner for + // each page. + for s in expected_elected.iter() { + // 1 page fetched, 1 `other` exposure collected per electable stash. + assert_eq!(Staking::eras_stakers(current_era() + 1, s).others.len(), 1); + } // 3. progress one block to fetch page 1. run_to_block(System::block_number() + 1); @@ -305,6 +312,11 @@ mod paged_on_initialize { ); // election cursor reamins unchanged during intermediate pages. assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + // exposures have been collected for all validators in the page. + for s in expected_elected.iter() { + // 2 pages fetched, 2 `other` exposures collected per electable stash. + assert_eq!(Staking::eras_stakers(current_era() + 1, s).others.len(), 2); + } // 4. progress one block to fetch lsp (i.e. 0). run_to_block(System::block_number() + 1); @@ -313,7 +325,12 @@ mod paged_on_initialize { ElectableStashes::::get().into_iter().collect::>(), expected_elected ); - // upon fetchin page 0, the electing started at will remain in storage until the + // exposures have been collected for all validators in the page. + for s in expected_elected.iter() { + // 3 pages fetched, 3 `other` exposures collected per electable stash. + assert_eq!(Staking::eras_stakers(current_era() + 1, s).others.len(), 3); + } + // upon fetching page 0, the electing started at will remain in storage until the // era rotates. assert_eq!(current_era(), 0); assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); From 2e71ab2d6b35e6f214970499e0eed1dddd9248e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 8 Nov 2024 12:00:11 +0100 Subject: [PATCH 31/95] EPM-MB: Supports only single page target snapshot (#6414) Removes the unnecessary complexity of paged target snapshot since it is not going be be used in AHM in the short/mid term. --- substrate/frame/staking/src/lib.rs | 10 ++- substrate/frame/staking/src/pallet/impls.rs | 52 +++--------- substrate/frame/staking/src/pallet/mod.rs | 8 -- .../frame/staking/src/tests_paged_election.rs | 79 ++++++++----------- 4 files changed, 49 insertions(+), 100 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 74ced178ad6c6..63d427cf1b9c8 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -150,14 +150,20 @@ //! //! The pallet supports a multi-page election. In a multi-page election, some key actions of the //! staking pallet progress over multi pages/blocks. Most notably: -//! 1. **Snapshot creation**: Both the voter and target snapshots are created over multi blocks. The +//! 1. **Snapshot creation**: The voter snapshot *may be* created over multi blocks. The //! [`frame_election_provider_support::ElectionDataProvider`] trait supports that functionality -//! by parameterizing the electin voters and electable targets by the page index. +//! by parameterizing the electing voters by the page index. Even though the target snapshot +//! could be paged, this pallet implements a single-page target snapshot only. //! 2. **Election**: The election is multi-block, where a set of supports is fetched per page/block. //! This pallet keeps track of the elected stashes and their exposures as the paged election is //! called. The [`frame_election_provider_support::ElectionProvider`] trait supports this //! functionaluty by parameterizing the elect call with the page index. //! +//! Note: [`frame_election_provider_support::ElectionDataProvider`] trait supports mulit-paged +//! target snaphsot. However, this pallet only supports and implements a single-page snapshot. +//! Calling [`ElectionDataProvider::electable_targets`] with a different index than 0 is redundant +//! and the single page idx 0 of targets be returned. +//! //! ### Prepare an election ahead of time with `on_initialize` //! //! This pallet is expected to have a set of winners ready and their exposures collected and stored diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d062537e2fe18..896e94ff01405 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -1117,14 +1117,12 @@ impl Pallet { all_voters } - /// Get all the targets associated with `page` that are eligible for the npos election. + /// Get all the targets associated are eligible for the npos election. /// - /// Note: in the context of the multi-page snapshot, we expect the *order* of `VoterList` and - /// `TargetList` not to change while the pages are being processed. This should be ensured by - /// the pallet, (e.g. using [`frame_election_provider_support::LockableElectionDataProvider`]). + /// The target snaphot is *always* single paged. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets(bounds: DataProviderBounds, page: PageIndex) -> Vec { + pub fn get_npos_targets(bounds: DataProviderBounds) -> Vec { let mut targets_size_tracker: StaticTracker = StaticTracker::default(); let final_predicted_len = { @@ -1134,18 +1132,8 @@ impl Pallet { let mut all_targets = Vec::::with_capacity(final_predicted_len as usize); let mut targets_seen = 0; - let mut targets_taken = 0u32; - - let mut targets_iter = match TargetSnapshotStatus::::get() { - // start the snapshot processing, start from the beginning. - SnapshotStatus::Waiting => T::TargetList::iter(), - // snapshot continues, start from last iterated target in the list. - SnapshotStatus::Ongoing(start_at) => - T::TargetList::iter_from(&start_at).unwrap_or(Box::new(vec![].into_iter())), - // all the targets have been consumed, return an empty iterator. - SnapshotStatus::Consumed => Box::new(vec![].into_iter()), - }; + let mut targets_iter = T::TargetList::iter(); while all_targets.len() < final_predicted_len as usize && targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * final_predicted_len as u32) { @@ -1167,35 +1155,9 @@ impl Pallet { if Validators::::contains_key(&target) { all_targets.push(target); - targets_taken.saturating_inc(); } } - // update the target snapshot status. - TargetSnapshotStatus::::mutate(|status| { - match (page, status.clone()) { - // last page, reset status for next round. - (0, _) => *status = SnapshotStatus::Waiting, - - (_, SnapshotStatus::Waiting) | (_, SnapshotStatus::Ongoing(_)) => { - let maybe_last = all_targets.last().map(|x| x).cloned(); - - if let Some(ref last) = maybe_last { - if maybe_last == T::TargetList::iter().last() { - // all targets in the target list have been consumed. - *status = SnapshotStatus::Consumed; - } else { - *status = SnapshotStatus::Ongoing(last.clone()); - } - } else { - debug_assert!(*status == SnapshotStatus::Consumed); - } - }, - // do nothing. - (_, SnapshotStatus::Consumed) => (), - } - }); - Self::register_weight(T::WeightInfo::get_npos_targets(all_targets.len() as u32)); log!(info, "generated {} npos targets", all_targets.len()); @@ -1389,7 +1351,11 @@ impl ElectionDataProvider for Pallet { bounds: DataProviderBounds, page: PageIndex, ) -> data_provider::Result> { - let targets = Self::get_npos_targets(bounds, page); + if page > 0 { + log!(warn, "multi-page target snapshot not supported, returning page 0."); + } + + let targets = Self::get_npos_targets(bounds); // We can't handle this case yet -- return an error. WIP to improve handling this case in // . if bounds.exhausted(None, CountBound(targets.len() as u32).into()) { diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0d32370e172a7..4e360dd9f41c0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -751,14 +751,6 @@ pub mod pallet { pub(crate) type VoterSnapshotStatus = StorageValue<_, SnapshotStatus, ValueQuery>; - /// Target snapshot progress status. - /// - /// If the status is `Ongoing`, it keeps track of the last target account returned in the - /// snapshot. - #[pallet::storage] - pub(crate) type TargetSnapshotStatus = - StorageValue<_, SnapshotStatus, ValueQuery>; - /// Keeps track of an ongoing multi-page election solution request. /// /// Stores the block number of when the first election page was requested. `None` indicates diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 08e2910493677..995d88c95ccee 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -358,58 +358,21 @@ mod paged_snapshot { .set_status(101, StakerStatus::Idle) .build_and_execute(|| { // all registered validators. - assert_eq!( + let all_targets = vec![51, 31, 41, 21, 11]; + assert_eq_uvec!( ::TargetList::iter().collect::>(), - vec![51, 31, 41, 21, 11] + all_targets, ); - // 2 targets per page. + // 3 targets per page. let bounds = - ElectionBoundsBuilder::default().targets_count(2.into()).build().targets; - - let mut all_targets = vec![]; - - let targets_page_3 = - ::electable_targets(bounds, 3).unwrap(); - all_targets.extend(targets_page_3.clone()); - - // result is expected: 2 most significant targets in the target list. - assert_eq!(targets_page_3, vec![51, 31]); - - // target snapshot status updated as expecteed: snapshot is ongoing, last target ID - // returned was 31 as there has been 2 targets comndumed already. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(31)); + ElectionBoundsBuilder::default().targets_count(3.into()).build().targets; - let targets_page_2 = - ::electable_targets(bounds, 2).unwrap(); - all_targets.extend(targets_page_2.clone()); - - assert_eq!(targets_page_2, vec![41, 21]); - // 4 targets consumed since the beginning. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Ongoing(21)); - - let targets_page_1 = - ::electable_targets(bounds, 1).unwrap(); - all_targets.extend(targets_page_1.clone()); - - // did not fullfill the bounds because there were not enough targets in the list. - assert_eq!(targets_page_1, vec![11]); - - // all targets have been consumed in the list. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Consumed); - - // all targets in the list have been consumed, it should return an empty set of - // targets. - assert!(::electable_targets(bounds, 0) - .unwrap() - .is_empty()); - - // all pages have been requested, thus in waiting status, prepared for - // electable targets requests for a new snapshot. - assert_eq!(TargetSnapshotStatus::::get(), SnapshotStatus::Waiting); + let targets = + ::electable_targets(bounds, 0).unwrap(); + assert_eq_uvec!(targets, all_targets.iter().take(3).cloned().collect::>()); - // now request 1 page with bounds where all registerd targets fit. u32::MAX - // emulates a no bounds request. + // emulates a no bounds target snapshot request. let bounds = ElectionBoundsBuilder::default().targets_count(u32::MAX.into()).build().targets; @@ -418,10 +381,32 @@ mod paged_snapshot { // complete set of paged targets is the same as single page, no bounds set of // targets. - assert_eq!(all_targets, single_page_targets); + assert_eq_uvec!(all_targets, single_page_targets); }) } + #[test] + fn target_snaposhot_multi_page_redundant() { + ExtBuilder::default().build_and_execute(|| { + let all_targets = vec![31, 21, 11]; + assert_eq_uvec!(::TargetList::iter().collect::>(), all_targets,); + + // no bounds. + let bounds = + ElectionBoundsBuilder::default().targets_count(u32::MAX.into()).build().targets; + + // target snapshot supports only single-page, thus it is redundant what's the page index + // requested. + let snapshot = Staking::electable_targets(bounds, 0).unwrap(); + assert!( + snapshot == all_targets && + snapshot == Staking::electable_targets(bounds, 1).unwrap() && + snapshot == Staking::electable_targets(bounds, 2).unwrap() && + snapshot == Staking::electable_targets(bounds, u32::MAX).unwrap(), + ); + }) + } + #[test] fn voter_snapshot_works() { ExtBuilder::default() From e9854fcec3fdb2607cd74c202ce12c2609d8bb56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Fri, 8 Nov 2024 18:04:35 +0100 Subject: [PATCH 32/95] Adds try-state checks for election prep metadata and tests --- substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 83 ++++++++++++++++- .../frame/staking/src/tests_paged_election.rs | 88 +++++++++++++++++-- 4 files changed, 164 insertions(+), 11 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 63d427cf1b9c8..0ec53a3552938 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1360,7 +1360,7 @@ impl EraInfo { // insert metadata. ErasStakersOverview::::insert(era, &validator, exposure_metadata); - // insert or update validator's overview. + // insert validator's overview. exposure_pages.iter().enumerate().for_each(|(idx, paged_exposure)| { let append_at = idx as Page; >::insert((era, &validator, append_at), &paged_exposure); diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 7ca5f4b6453c7..112d1ff148d5e 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -254,7 +254,7 @@ impl< SP::elect(page) } else { // will take first `MaxWinnersPerPage` in the validator set as winners. in this mock - // impl, we return a random nominator exposure per winner/page. + // impl, we return an arbitratily but deterministic nominator exposure per winner/page. let supports: Vec<(AccountId, Support)> = Validators::::iter_keys() .filter(|x| Staking::status(x) == Ok(StakerStatus::Validator)) .take(Self::MaxWinnersPerPage::get() as usize) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 896e94ff01405..d00f3cc662ed4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -80,6 +80,12 @@ impl Pallet { <::ElectionProvider as ElectionProvider>::Pages::get() } + /// Clears up all election preparation metadata in storage. + pub(crate) fn clear_election_metadata() { + ElectingStartedAt::::kill(); + ElectableStashes::::kill(); + } + /// Fetches the ledger associated with a controller or stash account, if any. pub fn ledger(account: StakingAccount) -> Result, Error> { StakingLedger::::get(account) @@ -633,8 +639,8 @@ impl Pallet { if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { Self::clear_era_information(old_era); } - // Including electing targets of previous era. - ElectingStartedAt::::kill(); + // Including election prep metadata. + Self::clear_election_metadata(); } /// Potentially plan a new era. @@ -704,6 +710,9 @@ impl Pallet { _ => {}, } + // election failed, clear election prep metadata. + Self::clear_election_metadata(); + Self::deposit_event(Event::StakingElectionFailed); return None } @@ -726,12 +735,15 @@ impl Pallet { Ok(result) => result, Err(e) => { log!(warn, "election provider page failed due to {:?} (page: {})", e, page); + // election failed, clear election prep metadata. + Self::clear_election_metadata(); + Self::deposit_event(Event::StakingElectionFailed); return }, }; - // preparing the next era. Note: we expect elect paged to be called *only* during a + // preparing the next era. Note: we expect `do_elect_paged` to be called *only* during a // non-genesis era, thus current era should be set by now. let planning_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); @@ -2112,13 +2124,14 @@ impl sp_staking::StakingUnchecked for Pallet { #[cfg(any(test, feature = "try-runtime"))] impl Pallet { - pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), TryRuntimeError> { + pub(crate) fn do_try_state(now: BlockNumberFor) -> Result<(), TryRuntimeError> { ensure!( T::VoterList::iter() .all(|x| >::contains_key(&x) || >::contains_key(&x)), "VoterList contains non-staker" ); + Self::ensure_snapshot_metadata_state(now)?; Self::check_ledgers()?; Self::check_bonded_consistency()?; Self::check_payees()?; @@ -2129,6 +2142,68 @@ impl Pallet { Self::ensure_disabled_validators_sorted() } + /// Invariants: + /// TODO + pub fn ensure_snapshot_metadata_state(now: BlockNumberFor) -> Result<(), TryRuntimeError> { + let pages: BlockNumberFor = Self::election_pages().into(); + let next_election = ::next_election_prediction(now); + let expect_election_start_at = next_election.saturating_sub(pages); + + let election_prep_started = now >= expect_election_start_at; + + // check election metadata, electable targets and era exposures if election should have + // already started. + match election_prep_started { + // election prep should have been started. + true => + if let Some(started_at) = ElectingStartedAt::::get() { + ensure!( + started_at == expect_election_start_at, + "unexpected electing_started_at block number in storage." + ); + ensure!( + !ElectableStashes::::get().is_empty(), + "election should have been started and the electable stashes non empty." + ); + + // all the current electable stashes exposures should have been collected and + // stored for the next era, and their total exposure suhould be > 0. + for s in ElectableStashes::::get().iter() { + ensure!( + EraInfo::::get_paged_exposure( + Self::current_era().unwrap_or_default().saturating_add(1), + s, + 0 + ) + .defensive_proof("electable stash exposure does not exist, unexpected.") + .unwrap() + .exposure_metadata + .total != Zero::zero(), + "no exposures collected for an electable stash." + ); + } + } else { + return Err( + "election prep should have started already, no election metadata in storage." + .into(), + ); + }, + // election prep should have not been started. + false => { + ensure!( + ElectableStashes::::get().is_empty(), + "unexpected electable stashes in storage while election prep hasn't started." + ); + ensure!( + ElectingStartedAt::::get().is_none(), + "unexpected election metadata while election prep hasn't started.", + ); + }, + } + + Ok(()) + } + /// Invariants: /// * A controller should not be associated with more than one ledger. /// * A bonded (stash, controller) pair should have only one associated ledger. I.e. if the diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 995d88c95ccee..78c26b2ed24d5 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::{mock::*, *}; -use frame_support::{assert_ok, testing_prelude::*}; +use frame_support::{assert_ok, testing_prelude::*, BoundedBTreeSet}; use substrate_test_utils::assert_eq_uvec; use frame_election_provider_support::{ @@ -52,6 +52,9 @@ fn add_electable_stashes_work() { ElectableStashes::::get().into_inner().into_iter().collect::>(), vec![1, 2, 3, 4, 6] ); + + // skip final try state checks. + SkipTryStateCheck::set(true); }) } @@ -100,8 +103,12 @@ mod paged_on_initialize { assert_eq!(ElectingStartedAt::::get(), None); assert!(ElectableStashes::::get().is_empty()); + // try-state sanity check. + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); + // 2. starts preparing election at the (election_prediction - n_pages) block. run_to_block(next_election - pages); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // electing started at cursor is set once the election starts to be prepared. assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); @@ -116,6 +123,7 @@ mod paged_on_initialize { // 3. progress to election block, which matches with era rotation. run_to_block(next_election); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 1); // clears out election metadata for era. assert!(ElectingStartedAt::::get().is_none()); @@ -174,7 +182,11 @@ mod paged_on_initialize { ] ); + // try-state sanity check. + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); + start_session(1); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 0); // election haven't started yet. assert_eq!(ElectingStartedAt::::get(), None); @@ -182,6 +194,7 @@ mod paged_on_initialize { // progress to era rotation session. start_session(SessionsPerEra::get()); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 1); assert_eq_uvec!(Session::validators(), vec![11, 21, 31]); assert_eq!( @@ -212,6 +225,7 @@ mod paged_on_initialize { // progress session and rotate era. start_session(SessionsPerEra::get() * 2); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 2); assert_eq_uvec!(Session::validators(), vec![11, 21]); @@ -242,10 +256,10 @@ mod paged_on_initialize { #[test] fn multi_page_election_works() { ExtBuilder::default() - .add_staker(61, 61, 10, StakerStatus::Validator) - .add_staker(71, 71, 10, StakerStatus::Validator) - .add_staker(81, 81, 10, StakerStatus::Validator) - .add_staker(91, 91, 10, StakerStatus::Validator) + .add_staker(61, 61, 1000, StakerStatus::Validator) + .add_staker(71, 71, 1000, StakerStatus::Validator) + .add_staker(81, 81, 1000, StakerStatus::Validator) + .add_staker(91, 91, 1000, StakerStatus::Validator) .multi_page_election_provider(3) .max_winners_per_page(5) .build_and_execute(|| { @@ -278,15 +292,20 @@ mod paged_on_initialize { ValidatorCount::::set(expected_elected.len() as u32); assert_eq!(expected_elected.len(), 5); + // try-state sanity check. + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); + // 1. election prep hasn't started yet, election cursor and electable stashes are not // set yet. run_to_block(next_election - pages - 1); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(ElectingStartedAt::::get(), None); assert!(ElectableStashes::::get().is_empty()); // 2. starts preparing election at the (election_prediction - n_pages) block. // fetches msp (i.e. 2). run_to_block(next_election - pages); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // electing started at cursor is set once the election starts to be prepared. assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); @@ -305,6 +324,7 @@ mod paged_on_initialize { // 3. progress one block to fetch page 1. run_to_block(System::block_number() + 1); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // the electable stashes remain the same. assert_eq_uvec!( ElectableStashes::::get().into_iter().collect::>(), @@ -320,6 +340,7 @@ mod paged_on_initialize { // 4. progress one block to fetch lsp (i.e. 0). run_to_block(System::block_number() + 1); + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // the electable stashes remain the same. assert_eq_uvec!( ElectableStashes::::get().into_iter().collect::>(), @@ -336,6 +357,7 @@ mod paged_on_initialize { assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); // 5. rotate era. + assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); start_active_era(current_era() + 1); // the new era validators are the expected elected stashes. assert_eq_uvec!(Session::validators(), expected_elected); @@ -344,6 +366,62 @@ mod paged_on_initialize { assert!(ElectableStashes::::get().is_empty()); }) } + + #[test] + fn try_state_failure_works() { + ExtBuilder::default().build_and_execute(|| { + let pages: BlockNumber = + <::ElectionProvider as ElectionProvider>::Pages::get().into(); + let next_election = + ::next_election_prediction(System::block_number()); + + let mut invalid_stashes = BoundedBTreeSet::new(); + + run_to_block(next_election - pages - 1); + + // election hasn't started yet, no electable stashes expected in storage. + assert_ok!(invalid_stashes.try_insert(42)); + ElectableStashes::::set(invalid_stashes); + assert_err!( + Staking::ensure_snapshot_metadata_state(System::block_number()), + "unexpected electable stashes in storage while election prep hasn't started." + ); + Staking::clear_election_metadata(); + + // election hasn't started yet, no electable stashes expected in storage. + ElectingStartedAt::::set(Some(42)); + assert_err!( + Staking::ensure_snapshot_metadata_state(System::block_number()), + "unexpected election metadata while election prep hasn't started." + ); + Staking::clear_election_metadata(); + + run_to_block(next_election - pages); + + // election prep started, metadata, electable stashes and exposures are expected to + // exist. + let _ = ErasStakersOverview::::clear(u32::MAX, None); + let _ = ErasStakersPaged::::clear(u32::MAX, None); + assert_err!( + Staking::ensure_snapshot_metadata_state(System::block_number()), + "no exposures collected for an electable stash." + ); + + ElectingStartedAt::::kill(); + assert_err!( + Staking::ensure_snapshot_metadata_state(System::block_number()), + "election prep should have started already, no election metadata in storage." + ); + ElectingStartedAt::::set(Some(424242)); + assert_err!( + Staking::ensure_snapshot_metadata_state(System::block_number()), + "unexpected electing_started_at block number in storage." + ); + + // skip final try state checks. + SkipTryStateCheck::set(true); + }) + } } mod paged_snapshot { From 9f4b6a337c31847e6f8e1c326c8892cb162b5377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 11 Nov 2024 23:27:21 +0100 Subject: [PATCH 33/95] more tests --- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 8 ++- .../frame/staking/src/tests_paged_election.rs | 69 +++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 112d1ff148d5e..e822dfaf017a2 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -263,7 +263,7 @@ impl< v, Support { total: (100 + page).into(), - voters: vec![(page as AccountId, (100 + page).into())], + voters: vec![((page + 1) as AccountId, (100 + page).into())], }, ) }) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d00f3cc662ed4..f1d6ce420f4ba 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2143,7 +2143,13 @@ impl Pallet { } /// Invariants: - /// TODO + /// * If the election preparation has started (i.e. `now` >= `expected_election - n_pages`): + /// * The election preparation metadata should be set (`ElectingStartedAt`); + /// * The electable stashes should not be empty; + /// * The exposures for the current electable stashes should have been collected; + /// * If the election preparation has not started yet: + /// * The election preparation metadata is empty; + /// * The electable stashes for this era is empty; pub fn ensure_snapshot_metadata_state(now: BlockNumberFor) -> Result<(), TryRuntimeError> { let pages: BlockNumberFor = Self::election_pages().into(); let next_election = ::next_election_prediction(now); diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 78c26b2ed24d5..26946887fb5ed 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -367,6 +367,75 @@ mod paged_on_initialize { }) } + #[test] + fn multi_page_election_with_mulit_page_exposures_rewards_work() { + ExtBuilder::default() + .add_staker(61, 61, 1000, StakerStatus::Validator) + .add_staker(71, 71, 1000, StakerStatus::Validator) + .add_staker(1, 1, 5, StakerStatus::Nominator(vec![21, 31, 71])) + .add_staker(2, 2, 5, StakerStatus::Nominator(vec![21, 31, 71])) + .add_staker(3, 3, 5, StakerStatus::Nominator(vec![21, 31, 71])) + .multi_page_election_provider(3) + .max_winners_per_page(3) + .exposures_page_size(2) + .build_and_execute(|| { + // election provider has 3 pages. + let pages: BlockNumber = + <::ElectionProvider as ElectionProvider>::Pages::get().into(); + assert_eq!(pages, 3); + // 3 max winners per page. + let max_winners_page = <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage::get(); + assert_eq!(max_winners_page, 3); + + // setup validator payee prefs and 10% commission. + for s in vec![21, 31, 71] { + Payee::::insert(s, RewardDestination::Account(s)); + let prefs = ValidatorPrefs { commission: Perbill::from_percent(10), ..Default::default() }; + Validators::::insert(s, prefs.clone()); + } + + let init_balance_all = vec![21, 31, 71, 1, 2, 3].iter().fold(0, |mut acc, s| { + acc += asset::total_balance::(&s); + acc + }); + + // progress era. + assert_eq!(current_era(), 0); + start_active_era(1); + assert_eq!(current_era(), 1); + assert_eq!(Session::validators(), vec![21, 31, 71]); + + // distribute reward, + Pallet::::reward_by_ids(vec![(21, 50)]); + Pallet::::reward_by_ids(vec![(31, 50)]); + Pallet::::reward_by_ids(vec![(71, 50)]); + + let total_payout = current_total_payout_for_duration(reward_time_per_era()); + + start_active_era(2); + + // all the validators exposed in era 1 have two pages of exposures, since exposure + // page size is 2. + assert_eq!(MaxExposurePageSize::get(), 2); + assert_eq!(EraInfo::::get_page_count(1, &21), 2); + assert_eq!(EraInfo::::get_page_count(1, &31), 2); + assert_eq!(EraInfo::::get_page_count(1, &71), 2); + + make_all_reward_payment(1); + + let balance_all = vec![21, 31, 71, 1, 2, 3].iter().fold(0, |mut acc, s| { + acc += asset::total_balance::(&s); + acc + }); + + assert_eq_error_rate!( + total_payout, + balance_all - init_balance_all, + 4 + ); + }) + } + #[test] fn try_state_failure_works() { ExtBuilder::default().build_and_execute(|| { From fb31d1b9d35968c52fca8f8320b7f92354f19221 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Tue, 12 Nov 2024 08:44:18 +0000 Subject: [PATCH 34/95] ".git/.scripts/commands/fmt/fmt.sh" --- .../frame/election-provider-multi-phase/src/benchmarking.rs | 3 ++- substrate/frame/staking/src/pallet/mod.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs index 408cbb476e0d5..a2289195fd662 100644 --- a/substrate/frame/election-provider-multi-phase/src/benchmarking.rs +++ b/substrate/frame/election-provider-multi-phase/src/benchmarking.rs @@ -289,7 +289,8 @@ mod benchmarks { // We don't directly need the data-provider to be populated, but it is just easy to use it. set_up_data_provider::(v, t); // default bounds are unbounded. - let targets = T::DataProvider::electable_targets(DataProviderBounds::default(), Zero::zero())?; + let targets = + T::DataProvider::electable_targets(DataProviderBounds::default(), Zero::zero())?; let voters = T::DataProvider::electing_voters(DataProviderBounds::default(), Zero::zero())?; let desired_targets = T::DataProvider::desired_targets()?; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 69d9a5a337954..b98279f3c80e0 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -911,7 +911,9 @@ pub mod pallet { /// The election failed. No new era is planned. StakingElectionFailed, /// An account has stopped participating as either a validator or nominator. - Chilled { stash: T::AccountId }, + Chilled { + stash: T::AccountId, + }, /// A Page of stakers rewards are getting paid. `next` is `None` if all pages are claimed. PayoutStarted { era_index: EraIndex, From 01e09c6c7842a32c9676be40628250f605f5e665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 09:58:28 +0100 Subject: [PATCH 35/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 40fa163a0aa63..614e56514ef4e 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -669,7 +669,7 @@ pub mod pallet { #[pallet::constant] type SignedDepositWeight: Get>; - /// Maximum number of winners that an electio supports. + /// Maximum number of winners that an election supports. /// /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. type MaxWinners: Get; From b4c900c96c54bca832e95b812928e1b2fc6e2151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 09:59:20 +0100 Subject: [PATCH 36/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 614e56514ef4e..c5d42361470a6 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1786,7 +1786,7 @@ impl ElectionProvider for Pallet { fn elect(page: PageIndex) -> Result, Self::Error> { // Note: this pallet **MUST** only by used in the single-block mode. - ensure!(page.is_zero(), ElectionError::::MultiPageNotSupported); + ensure!(page == SINGLE_PAGE, ElectionError::::MultiPageNotSupported); match Self::do_elect() { Ok(bounded_supports) => { From 628ae6777a97714c0a3b9cffbca0400af3a0f914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:01:00 +0100 Subject: [PATCH 37/95] Update prdoc/pr_6034.prdoc Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- prdoc/pr_6034.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index 420fd5ca36742..d26f285f4afd4 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -3,7 +3,7 @@ title: Adds multi-block election types and refactors current single logic to sup doc: - audience: Runtime Dev description: | - This PR adds election types and structs required to run a multi-block election. In additoin, + This PR adds election types and structs required to run a multi-block election. In addition, it EPM, staking pallet and all dependent pallets and logic to use the multi-block types. crates: From d05a002fb841aa4b4252634fdab4d363d8d5dee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:02:23 +0100 Subject: [PATCH 38/95] Update substrate/frame/staking/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 0ec53a3552938..9cdccca439f1d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -157,7 +157,7 @@ //! 2. **Election**: The election is multi-block, where a set of supports is fetched per page/block. //! This pallet keeps track of the elected stashes and their exposures as the paged election is //! called. The [`frame_election_provider_support::ElectionProvider`] trait supports this -//! functionaluty by parameterizing the elect call with the page index. +//! functionality by parameterizing the elect call with the page index. //! //! Note: [`frame_election_provider_support::ElectionDataProvider`] trait supports mulit-paged //! target snaphsot. However, this pallet only supports and implements a single-page snapshot. From 07796d935f328b2085d3cfcf9c67db851abadfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:02:38 +0100 Subject: [PATCH 39/95] Update substrate/frame/staking/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/staking/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 9cdccca439f1d..437cd1071add0 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1290,7 +1290,7 @@ impl EraInfo { /// /// If the exposure does not exist yet for the tuple (era, validator), it sets it. Otherwise, /// it updates the existing record by ensuring *intermediate* exposure pages are filled up with - /// `T::MaxExposurePageSize` number of backiers per page. + /// `T::MaxExposurePageSize` number of backers per page. pub fn upsert_exposure( era: EraIndex, validator: &T::AccountId, From 23b9c212bd00437da9a18af639c84aff32c8d854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:03:36 +0100 Subject: [PATCH 40/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index c5d42361470a6..5e2e754f2bf22 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -192,8 +192,8 @@ //! ## Multi-page election support //! //! The [`frame_election_provider_support::ElectionDataProvider`] and -//! [`frame_election_provider_support::ElectionProvider`] traits used by this pallet support a -//! multi page election. +//! [`frame_election_provider_support::ElectionProvider`] traits used by this pallet can support a +//! multi-page election. //! //! However, this pallet is meant to be used only in the context of a single-page election and data //! provider and all the relevant trait implementation ad configurations reflect that assumption. From 2570c230aba427b14ce277c6fdfd41ccef623868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:04:31 +0100 Subject: [PATCH 41/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 5e2e754f2bf22..1a1dbff2cde61 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -195,7 +195,7 @@ //! [`frame_election_provider_support::ElectionProvider`] traits used by this pallet can support a //! multi-page election. //! -//! However, this pallet is meant to be used only in the context of a single-page election and data +//! However, this pallet only supports single-page election and data //! provider and all the relevant trait implementation ad configurations reflect that assumption. //! //! If external callers request the election of a page index higher than 0, the election will fail From 808e2ba98eebb0377abca510ff0b07bfef746751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:10:20 +0100 Subject: [PATCH 42/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 1a1dbff2cde61..db087bae23154 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -674,7 +674,7 @@ pub mod pallet { /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. type MaxWinners: Get; - /// Maximum number of voters that can support a winner target in an election solution. + /// Maximum number of voters that can support a winner in an election solution. /// /// This limit must be set so that the memory limits of the rest of the system are /// respected. From 2092d2c261e41ae7178bc84e91864f4ea51f32d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:11:27 +0100 Subject: [PATCH 43/95] Update substrate/frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/unsigned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 1113c0bc8a96b..c6c29ff0af5a2 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -431,7 +431,7 @@ pub trait MinerConfig { type MaxWeight: Get; /// The maximum number of winners that can be elected per page (and overall). type MaxWinners: Get; - /// The maximum number of backers (edges) per winner in the last solution. + /// The maximum number of backers per winner in the last solution. type MaxBackersPerWinner: Get; /// Something that can compute the weight of a solution. /// From f2fe96041b1bb5b949b746624504b8f8380a8576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:12:39 +0100 Subject: [PATCH 44/95] Update substrate/frame/election-provider-support/src/onchain.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-support/src/onchain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 95f74ba298277..c8c985b2a4401 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -43,7 +43,7 @@ pub enum Error { /// `MaxWinners`. TooManyWinners, /// Single page election called with multi-page configs. - SinglePageExpected, + UnsupportedPageIndex, } impl From for Error { From bca81c29e3ffc33416aacd39a1dc07e37fae00b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:13:55 +0100 Subject: [PATCH 45/95] Update substrate/frame/election-provider-support/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-support/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index bfd29225fc6d6..72899972d96d6 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -326,7 +326,7 @@ pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. type MaxVotesPerVoter: Get; - /// Returns the possible targets for the election associated with page `page`, i.e. the targets + /// Returns the possible targets for the election associated with the provided `page`, i.e. the targets /// that could become elected, thus "electable". /// /// This should be implemented as a self-weighing function. The implementor should register its From df729a0898f3f69204868123ed0c117d1ca93458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 10:39:16 +0100 Subject: [PATCH 46/95] addresses PR review comments --- .../election-provider-support/src/onchain.rs | 4 ++-- substrate/frame/staking/src/pallet/impls.rs | 20 ++++++++----------- .../frame/staking/src/tests_paged_election.rs | 16 +++++++++++++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index c8c985b2a4401..be59450ce148b 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -42,7 +42,7 @@ pub enum Error { /// Configurational error caused by `desired_targets` requested by data provider exceeding /// `MaxWinners`. TooManyWinners, - /// Single page election called with multi-page configs. + /// Election page index not supported. UnsupportedPageIndex, } @@ -181,7 +181,7 @@ impl ElectionProvider for OnChainExecution { fn elect(page: PageIndex) -> Result, Self::Error> { if page > 0 { - return Err(Error::SinglePageExpected) + return Err(Error::UnsupportedPageIndex) } let election_bounds = ElectionBoundsBuilder::from(T::Bounds::get()).build(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d926f33084a85..5993b3dc4a978 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -625,9 +625,6 @@ impl Pallet { /// * Store start session index for the new planned era. /// * Clean old era information. /// - /// Note: staking information for the new planned era has been processed and stored during the - /// `elect_paged(page_index)` calls. - /// /// The new validator set for this era is stored under [`ElectableStashes`]. pub fn trigger_new_era(start_session_index: SessionIndex) { // Increment or set current era. @@ -857,15 +854,14 @@ impl Pallet { pub(crate) fn add_electables( stashes: BoundedVec>, ) -> Result<(), ()> { - let mut storage_stashes = ElectableStashes::::get(); - for stash in stashes.into_iter() { - storage_stashes.try_insert(stash).map_err(|_| { - // add as many stashes as possible before returning err. - ElectableStashes::::set(storage_stashes.clone()); - })?; - } - - ElectableStashes::::set(storage_stashes); + ElectableStashes::::mutate(|electable| { + for stash in stashes.into_iter() { + if let Err(_) = (*electable).try_insert(stash) { + return Err(()) + } + } + Ok(()) + })?; Ok(()) } diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 26946887fb5ed..edb40bc9bb99b 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -45,12 +45,24 @@ fn add_electable_stashes_work() { vec![1, 2, 3, 4] ); + // skip final try state checks. + SkipTryStateCheck::set(true); + }) +} + +#[test] +fn add_electable_stashes_overflow_works() { + ExtBuilder::default().build_and_execute(|| { + MaxValidatorSet::set(5); + assert_eq!(MaxValidatorSet::get(), 5); + assert!(ElectableStashes::::get().is_empty()); + // adds stashes so that bounds are overflown, fails and internal state changes so that // all slots are filled. - assert!(Staking::add_electables(bounded_vec![6, 7, 8, 9, 10]).is_err()); + assert!(Staking::add_electables(bounded_vec![1, 2, 3, 4, 5, 6]).is_err()); assert_eq!( ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3, 4, 6] + vec![1, 2, 3, 4, 5] ); // skip final try state checks. From 51329d7fc4c954469ecf9fb739835134c9c6f4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 12:39:25 +0100 Subject: [PATCH 47/95] ensures only collected electable stashes have exposures collectede --- .../election-provider-support/src/lib.rs | 12 +- substrate/frame/staking/src/pallet/impls.rs | 62 ++++++--- .../frame/staking/src/tests_paged_election.rs | 129 ++++++++++++------ 3 files changed, 140 insertions(+), 63 deletions(-) diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 72899972d96d6..766469c9c425b 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -326,8 +326,8 @@ pub trait ElectionDataProvider { /// Maximum number of votes per voter that this data provider is providing. type MaxVotesPerVoter: Get; - /// Returns the possible targets for the election associated with the provided `page`, i.e. the targets - /// that could become elected, thus "electable". + /// Returns the possible targets for the election associated with the provided `page`, i.e. the + /// targets that could become elected, thus "electable". /// /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. @@ -803,6 +803,14 @@ pub struct BoundedSupports, BInner: Get>( pub BoundedVec<(AccountId, BoundedSupport), BOuter>, ); +impl, BInner: Get> sp_std::ops::DerefMut + for BoundedSupports +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + impl, BInner: Get> Debug for BoundedSupports { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5993b3dc4a978..46a8d6c67ede0 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -729,6 +729,10 @@ impl Pallet { /// The results from the elect call shold be stored in the `ElectableStashes` storage. In /// addition, it stores stakers' information for next planned era based on the paged solution /// data returned. + /// + /// If any new election winner does not fit in the electable stashes storage, it truncates the + /// result of the election. We ensure that only the winners that are part of the electable + /// stashes have exposures collected for the next era. pub(crate) fn do_elect_paged(page: PageIndex) { let paged_result = match ::elect(page) { Ok(result) => result, @@ -742,19 +746,41 @@ impl Pallet { }, }; + if let Err(_) = Self::do_elect_paged_inner(paged_result) { + defensive!("electable stashes exceeded limit, unexpected but election proceeds."); + }; + } + + pub(crate) fn do_elect_paged_inner( + mut supports: BoundedSupportsOf, + ) -> Result<(), ()> { // preparing the next era. Note: we expect `do_elect_paged` to be called *only* during a // non-genesis era, thus current era should be set by now. let planning_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); - let stashes = Self::store_stakers_info( - Self::collect_exposures(paged_result).into_inner(), - planning_era, - ); + match Self::add_electables(supports.iter().map(|(s, _)| s.clone())) { + Ok(_) => { + let _ = Self::store_stakers_info( + Self::collect_exposures(supports).into_inner(), + planning_era, + ); + Ok(()) + }, + Err(not_included) => { + log!( + warn, + "not all winners fit within the electable stashes, excluding tail: {:?}.", + not_included + ); + + // filter out exposures of stashes that do not fit in electable stashes. + supports.retain(|(s, _)| !not_included.contains(s)); - match Self::add_electables(stashes) { - Ok(_) => (), - Err(_) => { - defensive!("electable stashes exceeded limit, unexpected."); + let _ = Self::store_stakers_info( + Self::collect_exposures(supports).into_inner(), + planning_era, + ); + Err(()) }, } } @@ -850,20 +876,22 @@ impl Pallet { /// Adds a new set of stashes to the electable stashes. /// - /// Deduplicates stashes in place and returns an error if the bounds are exceeded. + /// Deduplicates stashes in place and returns an error if the bounds are exceeded. In case of + /// error, it returns the stashes that were not added to the storage. pub(crate) fn add_electables( - stashes: BoundedVec>, - ) -> Result<(), ()> { + mut stashes_iter: impl Iterator, + ) -> Result<(), Vec> { ElectableStashes::::mutate(|electable| { - for stash in stashes.into_iter() { - if let Err(_) = (*electable).try_insert(stash) { - return Err(()) + while let Some(stash) = stashes_iter.next() { + if let Err(_) = (*electable).try_insert(stash.clone()) { + let mut not_included = stashes_iter.collect::>(); + not_included.push(stash); + + return Err(not_included); } } Ok(()) - })?; - - Ok(()) + }) } /// Remove all associated data of a stash account from the staking system. diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index edb40bc9bb99b..46180bf922f9d 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -20,54 +20,95 @@ use frame_support::{assert_ok, testing_prelude::*, BoundedBTreeSet}; use substrate_test_utils::assert_eq_uvec; use frame_election_provider_support::{ - bounds::ElectionBoundsBuilder, ElectionDataProvider, SortedListProvider, + bounds::ElectionBoundsBuilder, ElectionDataProvider, SortedListProvider, Support, }; use sp_staking::StakingInterface; -#[test] -fn add_electable_stashes_work() { - ExtBuilder::default().build_and_execute(|| { - MaxValidatorSet::set(5); - assert_eq!(MaxValidatorSet::get(), 5); - assert!(ElectableStashes::::get().is_empty()); - - // adds stashes without duplicates, do not overflow bounds. - assert_ok!(Staking::add_electables(bounded_vec![1, 2, 3])); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3] - ); - - // adds with duplicates which are deduplicated implicitly, no not overflow bounds. - assert_ok!(Staking::add_electables(bounded_vec![1, 2, 4])); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3, 4] - ); - - // skip final try state checks. - SkipTryStateCheck::set(true); - }) -} +mod electable_stashes { + use super::*; + + #[test] + fn add_electable_stashes_work() { + ExtBuilder::default().build_and_execute(|| { + MaxValidatorSet::set(5); + assert_eq!(MaxValidatorSet::get(), 5); + assert!(ElectableStashes::::get().is_empty()); + + // adds stashes without duplicates, do not overflow bounds. + assert_ok!(Staking::add_electables(vec![1u64, 2, 3].into_iter())); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3] + ); + + // adds with duplicates which are deduplicated implicitly, no not overflow bounds. + assert_ok!(Staking::add_electables(vec![1u64, 2, 4].into_iter())); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4] + ); + + // skip final try state checks. + SkipTryStateCheck::set(true); + }) + } + + #[test] + fn add_electable_stashes_overflow_works() { + ExtBuilder::default().build_and_execute(|| { + MaxValidatorSet::set(5); + assert_eq!(MaxValidatorSet::get(), 5); + assert!(ElectableStashes::::get().is_empty()); -#[test] -fn add_electable_stashes_overflow_works() { - ExtBuilder::default().build_and_execute(|| { - MaxValidatorSet::set(5); - assert_eq!(MaxValidatorSet::get(), 5); - assert!(ElectableStashes::::get().is_empty()); - - // adds stashes so that bounds are overflown, fails and internal state changes so that - // all slots are filled. - assert!(Staking::add_electables(bounded_vec![1, 2, 3, 4, 5, 6]).is_err()); - assert_eq!( - ElectableStashes::::get().into_inner().into_iter().collect::>(), - vec![1, 2, 3, 4, 5] - ); - - // skip final try state checks. - SkipTryStateCheck::set(true); - }) + // adds stashes so that bounds are overflown, fails and internal state changes so that + // all slots are filled. + assert!(Staking::add_electables(vec![1u64, 2, 3, 4, 5, 6].into_iter()).is_err()); + assert_eq!( + ElectableStashes::::get().into_inner().into_iter().collect::>(), + vec![1, 2, 3, 4, 5] + ); + + SkipTryStateCheck::set(true); + }) + } + + #[test] + fn overflow_electable_stashes_no_exposures_work() { + // ensures exposures are stored only for the electable stashes that fit within the + // electable stashes bounds in case of overflow. + ExtBuilder::default().build_and_execute(|| { + MaxValidatorSet::set(2); + assert_eq!(MaxValidatorSet::get(), 2); + assert!(ElectableStashes::::get().is_empty()); + + // current era is 0, preparing 1. + assert_eq!(current_era(), 0); + + let supports = to_bounded_supports(vec![ + (1, Support { total: 100, voters: vec![(10, 1_000)] }), + (2, Support { total: 200, voters: vec![(20, 2_000)] }), + (3, Support { total: 300, voters: vec![(30, 3_000)] }), + (4, Support { total: 400, voters: vec![(40, 4_000)] }), + ]); + + // error due to bounds. + assert!(Staking::do_elect_paged_inner(supports).is_err()); + + // electable stashes have been collected to the max bounds despite the error. + assert_eq!(ElectableStashes::::get().into_iter().collect::>(), vec![1, 2]); + + let exposure_exists = + |acc, era| EraInfo::::get_full_exposure(era, &acc).total != 0; + + // exposures were only collected for electable stashes in bounds (1 and 2). + assert!(exposure_exists(1, 1)); + assert!(exposure_exists(2, 1)); + assert!(!exposure_exists(3, 1)); + assert!(!exposure_exists(4, 1)); + + SkipTryStateCheck::set(true); + }) + } } mod paged_on_initialize { From 64d3ab3ab2102407a50cfba743add566a220c493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 12:43:11 +0100 Subject: [PATCH 48/95] comment nits --- substrate/frame/staking/src/pallet/impls.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 46a8d6c67ede0..d4c136751f2ff 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -751,6 +751,10 @@ impl Pallet { }; } + /// Inner implementation of [`Self::do_elect_paged`]. + /// + /// Returns an error if adding election winners to the electable stashes storage fails due to + /// exceeded bounds. pub(crate) fn do_elect_paged_inner( mut supports: BoundedSupportsOf, ) -> Result<(), ()> { @@ -773,7 +777,8 @@ impl Pallet { not_included ); - // filter out exposures of stashes that do not fit in electable stashes. + // filter out supports of stashes that do not fit within the electable stashes + // storage bounds to prevent collecting their exposures. supports.retain(|(s, _)| !not_included.contains(s)); let _ = Self::store_stakers_info( From 2082723b4fa32b89cbd6061bcb4a28fa7352f5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 14:54:21 +0100 Subject: [PATCH 49/95] adds type alias to ensure bounds are in order --- .../election-provider-multi-phase/src/lib.rs | 21 ++++++++++--------- .../src/signed.rs | 4 ++-- .../src/unsigned.rs | 10 ++++----- substrate/frame/staking/src/lib.rs | 16 ++------------ substrate/frame/staking/src/mock.rs | 2 +- 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index db087bae23154..fb6e785eb65bc 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -308,6 +308,12 @@ pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex /// The accuracy of the election, when submitted from offchain. Derived from [`SolutionOf`]. pub type SolutionAccuracyOf = ::MinerConfig> as NposSolution>::Accuracy; +/// A ready solution parameterized with this pallet's miner config. +pub type ReadySolutionOf = ReadySolution< + ::AccountId, + ::MaxWinners, + ::MaxBackersPerWinner, +>; /// The fallback election type. pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; @@ -1000,7 +1006,7 @@ pub mod pallet { ensure!(CurrentPhase::::get().is_emergency(), Error::::CallNotAllowed); // bound supports with T::MaxWinners. - let supports: BoundedSupports<_, _, _> = + let supports: BoundedSupportsOf> = supports.try_into_bounded_supports().map_err(|_| Error::::TooManyWinners)?; // Note: we don't `rotate_round` at this point; the next call to @@ -1280,8 +1286,7 @@ pub mod pallet { /// /// Always sorted by score. #[pallet::storage] - pub type QueuedSolution = - StorageValue<_, ReadySolution>; + pub type QueuedSolution = StorageValue<_, ReadySolutionOf>; /// Snapshot data of the round. /// @@ -1413,8 +1418,7 @@ impl Pallet { /// Current best solution, signed or unsigned, queued to be returned upon `elect`. /// /// Always sorted by score. - pub fn queued_solution( - ) -> Option> { + pub fn queued_solution() -> Option> { QueuedSolution::::get() } @@ -1600,8 +1604,7 @@ impl Pallet { pub fn feasibility_check( raw_solution: RawSolution>, compute: ElectionCompute, - ) -> Result, FeasibilityError> - { + ) -> Result, FeasibilityError> { let desired_targets = DesiredTargets::::get().ok_or(FeasibilityError::SnapshotUnavailable)?; @@ -1681,9 +1684,7 @@ impl Pallet { } /// record the weight of the given `supports`. - fn weigh_supports( - supports: &BoundedSupports, - ) { + fn weigh_supports(supports: &BoundedSupportsOf) { let active_voters = supports .iter() .map(|(_, x)| x) diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index 7fe8f5920b14e..5b8b22e6119b7 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -21,7 +21,7 @@ use core::marker::PhantomData; use crate::{ unsigned::MinerConfig, Config, ElectionCompute, Pallet, QueuedSolution, RawSolution, - ReadySolution, SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, + ReadySolutionOf, SignedSubmissionIndices, SignedSubmissionNextIndex, SignedSubmissionsMap, SnapshotMetadata, SolutionOf, SolutionOrSnapshotSize, Weight, WeightInfo, }; use alloc::{ @@ -490,7 +490,7 @@ impl Pallet { /// /// Infallible pub fn finalize_signed_phase_accept_solution( - ready_solution: ReadySolution, + ready_solution: ReadySolutionOf, who: &T::AccountId, deposit: BalanceOf, call_fee: BalanceOf, diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index c6c29ff0af5a2..00b41bbb25580 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -19,8 +19,8 @@ use crate::{ helpers, Call, Config, CurrentPhase, DesiredTargets, ElectionCompute, Error, FeasibilityError, - Pallet, QueuedSolution, RawSolution, ReadySolution, Round, RoundSnapshot, Snapshot, - SolutionAccuracyOf, SolutionOf, SolutionOrSnapshotSize, Weight, + Pallet, QueuedSolution, RawSolution, ReadySolution, ReadySolutionOf, Round, RoundSnapshot, + Snapshot, SolutionAccuracyOf, SolutionOf, SolutionOrSnapshotSize, Weight, }; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; @@ -429,7 +429,8 @@ pub trait MinerConfig { /// /// The weight is computed using `solution_weight`. type MaxWeight: Get; - /// The maximum number of winners that can be elected per page (and overall). + /// The maximum number of winners that can be elected in the single page supported by this + /// pallet. type MaxWinners: Get; /// The maximum number of backers per winner in the last solution. type MaxBackersPerWinner: Get; @@ -751,8 +752,7 @@ impl Miner { snapshot: RoundSnapshot>, current_round: u32, minimum_untrusted_score: Option, - ) -> Result, FeasibilityError> - { + ) -> Result, FeasibilityError> { let RawSolution { solution, score, round } = raw_solution; let RoundSnapshot { voters: snapshot_voters, targets: snapshot_targets } = snapshot; diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 437cd1071add0..c5a61f0981495 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -422,13 +422,6 @@ pub struct ActiveEraInfo { pub start: Option, } -/// Pointer to the last iterated indices for targets and voters used when generating the snapshot. -#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub(crate) struct LastIteratedStakers { - voter: AccountId, - target: AccountId, -} - /// Reward points of an era. Used to split era total payout between validators. /// /// This points will be used to reward validators and their respective nominators. @@ -488,22 +481,17 @@ pub struct UnlockChunk { } /// Status of a paged snapshot progress. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen, Default)] pub enum SnapshotStatus { /// Paged snapshot is in progress, the `AccountId` was the last staker iterated in the list. Ongoing(AccountId), /// All the stakers in the system have been consumed since the snapshot started. Consumed, /// Waiting for a new snapshot to be requested. + #[default] Waiting, } -impl Default for SnapshotStatus { - fn default() -> Self { - Self::Waiting - } -} - /// The ledger of a (bonded) stash. /// /// Note: All the reads and mutations to the [`Ledger`], [`Bonded`] and [`Payee`] storage items diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index e822dfaf017a2..cd68244c8cc24 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -209,7 +209,7 @@ parameter_types! { pub static MaxValidatorSet: u32 = 100; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static AbsoluteMaxNominations: u32 = 16; - pub static MaxWinnersPerPage: u32 = 10_000; + pub static MaxWinnersPerPage: u32 = 100; } type VoterBagsListInstance = pallet_bags_list::Instance1; From d720e5a65766cdf69d5337f12e2734a7669d40ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 15:19:25 +0100 Subject: [PATCH 50/95] integrity test --- substrate/frame/staking/src/pallet/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index b98279f3c80e0..5e825666d9733 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1088,6 +1088,14 @@ pub mod pallet { T::SlashDeferDuration::get(), T::BondingDuration::get(), ); + + // the max validator set bound must be the same of lower that the EP's max winner's per + // page, to ensure that the max validator set does not overflow when the retuned + // election page is full. + assert!( + ::MaxWinnersPerPage::get() <= + T::MaxValidatorSet::get() + ); } #[cfg(feature = "try-runtime")] From a88361a567c06e20820cb8ddefdab1f49a88c215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 15:20:46 +0100 Subject: [PATCH 51/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index fb6e785eb65bc..08fb10e2071ed 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -682,8 +682,7 @@ pub mod pallet { /// Maximum number of voters that can support a winner in an election solution. /// - /// This limit must be set so that the memory limits of the rest of the system are - /// respected. + /// This is needed to ensure election computation is bounded. type MaxBackersPerWinner: Get; /// Something that calculates the signed deposit base based on the signed submissions queue From ea5aa9ed89a8ec55b9cafca74f0dcc91040b328a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 15:21:19 +0100 Subject: [PATCH 52/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 08fb10e2071ed..46e54681807d9 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -1785,7 +1785,7 @@ impl ElectionProvider for Pallet { type DataProvider = T::DataProvider; fn elect(page: PageIndex) -> Result, Self::Error> { - // Note: this pallet **MUST** only by used in the single-block mode. + // Note: this pallet **MUST** only by used in the single-page mode. ensure!(page == SINGLE_PAGE, ElectionError::::MultiPageNotSupported); match Self::do_elect() { From d140b1feb61c25959cd0a7d48951ae1f495cd4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 12 Nov 2024 16:06:15 +0100 Subject: [PATCH 53/95] removes the lockable election provider and other nits --- .../election-provider-multi-phase/src/lib.rs | 3 ++- .../election-provider-multi-phase/src/mock.rs | 1 - .../election-provider-support/src/lib.rs | 19 -------------- substrate/frame/staking/src/pallet/impls.rs | 26 ++----------------- substrate/frame/staking/src/pallet/mod.rs | 7 ----- 5 files changed, 4 insertions(+), 52 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index fb6e785eb65bc..cc32b230f08a4 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -534,6 +534,7 @@ where (Miner(x), Miner(y)) if x == y => true, (DataProvider(x), DataProvider(y)) if x == y => true, (Fallback(x), Fallback(y)) if x == y => true, + (MultiPageNotSupported, MultiPageNotSupported) => true, _ => false, } } @@ -2510,7 +2511,7 @@ mod tests { assert_ok!(MultiPhase::elect(SINGLE_PAGE)); // however, multi page calls will fail. - assert!(MultiPhase::elect(10).is_err()); + assert_noop!(MultiPhase::elect(SINGLE_PAGE + 1), ElectionError::MultiPageNotSupported); }) } diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 4f2c38681d421..4add202ebc045 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -298,7 +298,6 @@ parameter_types! { pub static MaxWinners: u32 = 200; #[derive(Debug)] pub static MaxBackersPerWinner: u32 = 200; - pub static Pages: u32 = 1; // `ElectionBounds` and `OnChainElectionsBounds` are defined separately to set them independently in the tests. pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static OnChainElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 766469c9c425b..d1990e4b52fdf 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -64,12 +64,6 @@ //! supporting an election to be performed over multiple pages. This enables the //! [`ElectionDataProvider`] implementor to provide all the election data over multiple pages. //! Similarly [`ElectionProvider::elect`] is parameterized by page index. -////! ## [`LockableElectionDataProvider`] for multi-page election -//! -//! The [`LockableElectionDataProvider`] trait exposes a way for election data providers to lock -//! and unlock election data mutations. This is an useful trait to ensure that the results of -//! calling [`ElectionDataProvider::electing_voters`] and -//! [`ElectionDataProvider::electable_targets`] remain consistent over multiple pages. //! //! ## Election Data //! @@ -407,19 +401,6 @@ pub trait ElectionDataProvider { fn set_desired_targets(_count: u32) {} } -/// An [`ElectionDataProvider`] that exposes for an external entity to request lock/unlock on -/// updates in the election data. -/// -/// This functionality is useful when requesting multi-pages of election data, so that the data -/// provided across pages (and potentially across blocks) is consistent. -pub trait LockableElectionDataProvider: ElectionDataProvider { - /// Lock mutations in the election data provider. - fn set_lock() -> data_provider::Result<()>; - - /// Unlocks mutations in the election data provider. - fn unlock(); -} - /// Something that can compute the result of an election and pass it back to the caller in a paged /// way. pub trait ElectionProvider { diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index d4c136751f2ff..46207da2ce091 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -20,8 +20,7 @@ use frame_election_provider_support::{ bounds::{CountBound, SizeBound}, data_provider, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, - LockableElectionDataProvider, PageIndex, ScoreProvider, SortedListProvider, VoteWeight, - VoterOf, + PageIndex, ScoreProvider, SortedListProvider, VoteWeight, VoterOf, }; use frame_support::{ defensive, @@ -1010,8 +1009,7 @@ impl Pallet { /// nominators. /// /// Note: in the context of the multi-page snapshot, we expect the *order* of `VoterList` and - /// `TargetList` not to change while the pages are being processed. This should be ensured by - /// the pallet, (e.g. using [`frame_election_provider_support::LockableElectionDataProvider`]). + /// `TargetList` not to change while the pages are being processed. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. pub fn get_npos_voters(bounds: DataProviderBounds, page: PageIndex) -> Vec> { @@ -1346,26 +1344,6 @@ impl Pallet { } } -impl LockableElectionDataProvider for Pallet { - // TODO: currently, setting the lock in the election data provider is a noop. Implement the - // logic that freezes and/or buffers the mutations to ledgers while the lock is set *before* - // the multi-page election is enabled. - // Tracking issue . - fn set_lock() -> data_provider::Result<()> { - match ElectionDataLock::::get() { - Some(_) => Err("lock already set"), - None => { - ElectionDataLock::::set(Some(())); - Ok(()) - }, - } - } - - fn unlock() { - ElectionDataLock::::set(None); - } -} - impl ElectionDataProvider for Pallet { type AccountId = T::AccountId; type BlockNumber = BlockNumberFor; diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 5e825666d9733..0720d2391d130 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -763,13 +763,6 @@ pub mod pallet { pub(crate) type ElectableStashes = StorageValue<_, BoundedBTreeSet, ValueQuery>; - /// Lock state for election data mutations. - /// - /// While the lock is set, there should be no mutations on the ledgers/staking data, ensuring - /// that the data provided to [`Config::ElectionDataProvider`] is stable during all pages. - #[pallet::storage] - pub(crate) type ElectionDataLock = StorageValue<_, (), OptionQuery>; - #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { From 1a2ddfcee1ce2b3f4512586035601998297449a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 13 Nov 2024 17:39:17 +0100 Subject: [PATCH 54/95] removes unecessary last_page_empty_slots --- substrate/frame/staking/src/lib.rs | 17 +++++++------ substrate/frame/staking/src/pallet/impls.rs | 3 --- .../frame/staking/src/tests_paged_election.rs | 24 +++---------------- substrate/primitives/staking/src/lib.rs | 7 ------ 4 files changed, 11 insertions(+), 40 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index c5a61f0981495..764575e94e359 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -809,8 +809,6 @@ impl EraInfo { let page_size = T::MaxExposurePageSize::get().defensive_max(1); if let Some(stored_overview) = ErasStakersOverview::::get(era, &validator) { - let exposures_append = exposure.split_others(stored_overview.last_page_empty_slots); let last_page_idx = stored_overview.page_count.saturating_sub(1); - let last_page_idx = ErasStakersOverview::::mutate(era, &validator, |stored| { + let mut last_page = + ErasStakersPaged::::get((era, validator, last_page_idx)).unwrap_or_default(); + let last_page_empty_slots = + T::MaxExposurePageSize::get().saturating_sub(last_page.others.len() as u32); + + let exposures_append = exposure.split_others(last_page_empty_slots); + + ErasStakersOverview::::mutate(era, &validator, |stored| { // new metadata is updated based on 3 different set of exposures: the // current one, the exposure split to be "fitted" into the current last page and // the exposure set that will be appended from the new page onwards. @@ -1308,14 +1312,9 @@ impl EraInfo { }), ); *stored = new_metadata.into(); - - last_page_idx }); // fill up last page with exposures. - let mut last_page = - ErasStakersPaged::::get((era, validator, last_page_idx)).unwrap_or_default(); - last_page.page_total = last_page .page_total .saturating_add(exposures_append.total) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 46207da2ce091..a14ece52f83b7 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -2408,7 +2408,6 @@ impl Pallet { own: Zero::zero(), nominator_count: 0, page_count: 0, - last_page_empty_slots: Default::default(), }; ErasStakersPaged::::iter_prefix((era,)) @@ -2427,8 +2426,6 @@ impl Pallet { own: metadata.own, nominator_count: metadata.nominator_count + expo.others.len() as u32, page_count: metadata.page_count + 1, - last_page_empty_slots: (T::MaxExposurePageSize::get() - .saturating_sub(expo.others.len() as u32)), }, ); diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 46180bf922f9d..2610b93916cfd 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -723,23 +723,11 @@ mod paged_exposures { // Stakers overview OK for validator 1 and 2. assert_eq!( ErasStakersOverview::::get(0, &1).unwrap(), - PagedExposureMetadata { - total: 1700, - own: 1000, - nominator_count: 3, - page_count: 2, - last_page_empty_slots: 1, - }, + PagedExposureMetadata { total: 1700, own: 1000, nominator_count: 3, page_count: 2 }, ); assert_eq!( ErasStakersOverview::::get(0, &2).unwrap(), - PagedExposureMetadata { - total: 2000, - own: 1000, - nominator_count: 2, - page_count: 1, - last_page_empty_slots: 0, - }, + PagedExposureMetadata { total: 2000, own: 1000, nominator_count: 2, page_count: 1 }, ); // stores exposure page with exposures of validator 1, returns exposed validator @@ -752,13 +740,7 @@ mod paged_exposures { // Stakers overview OK for validator 1. assert_eq!( ErasStakersOverview::::get(0, &1).unwrap(), - PagedExposureMetadata { - total: 2200, - own: 1000, - nominator_count: 5, - page_count: 3, - last_page_empty_slots: 1, - }, + PagedExposureMetadata { total: 2200, own: 1000, nominator_count: 5, page_count: 3 }, ); // validator 1 has 3 paged exposures. diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 0efb21070e20e..4885f242c5c46 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -409,7 +409,6 @@ impl< let individual_chunks = self.others.chunks(page_size as usize); let mut exposure_pages: Vec> = Vec::with_capacity(individual_chunks.len()); - let mut total_chunks_last_page = Default::default(); for chunk in individual_chunks { let mut page_total: Balance = Zero::zero(); @@ -422,8 +421,6 @@ impl< value: individual.value, }) } - - total_chunks_last_page = others.len() as u32; exposure_pages.push(ExposurePage { page_total, others }); } @@ -433,7 +430,6 @@ impl< own: self.own, nominator_count: self.others.len() as u32, page_count: exposure_pages.len() as Page, - last_page_empty_slots: page_size.saturating_sub(total_chunks_last_page), }, exposure_pages, ) @@ -499,8 +495,6 @@ pub struct PagedExposureMetadata { pub nominator_count: u32, /// Number of pages of nominators. pub page_count: Page, - /// Number of empty slots in the last page. - pub last_page_empty_slots: u32, } impl PagedExposureMetadata @@ -532,7 +526,6 @@ where own: self.own, nominator_count: new_nominator_count, page_count: new_page_count, - last_page_empty_slots: Max::get().saturating_sub(new_nominator_count % Max::get()), } } } From 21170560c3a3283547dcc8a5c03ca134080e6cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 10:36:15 +0100 Subject: [PATCH 55/95] docs and tests for exposures.split_others --- substrate/frame/staking/src/lib.rs | 6 ++- substrate/primitives/staking/src/lib.rs | 57 ++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 764575e94e359..e87439515afa1 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1276,7 +1276,8 @@ impl EraInfo { /// /// If the exposure does not exist yet for the tuple (era, validator), it sets it. Otherwise, /// it updates the existing record by ensuring *intermediate* exposure pages are filled up with - /// `T::MaxExposurePageSize` number of backers per page. + /// `T::MaxExposurePageSize` number of backers per page and the remaining exposures are addded + /// to new exposure pages. pub fn upsert_exposure( era: EraIndex, validator: &T::AccountId, @@ -1292,6 +1293,9 @@ impl EraInfo { let last_page_empty_slots = T::MaxExposurePageSize::get().saturating_sub(last_page.others.len() as u32); + // splits the exposure so that `exposures_append` will fit witin the last exposure + // page, up to the max exposure page size. The remaining individual exposures in + // `exposure` will be added to new pages. let exposures_append = exposure.split_others(last_page_empty_slots); ErasStakersOverview::::mutate(era, &validator, |stored| { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 4885f242c5c46..9e9fde3a6db00 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -381,8 +381,10 @@ impl< Balance: HasCompact + AtLeast32BitUnsigned + Copy + codec::MaxEncodedLen, > Exposure { - /// Splits self into two where the returned partial `Exposure` has max of `n_others` individual - /// exposures while the remaining exposures are left in `self`. + /// Splits self into two instances of exposures. + /// + /// `n_others` individual exposures are consumed from self and returned as part of the new + /// exposure. pub fn split_others(&mut self, n_others: u32) -> Self { let head_others: Vec<_> = self.others.drain(..(n_others as usize).min(self.others.len())).collect(); @@ -716,4 +718,55 @@ mod tests { let exposure_page: ExposurePage = empty_exposures.into(); assert_eq!(exposure_page, ExposurePage { page_total: 0, others: vec![] }); } + + #[test] + fn exposure_split_others_works() { + let exposure = Exposure { + total: 100, + own: 20, + others: vec![ + IndividualExposure { who: 1, value: 20u32 }, + IndividualExposure { who: 2, value: 20 }, + IndividualExposure { who: 3, value: 20 }, + IndividualExposure { who: 4, value: 20 }, + ], + }; + + let mut exposure_0 = exposure.clone(); + // split others with with 0 `n_others` is a noop and returns an exposure with own only. + let split_exposure = exposure_0.split_others(0); + assert_eq!(exposure_0, exposure); + assert_eq!(split_exposure, Exposure { total: 20, own: 20, others: vec![] }); + + let mut exposure_1 = exposure.clone(); + // split individual exposures so that the returned exposure has 1 individual exposure. + let split_exposure = exposure_1.split_others(1); + assert_eq!(exposure_1.own, 20); + assert_eq!(exposure_1.total, 20 + 3 * 20); + assert_eq!(exposure_1.others.len(), 3); + + assert_eq!(split_exposure.own, 20); + assert_eq!(split_exposure.total, 20 + 1 * 20); + assert_eq!(split_exposure.others.len(), 1); + + let mut exposure_3 = exposure.clone(); + // split individual exposures so that the returned exposure has 3 individual exposures, + // which are consumed from the original exposure. + let split_exposure = exposure_3.split_others(3); + assert_eq!(exposure_3.own, 20); + assert_eq!(exposure_3.total, 20 + 1 * 20); + assert_eq!(exposure_3.others.len(), 1); + + assert_eq!(split_exposure.own, 20); + assert_eq!(split_exposure.total, 20 + 3 * 20); + assert_eq!(split_exposure.others.len(), 3); + + let mut exposure_100 = exposure.clone(); + // split others with with more `n_others` than the number of others in the exposure returns + // consumes all the individual exposures of the original Exposure and returns them in the + // new exposure. + let split_exposure = exposure_100.split_others(100); + assert_eq!(split_exposure, exposure); + assert_eq!(exposure_100, Exposure { total: 20, own: 20, others: vec![] }); + } } From 83c7288d71fb8540148b829b8b4cee82b3b2c31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 11:14:30 +0100 Subject: [PATCH 56/95] nits and removes sp-std dependency from staking primitives --- Cargo.lock | 1 - substrate/primitives/staking/Cargo.toml | 2 -- substrate/primitives/staking/src/lib.rs | 26 +++++++++++++------------ 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 771cffeebe5af..8408adf93675c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27272,7 +27272,6 @@ dependencies = [ "serde", "sp-core 28.0.0", "sp-runtime 31.0.1", - "sp-std 14.0.0", ] [[package]] diff --git a/substrate/primitives/staking/Cargo.toml b/substrate/primitives/staking/Cargo.toml index 80220cd1f6fcc..35e7e4f604136 100644 --- a/substrate/primitives/staking/Cargo.toml +++ b/substrate/primitives/staking/Cargo.toml @@ -23,7 +23,6 @@ impl-trait-for-tuples = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } -sp-std = { workspace = true } [features] default = ["std"] @@ -33,6 +32,5 @@ std = [ "serde/std", "sp-core/std", "sp-runtime/std", - "sp-std/std", ] runtime-benchmarks = ["sp-runtime/runtime-benchmarks"] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 9e9fde3a6db00..b53d75f512a57 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -25,7 +25,7 @@ extern crate alloc; use crate::currency_to_vote::CurrencyToVote; use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode, FullCodec, HasCompact, MaxEncodedLen}; -use core::ops::Sub; +use core::ops::{Add, AddAssign, Sub, SubAssign}; use scale_info::TypeInfo; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Zero}, @@ -357,8 +357,6 @@ pub struct IndividualExposure { /// A snapshot of the stake backing a single validator in the system. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -#[codec(mel_bound(T: Config))] -#[scale_info(skip_type_params(T))] pub struct Exposure { /// The total balance backing this validator. #[codec(compact)] @@ -385,6 +383,9 @@ impl< /// /// `n_others` individual exposures are consumed from self and returned as part of the new /// exposure. + /// + /// Since this method splits `others` of a single exposure, `total.own` will be the same for + /// both `self` and the returned exposure. pub fn split_others(&mut self, n_others: u32) -> Self { let head_others: Vec<_> = self.others.drain(..(n_others as usize).min(self.others.len())).collect(); @@ -455,8 +456,8 @@ impl Default for ExposurePage { } /// Returns an exposure page from a set of individual exposures. -impl - From>> for ExposurePage +impl From>> + for ExposurePage { fn from(exposures: Vec>) -> Self { exposures.into_iter().fold(ExposurePage::default(), |mut page, e| { @@ -503,8 +504,8 @@ impl PagedExposureMetadata where Balance: HasCompact + codec::MaxEncodedLen - + sp_std::ops::Add - + sp_std::ops::Sub + + Add + + Sub + sp_runtime::Saturating + PartialEq + Copy @@ -733,7 +734,8 @@ mod tests { }; let mut exposure_0 = exposure.clone(); - // split others with with 0 `n_others` is a noop and returns an exposure with own only. + // split others with with 0 `n_others` is a noop and returns an empty exposure (with `own` + // only). let split_exposure = exposure_0.split_others(0); assert_eq!(exposure_0, exposure); assert_eq!(split_exposure, Exposure { total: 20, own: 20, others: vec![] }); @@ -761,12 +763,12 @@ mod tests { assert_eq!(split_exposure.total, 20 + 3 * 20); assert_eq!(split_exposure.others.len(), 3); - let mut exposure_100 = exposure.clone(); - // split others with with more `n_others` than the number of others in the exposure returns + let mut exposure_max = exposure.clone(); + // split others with with more `n_others` than the number of others in the exposure // consumes all the individual exposures of the original Exposure and returns them in the // new exposure. - let split_exposure = exposure_100.split_others(100); + let split_exposure = exposure_max.split_others(u32::MAX); assert_eq!(split_exposure, exposure); - assert_eq!(exposure_100, Exposure { total: 20, own: 20, others: vec![] }); + assert_eq!(exposure_max, Exposure { total: 20, own: 20, others: vec![] }); } } From 6705e0ffae777890bd927f2e78362486588cd005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 11:15:02 +0100 Subject: [PATCH 57/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Guillaume Thiolliere --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 4081900d4d472..b0fad1bedeac6 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -196,7 +196,7 @@ //! multi-page election. //! //! However, this pallet only supports single-page election and data -//! provider and all the relevant trait implementation ad configurations reflect that assumption. +//! provider and all the relevant trait implementation and configurations reflect that assumption. //! //! If external callers request the election of a page index higher than 0, the election will fail //! with [`ElectionError::MultiPageNotSupported`]. From 4e13e4f682c5b97e28bfd3a7c57cdf0125f11c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 11:15:17 +0100 Subject: [PATCH 58/95] Update prdoc/pr_6034.prdoc Co-authored-by: Guillaume Thiolliere --- prdoc/pr_6034.prdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prdoc/pr_6034.prdoc b/prdoc/pr_6034.prdoc index d26f285f4afd4..e6ecd8aae5c8c 100644 --- a/prdoc/pr_6034.prdoc +++ b/prdoc/pr_6034.prdoc @@ -4,7 +4,7 @@ doc: - audience: Runtime Dev description: | This PR adds election types and structs required to run a multi-block election. In addition, - it EPM, staking pallet and all dependent pallets and logic to use the multi-block types. + it modifies EPM, staking pallet and all dependent pallets and logic to use the multi-block types. crates: - name: frame-election-provider-support From 825984b98db9550ac6075b6206f0777ce59aedb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 11:25:19 +0100 Subject: [PATCH 59/95] fixes epm test case --- .../frame/election-provider-multi-phase/src/lib.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index b0fad1bedeac6..bf511ece1c52c 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -2493,7 +2493,7 @@ mod tests { #[test] fn try_elect_multi_page_fails() { - ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + let prepare_election = || { roll_to_signed(); assert!(Snapshot::::get().is_some()); @@ -2505,11 +2505,17 @@ mod tests { )); roll_to(30); assert!(QueuedSolution::::get().is_some()); + }; + ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + prepare_election(); // single page elect call works as expected. assert_ok!(MultiPhase::elect(SINGLE_PAGE)); + }); - // however, multi page calls will fail. + ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { + prepare_election(); + // multi page calls will fail with multipage not supported error. assert_noop!(MultiPhase::elect(SINGLE_PAGE + 1), ElectionError::MultiPageNotSupported); }) } From 93d6bda464692ad55a5604c3cde354a7b46933da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 11:45:23 +0100 Subject: [PATCH 60/95] removes TryIntoBoundedSupports trait and impl coversion directly in SupportedBounds --- .../election-provider-multi-phase/src/lib.rs | 6 ++--- .../src/unsigned.rs | 6 ++--- .../election-provider-support/src/lib.rs | 23 ++++++++----------- .../election-provider-support/src/onchain.rs | 11 ++++----- substrate/frame/staking/src/mock.rs | 4 ++-- .../primitives/npos-elections/src/lib.rs | 2 ++ 6 files changed, 24 insertions(+), 28 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index bf511ece1c52c..8676be438300f 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -248,7 +248,7 @@ use codec::{Decode, Encode}; use frame_election_provider_support::{ bounds::{CountBound, ElectionBounds, ElectionBoundsBuilder, SizeBound}, BoundedSupports, BoundedSupportsOf, DataProviderBounds, ElectionDataProvider, ElectionProvider, - InstantElectionProvider, NposSolution, PageIndex, TryIntoBoundedSupports, + InstantElectionProvider, NposSolution, PageIndex, }; use frame_support::{ dispatch::DispatchClass, @@ -1007,7 +1007,7 @@ pub mod pallet { // bound supports with T::MaxWinners. let supports: BoundedSupportsOf> = - supports.try_into_bounded_supports().map_err(|_| Error::::TooManyWinners)?; + supports.try_into().map_err(|_| Error::::TooManyWinners)?; // Note: we don't `rotate_round` at this point; the next call to // `ElectionProvider::elect` will succeed and take care of that. @@ -2534,7 +2534,7 @@ mod tests { (30, Support { total: 40, voters: vec![(2, 5), (4, 5), (30, 30)] }), (40, Support { total: 60, voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] }), ] - .try_into_bounded_supports() + .try_into() .unwrap(); assert_eq!(supports, expected_supports); diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 00b41bbb25580..90b12343aaeb2 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -24,9 +24,7 @@ use crate::{ }; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; -use frame_election_provider_support::{ - NposSolution, NposSolver, PerThing128, TryIntoBoundedSupports, VoteWeight, -}; +use frame_election_provider_support::{NposSolution, NposSolver, PerThing128, VoteWeight}; use frame_support::{ dispatch::DispatchResult, ensure, @@ -823,7 +821,7 @@ impl Miner { // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. let supports = supports - .try_into_bounded_supports() + .try_into() .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; Ok(ReadySolution { supports, compute, score }) diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index d1990e4b52fdf..49bd533cc8c3c 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -849,33 +849,30 @@ impl, BInner: Get> IntoIterator } } -/// An extension trait to convert from [`sp_npos_elections::Supports`] into -/// [`BoundedSupports`]. -pub trait TryIntoBoundedSupports, BInner: Get> { - /// Perform the conversion. - fn try_into_bounded_supports(self) -> Result, ()>; -} - -impl, BInner: Get> - TryIntoBoundedSupports for sp_npos_elections::Supports +impl, BInner: Get> TryFrom> + for BoundedSupports { - fn try_into_bounded_supports(self) -> Result, ()> { + type Error = crate::Error; + + fn try_from(supports: sp_npos_elections::Supports) -> Result { // optimization note: pre-allocate outer bounded vec. let mut outer_bounded_supports = BoundedVec::< (AccountId, BoundedSupport), BOuter, >::with_bounded_capacity( - self.len().min(BOuter::get() as usize) + supports.len().min(BOuter::get() as usize) ); // optimization note: avoid intermediate allocations. - self.into_iter() + supports + .into_iter() .map(|(account, support)| (account, support.try_into().map_err(|_| ()))) .try_for_each(|(account, maybe_bounded_supports)| { outer_bounded_supports .try_push((account, maybe_bounded_supports?)) .map_err(|_| ()) - })?; + }) + .map_err(|_| crate::Error::BoundsExceeded)?; Ok(outer_bounded_supports.into()) } diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index be59450ce148b..379dccee2ce69 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -22,7 +22,7 @@ use crate::{ bounds::{DataProviderBounds, ElectionBounds, ElectionBoundsBuilder}, BoundedSupportsOf, Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, - NposSolver, PageIndex, TryIntoBoundedSupports, WeightInfo, Zero, + NposSolver, PageIndex, WeightInfo, Zero, }; use alloc::collections::btree_map::BTreeMap; use core::marker::PhantomData; @@ -147,9 +147,8 @@ impl OnChainExecution { // defensive: Since npos solver returns a result always bounded by `desired_targets`, this // is never expected to happen as long as npos solver does what is expected for it to do. - let supports: BoundedSupportsOf = to_supports(&staked) - .try_into_bounded_supports() - .map_err(|_| Error::TooManyWinners)?; + let supports: BoundedSupportsOf = + to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; Ok(supports) } @@ -321,7 +320,7 @@ mod tests { ), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }), ] - .try_into_bounded_supports() + .try_into() .unwrap(); assert_eq!( @@ -357,7 +356,7 @@ mod tests { ), (30, Support { total: 35, voters: vec![(2, 20), (3, 15)] }) ] - .try_into_bounded_supports() + .try_into() .unwrap() ); }) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 12a4181387851..79491ad5434c3 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -21,7 +21,7 @@ use crate::{self as pallet_staking, *}; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, onchain, BoundedSupports, BoundedSupportsOf, ElectionProvider, PageIndex, SequentialPhragmen, - Support, TryIntoBoundedSupports, VoteWeight, + Support, VoteWeight, }; use frame_support::{ assert_ok, derive_impl, ord_parameter_types, parameter_types, @@ -1023,5 +1023,5 @@ pub(crate) fn to_bounded_supports( <::ElectionProvider as ElectionProvider>::MaxWinnersPerPage, <::ElectionProvider as ElectionProvider>::MaxBackersPerWinner, > { - supports.try_into_bounded_supports().unwrap() + supports.try_into().unwrap() } diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 9a9d33aa8e20d..96af46e30f63f 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -127,6 +127,8 @@ pub enum Error { InvalidSupportEdge, /// The number of voters is bigger than the `MaxVoters` bound. TooManyVoters, + /// Some bounds were exceeded when converting election types. + BoundsExceeded, } /// A type which is used in the API of this crate as a numeric weight of a vote, most often the From 69b38e59d98769ed93a0da26570cc714fa66240e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 14 Nov 2024 16:37:22 +0100 Subject: [PATCH 61/95] Adds max backers per winner bounds check in the phragmen implementation (#6482) --- .../election-provider-multi-phase/src/mock.rs | 16 +++- .../src/unsigned.rs | 95 ++++++++++++++++++- .../election-provider-support/src/lib.rs | 20 +++- .../election-provider-support/src/onchain.rs | 5 +- .../primitives/npos-elections/src/lib.rs | 11 ++- .../primitives/npos-elections/src/mock.rs | 2 + .../primitives/npos-elections/src/phragmen.rs | 28 +++++- .../primitives/npos-elections/src/pjr.rs | 6 ++ .../primitives/npos-elections/src/tests.rs | 80 +++++++++++++--- 9 files changed, 232 insertions(+), 31 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 4add202ebc045..100abc01c2d9d 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -153,7 +153,8 @@ pub fn trim_helpers() -> TrimHelpers { let desired_targets = crate::DesiredTargets::::get().unwrap(); let ElectionResult::<_, SolutionAccuracyOf> { mut assignments, .. } = - seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None, None) + .unwrap(); // sort by decreasing order of stake assignments.sort_by_key(|assignment| { @@ -180,7 +181,8 @@ pub fn raw_solution() -> RawSolution> { let desired_targets = crate::DesiredTargets::::get().unwrap(); let ElectionResult::<_, SolutionAccuracyOf> { winners: _, assignments } = - seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None, None) + .unwrap(); // closures let cache = helpers::generate_voter_cache::(&voters); @@ -308,7 +310,8 @@ parameter_types! { pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; - type Solver = SequentialPhragmen, Balancing>; + type Solver = + SequentialPhragmen, MaxBackersPerWinner, Balancing>; type DataProvider = StakingMock; type WeightInfo = (); type MaxWinnersPerPage = MaxWinners; @@ -420,7 +423,8 @@ impl crate::Config for Runtime { type MaxWinners = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; type MinerConfig = Self; - type Solver = SequentialPhragmen, Balancing>; + type Solver = + SequentialPhragmen, MaxBackersPerWinner, Balancing>; type ElectionBounds = ElectionsBounds; } @@ -607,6 +611,10 @@ impl ExtBuilder { ::set(weight); self } + pub fn max_backers_per_winner(self, max: u32) -> Self { + ::set(max); + self + } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 90b12343aaeb2..aa2b8f265bfbf 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -430,7 +430,7 @@ pub trait MinerConfig { /// The maximum number of winners that can be elected in the single page supported by this /// pallet. type MaxWinners: Get; - /// The maximum number of backers per winner in the last solution. + /// The maximum number of backers per winner in a solution. type MaxBackersPerWinner: Get; /// Something that can compute the weight of a solution. /// @@ -1865,6 +1865,99 @@ mod tests { }) } + #[test] + fn mine_solution_always_respects_max_backers_per_winner() { + use crate::mock::MaxBackersPerWinner; + use frame_election_provider_support::BoundedSupport; + + let targets = vec![10, 20, 30, 40]; + let voters = vec![ + (1, 10, bounded_vec![10, 20, 30]), + (2, 10, bounded_vec![10, 20, 30]), + (3, 10, bounded_vec![10, 20, 30]), + (4, 10, bounded_vec![10, 20, 30]), + (5, 10, bounded_vec![10, 20, 40]), + ]; + let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() }; + let (round, desired_targets) = (1, 3); + + let expected_score_unbounded = + ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 }; + let expected_score_bounded = + ElectionScore { minimal_stake: 2, sum_stake: 10, sum_stake_squared: 44 }; + + // solution without max_backers_per_winner set will be higher than the score when bounds + // are set, confirming the trimming when using the same snapshot state. + assert!(expected_score_unbounded > expected_score_bounded); + + // election with unbounded max backers per winnner. + ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| { + assert_eq!(MaxBackersPerWinner::get(), u32::MAX); + + let solution = Miner::::mine_solution_with_snapshot::< + ::Solver, + >(voters.clone(), targets.clone(), desired_targets) + .unwrap() + .0; + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score: expected_score_unbounded, round }, + Default::default(), + desired_targets, + snapshot.clone(), + round, + Default::default(), + ) + .unwrap(); + + assert_eq!( + ready_solution.supports.into_iter().collect::>(), + vec![ + ( + 10, + BoundedSupport { total: 21, voters: bounded_vec![(1, 10), (4, 8), (5, 3)] } + ), + (20, BoundedSupport { total: 17, voters: bounded_vec![(2, 10), (5, 7)] }), + (30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }), + ] + ); + }); + + // election with max 1 backer per winnner. + ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| { + assert_eq!(MaxBackersPerWinner::get(), 1); + + let solution = Miner::::mine_solution_with_snapshot::< + ::Solver, + >(voters, targets, desired_targets) + .unwrap() + .0; + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score: expected_score_bounded, round }, + Default::default(), + desired_targets, + snapshot, + round, + Default::default(), + ) + .unwrap(); + + for (_, supports) in ready_solution.supports.iter() { + assert!((supports.voters.len() as u32) <= MaxBackersPerWinner::get()); + } + + assert_eq!( + ready_solution.supports.into_iter().collect::>(), + vec![ + (10, BoundedSupport { total: 6, voters: bounded_vec![(1, 6)] }), + (20, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), + (30, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), + ] + ); + }); + } + #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 49bd533cc8c3c..86bc085ca0a73 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -670,12 +670,16 @@ pub trait NposSolver { /// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the /// documentation of [`sp_npos_elections::seq_phragmen`] for more info. -pub struct SequentialPhragmen( - core::marker::PhantomData<(AccountId, Accuracy, Balancing)>, +pub struct SequentialPhragmen( + core::marker::PhantomData<(AccountId, Accuracy, MaxBackersPerWinner, Balancing)>, ); -impl>> - NposSolver for SequentialPhragmen +impl< + AccountId: IdentifierT, + Accuracy: PerThing128, + MaxBackersPerWinner: Get>, + Balancing: Get>, + > NposSolver for SequentialPhragmen { type AccountId = AccountId; type Accuracy = Accuracy; @@ -685,7 +689,13 @@ impl, voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error> { - sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) + sp_npos_elections::seq_phragmen( + winners, + targets, + voters, + MaxBackersPerWinner::get(), + Balancing::get(), + ) } fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 379dccee2ce69..5e4f9b54984c7 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -145,8 +145,9 @@ impl OnChainExecution { DispatchClass::Mandatory, ); - // defensive: Since npos solver returns a result always bounded by `desired_targets`, this - // is never expected to happen as long as npos solver does what is expected for it to do. + // defensive: Since npos solver returns a result always bounded by `desired_targets`, and + // ensures the maximum backers per winner, this is never expected to happen as long as npos + // solver does what is expected for it to do. let supports: BoundedSupportsOf = to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 96af46e30f63f..cfd8bc1d6656e 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -247,6 +247,9 @@ pub struct Candidate { elected: bool, /// The round index at which this candidate was elected. round: usize, + /// A list of included backers for this candidate. This can be used to control the bounds of + /// maximum backers per candidate. + bounded_backers: Vec, } impl Candidate { @@ -269,6 +272,8 @@ pub struct Edge { candidate: CandidatePtr, /// The weight (i.e. stake given to `who`) of this edge. weight: ExtendedBalance, + /// Skips this edge. + skip: bool, } #[cfg(test)] @@ -276,14 +281,14 @@ impl Edge { fn new(candidate: Candidate, weight: ExtendedBalance) -> Self { let who = candidate.who.clone(); let candidate = Rc::new(RefCell::new(candidate)); - Self { weight, who, candidate, load: Default::default() } + Self { weight, who, candidate, load: Default::default(), skip: false } } } #[cfg(feature = "std")] impl core::fmt::Debug for Edge { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Edge({:?}, weight = {:?})", self.who, self.weight) + write!(f, "Edge({:?}, weight = {:?}, skip = {})", self.who, self.weight, self.skip) } } @@ -556,6 +561,7 @@ pub fn setup_inputs( backed_stake: Default::default(), elected: Default::default(), round: Default::default(), + bounded_backers: Default::default(), } .to_ptr() }) @@ -580,6 +586,7 @@ pub fn setup_inputs( candidate: Rc::clone(&candidates[*idx]), load: Default::default(), weight: Default::default(), + skip: false, }); } // else {} would be wrong votes. We don't really care about it. } diff --git a/substrate/primitives/npos-elections/src/mock.rs b/substrate/primitives/npos-elections/src/mock.rs index 91757404145f3..a94803367fb40 100644 --- a/substrate/primitives/npos-elections/src/mock.rs +++ b/substrate/primitives/npos-elections/src/mock.rs @@ -311,6 +311,7 @@ pub(crate) fn run_and_compare( voters: Vec<(AccountId, Vec)>, stake_of: FS, to_elect: usize, + max_backers_candidate: Option, ) where Output: PerThing128, FS: Fn(&AccountId) -> VoteWeight, @@ -323,6 +324,7 @@ pub(crate) fn run_and_compare( .iter() .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), + max_backers_candidate, None, ) .unwrap(); diff --git a/substrate/primitives/npos-elections/src/phragmen.rs b/substrate/primitives/npos-elections/src/phragmen.rs index f331152e722a2..c6c2246244ae1 100644 --- a/substrate/primitives/npos-elections/src/phragmen.rs +++ b/substrate/primitives/npos-elections/src/phragmen.rs @@ -71,11 +71,13 @@ pub fn seq_phragmen( to_elect: usize, candidates: Vec, voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, + max_backers_per_candidate: Option, balancing: Option, ) -> Result, crate::Error> { let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, mut voters) = seq_phragmen_core::(to_elect, candidates, voters)?; + let (candidates, mut voters) = + seq_phragmen_core::(to_elect, candidates, voters, max_backers_per_candidate)?; if let Some(ref config) = balancing { // NOTE: might create zero-edges, but we will strip them again when we convert voter into @@ -118,6 +120,7 @@ pub fn seq_phragmen_core( to_elect: usize, candidates: Vec>, mut voters: Vec>, + max_backers_per_candidate: Option, ) -> Result<(Vec>, Vec>), crate::Error> { // we have already checked that we have more candidates than minimum_candidate_count. let to_elect = to_elect.min(candidates.len()); @@ -138,10 +141,21 @@ pub fn seq_phragmen_core( } } - // loop 2: increment score - for voter in &voters { - for edge in &voter.edges { + // loop 2: increment score and the included backers of a candidate. + for voter in &mut voters { + for edge in &mut voter.edges { let mut candidate = edge.candidate.borrow_mut(); + + if (candidate.bounded_backers.len() as u32) >= + max_backers_per_candidate.unwrap_or(Bounded::max_value()) && + !candidate.bounded_backers.contains(&voter.who) + { + // if the candidate has reached max backers and the voter is not part of the + // bounded backers, taint the edge with skip and continue. + edge.skip = true; + continue + } + if !candidate.elected && !candidate.approval_stake.is_zero() { let temp_n = multiply_by_rational_with_rounding( voter.load.n(), @@ -153,6 +167,7 @@ pub fn seq_phragmen_core( let temp_d = voter.load.d(); let temp = Rational128::from(temp_n, temp_d); candidate.score = candidate.score.lazy_saturating_add(temp); + candidate.bounded_backers.push(voter.who.clone()); } } } @@ -183,6 +198,11 @@ pub fn seq_phragmen_core( // update backing stake of candidates and voters for voter in &mut voters { for edge in &mut voter.edges { + if edge.skip { + // skip this edge as its candidate has already reached max backers. + continue + } + if edge.candidate.borrow().elected { // update internal state. edge.weight = multiply_by_rational_with_rounding( diff --git a/substrate/primitives/npos-elections/src/pjr.rs b/substrate/primitives/npos-elections/src/pjr.rs index 6e3775199a219..a807aa740754d 100644 --- a/substrate/primitives/npos-elections/src/pjr.rs +++ b/substrate/primitives/npos-elections/src/pjr.rs @@ -294,6 +294,8 @@ fn prepare_pjr_input( score: Default::default(), approval_stake: Default::default(), round: Default::default(), + // TODO: check if we need to pass the bounds here. + bounded_backers: supports.iter().map(|(a, _)| a).cloned().collect(), } .to_ptr() }) @@ -324,6 +326,7 @@ fn prepare_pjr_input( candidate: Rc::clone(&candidates[*idx]), weight, load: Default::default(), + skip: false, }); } } @@ -402,6 +405,7 @@ mod tests { score: Default::default(), approval_stake: Default::default(), round: Default::default(), + bounded_backers: Default::default(), } }) .collect::>(); @@ -412,6 +416,7 @@ mod tests { weight: c.backed_stake, candidate: c.to_ptr(), load: Default::default(), + skip: false, }) .collect::>(); voter.edges = edges; @@ -454,6 +459,7 @@ mod tests { approval_stake: Default::default(), backed_stake: Default::default(), round: Default::default(), + bounded_backers: Default::default(), } .to_ptr(); let score = pre_score(unelected, &vec![v1, v2, v3], 15); diff --git a/substrate/primitives/npos-elections/src/tests.rs b/substrate/primitives/npos-elections/src/tests.rs index 72ae9a0222be1..416168efcde1d 100644 --- a/substrate/primitives/npos-elections/src/tests.rs +++ b/substrate/primitives/npos-elections/src/tests.rs @@ -101,7 +101,7 @@ fn phragmen_core_poc_works() { let voters = vec![(10, 10, vec![1, 2]), (20, 20, vec![1, 3]), (30, 30, vec![2, 3])]; let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, voters) = seq_phragmen_core(2, candidates, voters).unwrap(); + let (candidates, voters) = seq_phragmen_core(2, candidates, voters, None).unwrap(); assert_eq!( voters @@ -141,7 +141,7 @@ fn balancing_core_works() { ]; let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, mut voters) = seq_phragmen_core(4, candidates, voters).unwrap(); + let (candidates, mut voters) = seq_phragmen_core(4, candidates, voters, None).unwrap(); let config = BalancingConfig { iterations: 4, tolerance: 0 }; let iters = balancing::balance::(&mut voters, &config); @@ -236,6 +236,7 @@ fn phragmen_poc_works() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -277,6 +278,50 @@ fn phragmen_poc_works() { ); } +#[test] +fn phragmen_poc_works_with_max_backers_per_candidate() { + let candidates = vec![1, 2, 3]; + let voters = vec![(10, vec![1, 2]), (20, vec![1, 2, 3]), (30, vec![1, 2, 3])]; + let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); + + let run_election = |max_backers: Option| { + let ElectionResult::<_, Perbill> { winners: _, assignments } = seq_phragmen( + 3, + candidates.clone(), + voters + .iter() + .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) + .collect::>(), + max_backers, + None, + ) + .unwrap(); + + let staked = assignment_ratio_to_staked(assignments, &stake_of); + to_support_map::(&staked) + }; + + let with_unbounded_backers = run_election(None); + + assert_eq!(with_unbounded_backers.get(&1).unwrap().voters.len(), 3); + assert_eq!(with_unbounded_backers.get(&2).unwrap().voters.len(), 3); + assert_eq!(with_unbounded_backers.get(&3).unwrap().voters.len(), 2); + + // max 2 backers per candidate. + let with_bounded_backers = run_election(Some(2)); + + assert_eq!(with_bounded_backers.get(&1).unwrap().voters.len(), 2); + assert_eq!(with_bounded_backers.get(&2).unwrap().voters.len(), 2); + assert_eq!(with_bounded_backers.get(&3).unwrap().voters.len(), 2); + + // max 1 backers per candidate. + let with_bounded_backers = run_election(Some(1)); + + assert_eq!(with_bounded_backers.get(&1).unwrap().voters.len(), 1); + assert_eq!(with_bounded_backers.get(&2).unwrap().voters.len(), 1); + assert_eq!(with_bounded_backers.get(&3).unwrap().voters.len(), 1); +} + #[test] fn phragmen_poc_works_with_balancing() { let candidates = vec![1, 2, 3]; @@ -291,6 +336,7 @@ fn phragmen_poc_works_with_balancing() { .iter() .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), + None, Some(config), ) .unwrap(); @@ -340,10 +386,10 @@ fn phragmen_poc_2_works() { let stake_of = create_stake_of(&[(10, 1000), (20, 1000), (30, 1000), (40, 1000), (2, 500), (4, 500)]); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates, voters, &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates, voters, &stake_of, 2, None); } #[test] @@ -352,10 +398,10 @@ fn phragmen_poc_3_works() { let voters = vec![(2, vec![10, 20, 30]), (4, vec![10, 20, 40])]; let stake_of = create_stake_of(&[(10, 1000), (20, 1000), (30, 1000), (2, 50), (4, 1000)]); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); - run_and_compare::(candidates, voters, &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); + run_and_compare::(candidates, voters, &stake_of, 2, None); } #[test] @@ -379,6 +425,7 @@ fn phragmen_accuracy_on_large_scale_only_candidates() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -410,6 +457,7 @@ fn phragmen_accuracy_on_large_scale_voters_and_candidates() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -442,6 +490,7 @@ fn phragmen_accuracy_on_small_scale_self_vote() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -472,6 +521,7 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -508,6 +558,7 @@ fn phragmen_large_scale_test() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -535,6 +586,7 @@ fn phragmen_large_scale_test_2() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -587,7 +639,7 @@ fn phragmen_linear_equalize() { (130, 1000), ]); - run_and_compare::(candidates, voters, &stake_of, 2); + run_and_compare::(candidates, voters, &stake_of, 2, None); } #[test] @@ -604,6 +656,7 @@ fn elect_has_no_entry_barrier() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -625,6 +678,7 @@ fn phragmen_self_votes_should_be_kept() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, + None, ) .unwrap(); @@ -664,7 +718,7 @@ fn duplicate_target_is_ignored() { let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![2, 3]), (30, 50, vec![1, 1, 2])]; let ElectionResult::<_, Perbill> { winners, assignments } = - seq_phragmen(2, candidates, voters, None).unwrap(); + seq_phragmen(2, candidates, voters, None, None).unwrap(); assert_eq!(winners, vec![(2, 140), (3, 110)]); assert_eq!( @@ -682,7 +736,7 @@ fn duplicate_target_is_ignored_when_winner() { let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![1, 2])]; let ElectionResult::<_, Perbill> { winners, assignments } = - seq_phragmen(2, candidates, voters, None).unwrap(); + seq_phragmen(2, candidates, voters, None, None).unwrap(); assert_eq!(winners, vec![(1, 100), (2, 100)]); assert_eq!( From e43e8859d140ad937e134981bb259d627889baf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 3 Dec 2024 23:04:56 +0100 Subject: [PATCH 62/95] addresses PR comments --- .../frame/election-provider-multi-phase/src/lib.rs | 1 + substrate/frame/staking/src/pallet/impls.rs | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 8676be438300f..6733bd15b357b 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -679,6 +679,7 @@ pub mod pallet { /// Maximum number of winners that an election supports. /// /// Note: This must always be greater or equal to `T::DataProvider::desired_targets()`. + #[pallet::constant] type MaxWinners: Get; /// Maximum number of voters that can support a winner in an election solution. diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 785c688453dd4..fb30e3f497d1e 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -707,18 +707,17 @@ impl Pallet { }, _ => {}, } - // election failed, clear election prep metadata. Self::clear_election_metadata(); - Self::deposit_event(Event::StakingElectionFailed); - return None - } - Self::deposit_event(Event::StakersElected); - Self::trigger_new_era(start_session_index); + None + } else { + Self::deposit_event(Event::StakersElected); + Self::trigger_new_era(start_session_index); - Some(validators) + Some(validators) + } } /// Paginated elect. From 676db53d98580947e3f78f9d955669988d36ca80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 3 Dec 2024 23:24:25 +0100 Subject: [PATCH 63/95] Revert "Adds max backers per winner bounds check in the phragmen implementation (#6482)" This reverts commit 69b38e59d98769ed93a0da26570cc714fa66240e. --- .../election-provider-multi-phase/src/mock.rs | 16 +--- .../src/unsigned.rs | 95 +------------------ .../election-provider-support/src/lib.rs | 20 +--- .../election-provider-support/src/onchain.rs | 5 +- .../primitives/npos-elections/src/lib.rs | 11 +-- .../primitives/npos-elections/src/mock.rs | 2 - .../primitives/npos-elections/src/phragmen.rs | 28 +----- .../primitives/npos-elections/src/pjr.rs | 6 -- .../primitives/npos-elections/src/tests.rs | 80 +++------------- 9 files changed, 31 insertions(+), 232 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 100abc01c2d9d..4add202ebc045 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -153,8 +153,7 @@ pub fn trim_helpers() -> TrimHelpers { let desired_targets = crate::DesiredTargets::::get().unwrap(); let ElectionResult::<_, SolutionAccuracyOf> { mut assignments, .. } = - seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None, None) - .unwrap(); + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // sort by decreasing order of stake assignments.sort_by_key(|assignment| { @@ -181,8 +180,7 @@ pub fn raw_solution() -> RawSolution> { let desired_targets = crate::DesiredTargets::::get().unwrap(); let ElectionResult::<_, SolutionAccuracyOf> { winners: _, assignments } = - seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None, None) - .unwrap(); + seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // closures let cache = helpers::generate_voter_cache::(&voters); @@ -310,8 +308,7 @@ parameter_types! { pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { type System = Runtime; - type Solver = - SequentialPhragmen, MaxBackersPerWinner, Balancing>; + type Solver = SequentialPhragmen, Balancing>; type DataProvider = StakingMock; type WeightInfo = (); type MaxWinnersPerPage = MaxWinners; @@ -423,8 +420,7 @@ impl crate::Config for Runtime { type MaxWinners = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; type MinerConfig = Self; - type Solver = - SequentialPhragmen, MaxBackersPerWinner, Balancing>; + type Solver = SequentialPhragmen, Balancing>; type ElectionBounds = ElectionsBounds; } @@ -611,10 +607,6 @@ impl ExtBuilder { ::set(weight); self } - pub fn max_backers_per_winner(self, max: u32) -> Self { - ::set(max); - self - } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index aa2b8f265bfbf..90b12343aaeb2 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -430,7 +430,7 @@ pub trait MinerConfig { /// The maximum number of winners that can be elected in the single page supported by this /// pallet. type MaxWinners: Get; - /// The maximum number of backers per winner in a solution. + /// The maximum number of backers per winner in the last solution. type MaxBackersPerWinner: Get; /// Something that can compute the weight of a solution. /// @@ -1865,99 +1865,6 @@ mod tests { }) } - #[test] - fn mine_solution_always_respects_max_backers_per_winner() { - use crate::mock::MaxBackersPerWinner; - use frame_election_provider_support::BoundedSupport; - - let targets = vec![10, 20, 30, 40]; - let voters = vec![ - (1, 10, bounded_vec![10, 20, 30]), - (2, 10, bounded_vec![10, 20, 30]), - (3, 10, bounded_vec![10, 20, 30]), - (4, 10, bounded_vec![10, 20, 30]), - (5, 10, bounded_vec![10, 20, 40]), - ]; - let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() }; - let (round, desired_targets) = (1, 3); - - let expected_score_unbounded = - ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 }; - let expected_score_bounded = - ElectionScore { minimal_stake: 2, sum_stake: 10, sum_stake_squared: 44 }; - - // solution without max_backers_per_winner set will be higher than the score when bounds - // are set, confirming the trimming when using the same snapshot state. - assert!(expected_score_unbounded > expected_score_bounded); - - // election with unbounded max backers per winnner. - ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| { - assert_eq!(MaxBackersPerWinner::get(), u32::MAX); - - let solution = Miner::::mine_solution_with_snapshot::< - ::Solver, - >(voters.clone(), targets.clone(), desired_targets) - .unwrap() - .0; - - let ready_solution = Miner::::feasibility_check( - RawSolution { solution, score: expected_score_unbounded, round }, - Default::default(), - desired_targets, - snapshot.clone(), - round, - Default::default(), - ) - .unwrap(); - - assert_eq!( - ready_solution.supports.into_iter().collect::>(), - vec![ - ( - 10, - BoundedSupport { total: 21, voters: bounded_vec![(1, 10), (4, 8), (5, 3)] } - ), - (20, BoundedSupport { total: 17, voters: bounded_vec![(2, 10), (5, 7)] }), - (30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }), - ] - ); - }); - - // election with max 1 backer per winnner. - ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| { - assert_eq!(MaxBackersPerWinner::get(), 1); - - let solution = Miner::::mine_solution_with_snapshot::< - ::Solver, - >(voters, targets, desired_targets) - .unwrap() - .0; - - let ready_solution = Miner::::feasibility_check( - RawSolution { solution, score: expected_score_bounded, round }, - Default::default(), - desired_targets, - snapshot, - round, - Default::default(), - ) - .unwrap(); - - for (_, supports) in ready_solution.supports.iter() { - assert!((supports.voters.len() as u32) <= MaxBackersPerWinner::get()); - } - - assert_eq!( - ready_solution.supports.into_iter().collect::>(), - vec![ - (10, BoundedSupport { total: 6, voters: bounded_vec![(1, 6)] }), - (20, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), - (30, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), - ] - ); - }); - } - #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 86bc085ca0a73..49bd533cc8c3c 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -670,16 +670,12 @@ pub trait NposSolver { /// A wrapper for [`sp_npos_elections::seq_phragmen`] that implements [`NposSolver`]. See the /// documentation of [`sp_npos_elections::seq_phragmen`] for more info. -pub struct SequentialPhragmen( - core::marker::PhantomData<(AccountId, Accuracy, MaxBackersPerWinner, Balancing)>, +pub struct SequentialPhragmen( + core::marker::PhantomData<(AccountId, Accuracy, Balancing)>, ); -impl< - AccountId: IdentifierT, - Accuracy: PerThing128, - MaxBackersPerWinner: Get>, - Balancing: Get>, - > NposSolver for SequentialPhragmen +impl>> + NposSolver for SequentialPhragmen { type AccountId = AccountId; type Accuracy = Accuracy; @@ -689,13 +685,7 @@ impl< targets: Vec, voters: Vec<(Self::AccountId, VoteWeight, impl IntoIterator)>, ) -> Result, Self::Error> { - sp_npos_elections::seq_phragmen( - winners, - targets, - voters, - MaxBackersPerWinner::get(), - Balancing::get(), - ) + sp_npos_elections::seq_phragmen(winners, targets, voters, Balancing::get()) } fn weight(voters: u32, targets: u32, vote_degree: u32) -> Weight { diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 5e4f9b54984c7..379dccee2ce69 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -145,9 +145,8 @@ impl OnChainExecution { DispatchClass::Mandatory, ); - // defensive: Since npos solver returns a result always bounded by `desired_targets`, and - // ensures the maximum backers per winner, this is never expected to happen as long as npos - // solver does what is expected for it to do. + // defensive: Since npos solver returns a result always bounded by `desired_targets`, this + // is never expected to happen as long as npos solver does what is expected for it to do. let supports: BoundedSupportsOf = to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index cfd8bc1d6656e..96af46e30f63f 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -247,9 +247,6 @@ pub struct Candidate { elected: bool, /// The round index at which this candidate was elected. round: usize, - /// A list of included backers for this candidate. This can be used to control the bounds of - /// maximum backers per candidate. - bounded_backers: Vec, } impl Candidate { @@ -272,8 +269,6 @@ pub struct Edge { candidate: CandidatePtr, /// The weight (i.e. stake given to `who`) of this edge. weight: ExtendedBalance, - /// Skips this edge. - skip: bool, } #[cfg(test)] @@ -281,14 +276,14 @@ impl Edge { fn new(candidate: Candidate, weight: ExtendedBalance) -> Self { let who = candidate.who.clone(); let candidate = Rc::new(RefCell::new(candidate)); - Self { weight, who, candidate, load: Default::default(), skip: false } + Self { weight, who, candidate, load: Default::default() } } } #[cfg(feature = "std")] impl core::fmt::Debug for Edge { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Edge({:?}, weight = {:?}, skip = {})", self.who, self.weight, self.skip) + write!(f, "Edge({:?}, weight = {:?})", self.who, self.weight) } } @@ -561,7 +556,6 @@ pub fn setup_inputs( backed_stake: Default::default(), elected: Default::default(), round: Default::default(), - bounded_backers: Default::default(), } .to_ptr() }) @@ -586,7 +580,6 @@ pub fn setup_inputs( candidate: Rc::clone(&candidates[*idx]), load: Default::default(), weight: Default::default(), - skip: false, }); } // else {} would be wrong votes. We don't really care about it. } diff --git a/substrate/primitives/npos-elections/src/mock.rs b/substrate/primitives/npos-elections/src/mock.rs index a94803367fb40..91757404145f3 100644 --- a/substrate/primitives/npos-elections/src/mock.rs +++ b/substrate/primitives/npos-elections/src/mock.rs @@ -311,7 +311,6 @@ pub(crate) fn run_and_compare( voters: Vec<(AccountId, Vec)>, stake_of: FS, to_elect: usize, - max_backers_candidate: Option, ) where Output: PerThing128, FS: Fn(&AccountId) -> VoteWeight, @@ -324,7 +323,6 @@ pub(crate) fn run_and_compare( .iter() .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), - max_backers_candidate, None, ) .unwrap(); diff --git a/substrate/primitives/npos-elections/src/phragmen.rs b/substrate/primitives/npos-elections/src/phragmen.rs index c6c2246244ae1..f331152e722a2 100644 --- a/substrate/primitives/npos-elections/src/phragmen.rs +++ b/substrate/primitives/npos-elections/src/phragmen.rs @@ -71,13 +71,11 @@ pub fn seq_phragmen( to_elect: usize, candidates: Vec, voters: Vec<(AccountId, VoteWeight, impl IntoIterator)>, - max_backers_per_candidate: Option, balancing: Option, ) -> Result, crate::Error> { let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, mut voters) = - seq_phragmen_core::(to_elect, candidates, voters, max_backers_per_candidate)?; + let (candidates, mut voters) = seq_phragmen_core::(to_elect, candidates, voters)?; if let Some(ref config) = balancing { // NOTE: might create zero-edges, but we will strip them again when we convert voter into @@ -120,7 +118,6 @@ pub fn seq_phragmen_core( to_elect: usize, candidates: Vec>, mut voters: Vec>, - max_backers_per_candidate: Option, ) -> Result<(Vec>, Vec>), crate::Error> { // we have already checked that we have more candidates than minimum_candidate_count. let to_elect = to_elect.min(candidates.len()); @@ -141,21 +138,10 @@ pub fn seq_phragmen_core( } } - // loop 2: increment score and the included backers of a candidate. - for voter in &mut voters { - for edge in &mut voter.edges { + // loop 2: increment score + for voter in &voters { + for edge in &voter.edges { let mut candidate = edge.candidate.borrow_mut(); - - if (candidate.bounded_backers.len() as u32) >= - max_backers_per_candidate.unwrap_or(Bounded::max_value()) && - !candidate.bounded_backers.contains(&voter.who) - { - // if the candidate has reached max backers and the voter is not part of the - // bounded backers, taint the edge with skip and continue. - edge.skip = true; - continue - } - if !candidate.elected && !candidate.approval_stake.is_zero() { let temp_n = multiply_by_rational_with_rounding( voter.load.n(), @@ -167,7 +153,6 @@ pub fn seq_phragmen_core( let temp_d = voter.load.d(); let temp = Rational128::from(temp_n, temp_d); candidate.score = candidate.score.lazy_saturating_add(temp); - candidate.bounded_backers.push(voter.who.clone()); } } } @@ -198,11 +183,6 @@ pub fn seq_phragmen_core( // update backing stake of candidates and voters for voter in &mut voters { for edge in &mut voter.edges { - if edge.skip { - // skip this edge as its candidate has already reached max backers. - continue - } - if edge.candidate.borrow().elected { // update internal state. edge.weight = multiply_by_rational_with_rounding( diff --git a/substrate/primitives/npos-elections/src/pjr.rs b/substrate/primitives/npos-elections/src/pjr.rs index a807aa740754d..6e3775199a219 100644 --- a/substrate/primitives/npos-elections/src/pjr.rs +++ b/substrate/primitives/npos-elections/src/pjr.rs @@ -294,8 +294,6 @@ fn prepare_pjr_input( score: Default::default(), approval_stake: Default::default(), round: Default::default(), - // TODO: check if we need to pass the bounds here. - bounded_backers: supports.iter().map(|(a, _)| a).cloned().collect(), } .to_ptr() }) @@ -326,7 +324,6 @@ fn prepare_pjr_input( candidate: Rc::clone(&candidates[*idx]), weight, load: Default::default(), - skip: false, }); } } @@ -405,7 +402,6 @@ mod tests { score: Default::default(), approval_stake: Default::default(), round: Default::default(), - bounded_backers: Default::default(), } }) .collect::>(); @@ -416,7 +412,6 @@ mod tests { weight: c.backed_stake, candidate: c.to_ptr(), load: Default::default(), - skip: false, }) .collect::>(); voter.edges = edges; @@ -459,7 +454,6 @@ mod tests { approval_stake: Default::default(), backed_stake: Default::default(), round: Default::default(), - bounded_backers: Default::default(), } .to_ptr(); let score = pre_score(unelected, &vec![v1, v2, v3], 15); diff --git a/substrate/primitives/npos-elections/src/tests.rs b/substrate/primitives/npos-elections/src/tests.rs index 416168efcde1d..72ae9a0222be1 100644 --- a/substrate/primitives/npos-elections/src/tests.rs +++ b/substrate/primitives/npos-elections/src/tests.rs @@ -101,7 +101,7 @@ fn phragmen_core_poc_works() { let voters = vec![(10, 10, vec![1, 2]), (20, 20, vec![1, 3]), (30, 30, vec![2, 3])]; let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, voters) = seq_phragmen_core(2, candidates, voters, None).unwrap(); + let (candidates, voters) = seq_phragmen_core(2, candidates, voters).unwrap(); assert_eq!( voters @@ -141,7 +141,7 @@ fn balancing_core_works() { ]; let (candidates, voters) = setup_inputs(candidates, voters); - let (candidates, mut voters) = seq_phragmen_core(4, candidates, voters, None).unwrap(); + let (candidates, mut voters) = seq_phragmen_core(4, candidates, voters).unwrap(); let config = BalancingConfig { iterations: 4, tolerance: 0 }; let iters = balancing::balance::(&mut voters, &config); @@ -236,7 +236,6 @@ fn phragmen_poc_works() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -278,50 +277,6 @@ fn phragmen_poc_works() { ); } -#[test] -fn phragmen_poc_works_with_max_backers_per_candidate() { - let candidates = vec![1, 2, 3]; - let voters = vec![(10, vec![1, 2]), (20, vec![1, 2, 3]), (30, vec![1, 2, 3])]; - let stake_of = create_stake_of(&[(10, 10), (20, 20), (30, 30)]); - - let run_election = |max_backers: Option| { - let ElectionResult::<_, Perbill> { winners: _, assignments } = seq_phragmen( - 3, - candidates.clone(), - voters - .iter() - .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) - .collect::>(), - max_backers, - None, - ) - .unwrap(); - - let staked = assignment_ratio_to_staked(assignments, &stake_of); - to_support_map::(&staked) - }; - - let with_unbounded_backers = run_election(None); - - assert_eq!(with_unbounded_backers.get(&1).unwrap().voters.len(), 3); - assert_eq!(with_unbounded_backers.get(&2).unwrap().voters.len(), 3); - assert_eq!(with_unbounded_backers.get(&3).unwrap().voters.len(), 2); - - // max 2 backers per candidate. - let with_bounded_backers = run_election(Some(2)); - - assert_eq!(with_bounded_backers.get(&1).unwrap().voters.len(), 2); - assert_eq!(with_bounded_backers.get(&2).unwrap().voters.len(), 2); - assert_eq!(with_bounded_backers.get(&3).unwrap().voters.len(), 2); - - // max 1 backers per candidate. - let with_bounded_backers = run_election(Some(1)); - - assert_eq!(with_bounded_backers.get(&1).unwrap().voters.len(), 1); - assert_eq!(with_bounded_backers.get(&2).unwrap().voters.len(), 1); - assert_eq!(with_bounded_backers.get(&3).unwrap().voters.len(), 1); -} - #[test] fn phragmen_poc_works_with_balancing() { let candidates = vec![1, 2, 3]; @@ -336,7 +291,6 @@ fn phragmen_poc_works_with_balancing() { .iter() .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), - None, Some(config), ) .unwrap(); @@ -386,10 +340,10 @@ fn phragmen_poc_2_works() { let stake_of = create_stake_of(&[(10, 1000), (20, 1000), (30, 1000), (40, 1000), (2, 500), (4, 500)]); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates, voters, &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates, voters, &stake_of, 2); } #[test] @@ -398,10 +352,10 @@ fn phragmen_poc_3_works() { let voters = vec![(2, vec![10, 20, 30]), (4, vec![10, 20, 40])]; let stake_of = create_stake_of(&[(10, 1000), (20, 1000), (30, 1000), (2, 50), (4, 1000)]); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2, None); - run_and_compare::(candidates, voters, &stake_of, 2, None); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates.clone(), voters.clone(), &stake_of, 2); + run_and_compare::(candidates, voters, &stake_of, 2); } #[test] @@ -425,7 +379,6 @@ fn phragmen_accuracy_on_large_scale_only_candidates() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -457,7 +410,6 @@ fn phragmen_accuracy_on_large_scale_voters_and_candidates() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -490,7 +442,6 @@ fn phragmen_accuracy_on_small_scale_self_vote() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -521,7 +472,6 @@ fn phragmen_accuracy_on_small_scale_no_self_vote() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -558,7 +508,6 @@ fn phragmen_large_scale_test() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -586,7 +535,6 @@ fn phragmen_large_scale_test_2() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -639,7 +587,7 @@ fn phragmen_linear_equalize() { (130, 1000), ]); - run_and_compare::(candidates, voters, &stake_of, 2, None); + run_and_compare::(candidates, voters, &stake_of, 2); } #[test] @@ -656,7 +604,6 @@ fn elect_has_no_entry_barrier() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -678,7 +625,6 @@ fn phragmen_self_votes_should_be_kept() { .map(|(ref v, ref vs)| (*v, stake_of(v), vs.clone())) .collect::>(), None, - None, ) .unwrap(); @@ -718,7 +664,7 @@ fn duplicate_target_is_ignored() { let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![2, 3]), (30, 50, vec![1, 1, 2])]; let ElectionResult::<_, Perbill> { winners, assignments } = - seq_phragmen(2, candidates, voters, None, None).unwrap(); + seq_phragmen(2, candidates, voters, None).unwrap(); assert_eq!(winners, vec![(2, 140), (3, 110)]); assert_eq!( @@ -736,7 +682,7 @@ fn duplicate_target_is_ignored_when_winner() { let voters = vec![(10, 100, vec![1, 1, 2, 3]), (20, 100, vec![1, 2])]; let ElectionResult::<_, Perbill> { winners, assignments } = - seq_phragmen(2, candidates, voters, None, None).unwrap(); + seq_phragmen(2, candidates, voters, None).unwrap(); assert_eq!(winners, vec![(1, 100), (2, 100)]); assert_eq!( From fe8b9ae9604607effb6b4536d53406429ecbe716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 3 Dec 2024 23:26:36 +0100 Subject: [PATCH 64/95] adds max backers per winner trimming test --- .../election-provider-multi-phase/src/mock.rs | 4 + .../src/unsigned.rs | 93 +++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 4add202ebc045..20fe4016375c8 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -607,6 +607,10 @@ impl ExtBuilder { ::set(weight); self } + pub fn max_backers_per_winner(self, max: u32) -> Self { + MaxBackersPerWinner::set(max); + self + } pub fn build(self) -> sp_io::TestExternalities { sp_tracing::try_init_simple(); let mut storage = diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 90b12343aaeb2..2e0767b28d950 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -1865,6 +1865,99 @@ mod tests { }) } + #[test] + fn mine_solution_always_respects_max_backers_per_winner() { + use crate::mock::MaxBackersPerWinner; + use frame_election_provider_support::BoundedSupport; + + let targets = vec![10, 20, 30, 40]; + let voters = vec![ + (1, 10, bounded_vec![10, 20, 30]), + (2, 10, bounded_vec![10, 20, 30]), + (3, 10, bounded_vec![10, 20, 30]), + (4, 10, bounded_vec![10, 20, 30]), + (5, 10, bounded_vec![10, 20, 40]), + ]; + let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() }; + let (round, desired_targets) = (1, 3); + + let expected_score_unbounded = + ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 }; + let expected_score_bounded = + ElectionScore { minimal_stake: 2, sum_stake: 10, sum_stake_squared: 44 }; + + // solution without max_backers_per_winner set will be higher than the score when bounds + // are set, confirming the trimming when using the same snapshot state. + assert!(expected_score_unbounded > expected_score_bounded); + + // election with unbounded max backers per winnner. + ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| { + assert_eq!(MaxBackersPerWinner::get(), u32::MAX); + + let solution = Miner::::mine_solution_with_snapshot::< + ::Solver, + >(voters.clone(), targets.clone(), desired_targets) + .unwrap() + .0; + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score: expected_score_unbounded, round }, + Default::default(), + desired_targets, + snapshot.clone(), + round, + Default::default(), + ) + .unwrap(); + + assert_eq!( + ready_solution.supports.into_iter().collect::>(), + vec![ + ( + 10, + BoundedSupport { total: 21, voters: bounded_vec![(1, 10), (4, 8), (5, 3)] } + ), + (20, BoundedSupport { total: 17, voters: bounded_vec![(2, 10), (5, 7)] }), + (30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }), + ] + ); + }); + + // election with max 1 backer per winnner. + ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| { + assert_eq!(MaxBackersPerWinner::get(), 1); + + let solution = Miner::::mine_solution_with_snapshot::< + ::Solver, + >(voters, targets, desired_targets) + .unwrap() + .0; + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score: expected_score_bounded, round }, + Default::default(), + desired_targets, + snapshot, + round, + Default::default(), + ) + .unwrap(); + + for (_, supports) in ready_solution.supports.iter() { + assert!((supports.voters.len() as u32) <= MaxBackersPerWinner::get()); + } + + assert_eq!( + ready_solution.supports.into_iter().collect::>(), + vec![ + (10, BoundedSupport { total: 6, voters: bounded_vec![(1, 6)] }), + (20, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), + (30, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), + ] + ); + }); + } + #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { From 84eea26a8edafcbbb22d7d0abdac6aa33ca2a875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 5 Dec 2024 13:13:50 +0100 Subject: [PATCH 65/95] Ensures max backers per winner bounds are met in Staking miner (#6771) Ensures max backers per winner bounds are met in Staking miner. This PR replaces https://github.com/paritytech/polkadot-sdk/pull/6482 (already reverted in the base branch) and moves the trimming logic when max backer per winner exceed configured bounds to the miner. --- .../src/unsigned.rs | 208 ++++++++++++++++-- 1 file changed, 189 insertions(+), 19 deletions(-) diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 2e0767b28d950..6c2d55cac3dea 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -112,16 +112,20 @@ impl From for MinerError { } } -/// Reports the trimming result of a mined solution +/// Reports the trimming result of a mined solution. #[derive(Debug, Clone)] pub struct TrimmingStatus { + /// Number of voters trimmed due to the solution weight limits. weight: usize, + /// Number of voters trimmed due to the solution length limits. length: usize, + /// Number of edges (voter -> target) trimmed due to the max backers per winner bound. + edges: usize, } impl TrimmingStatus { pub fn is_trimmed(&self) -> bool { - self.weight > 0 || self.length > 0 + self.weight > 0 || self.length > 0 || self.edges > 0 } pub fn trimmed_weight(&self) -> usize { @@ -131,6 +135,10 @@ impl TrimmingStatus { pub fn trimmed_length(&self) -> usize { self.length } + + pub fn trimmed_edges(&self) -> usize { + self.edges + } } /// Save a given call into OCW storage. @@ -493,7 +501,11 @@ impl Miner { let ElectionResult { assignments, winners: _ } = election_result; - // Reduce (requires round-trip to staked form) + // keeps track of how many edges were trimmed out. + let mut edges_trimmed = 0; + + // Reduce (requires round-trip to staked form) and ensures the max backer per winner bound + // requirements are met. let sorted_assignments = { // convert to staked and reduce. let mut staked = assignment_ratio_to_staked_normalized(assignments, &stake_of)?; @@ -520,6 +532,57 @@ impl Miner { }, ); + // ensures that the max backers per winner bounds are respected given the supports + // generated from the assignments. We achieve that by removing edges (voter -> + // target) in the assignments with lower stake until the total number of backers per + // winner fits within the expected bounded supports. This should be performed *after* + // applying reduce over the assignments to avoid over-trimming. + // + // a potential trimming does not affect the desired targets of the solution as the + // targets have *too many* edges by definition if trimmed. + let max_backers_per_winner = T::MaxBackersPerWinner::get().saturated_into::(); + + let _ = sp_npos_elections::to_supports(&staked) + .iter_mut() + .filter(|(_, support)| support.voters.len() > max_backers_per_winner) + .for_each(|(target, ref mut support)| { + // first sort by support stake, lowest at the tail. + support.voters.sort_by(|a, b| b.1.cmp(&a.1)); + + // filter out lowest stake edge in this support. + // optimization note: collects edge voters to remove from assignments into a + // btree set to optimize the search in the next loop. + let filtered: std::collections::BTreeSet<_> = support + .voters + .split_off(max_backers_per_winner) + .into_iter() + .map(|(who, stake)| { + // update total support of the target where the edge will be removed. + support.total -= stake; + who + }) + .collect(); + + // remove lowest stake edges calculated above from assignments. + staked.iter_mut().for_each(|assignment| { + if filtered.contains(&assignment.who) { + assignment.distribution.retain(|(t, _)| t != target); + } + }); + + edges_trimmed += filtered.len(); + }); + + debug_assert!({ + // at this point we expect the supports generated from the assignments to fit within + // the expected bounded supports. + let expected_ok: Result< + crate::BoundedSupports<_, T::MaxWinners, T::MaxBackersPerWinner>, + _, + > = sp_npos_elections::to_supports(&staked).try_into(); + expected_ok.is_ok() + }); + // convert back. assignment_staked_to_ratio_normalized(staked)? }; @@ -552,7 +615,8 @@ impl Miner { // re-calc score. let score = solution.clone().score(stake_of, voter_at, target_at)?; - let is_trimmed = TrimmingStatus { weight: weight_trimmed, length: length_trimmed }; + let is_trimmed = + TrimmingStatus { weight: weight_trimmed, length: length_trimmed, edges: edges_trimmed }; Ok((solution, score, size, is_trimmed)) } @@ -817,9 +881,12 @@ impl Miner { // Finally, check that the claimed score was indeed correct. let known_score = supports.evaluate(); + ensure!(known_score == score, FeasibilityError::InvalidScore); - // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. + // Size of winners in miner solution is equal to `desired_targets` <= `MaxWinners`. In + // addition, the miner should have ensured that the MaxBackerPerWinner bound in respected, + // thus this conversion should not fail. let supports = supports .try_into() .defensive_map_err(|_| FeasibilityError::BoundedConversionFailed)?; @@ -1884,7 +1951,7 @@ mod tests { let expected_score_unbounded = ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 }; let expected_score_bounded = - ElectionScore { minimal_stake: 2, sum_stake: 10, sum_stake_squared: 44 }; + ElectionScore { minimal_stake: 10, sum_stake: 30, sum_stake_squared: 300 }; // solution without max_backers_per_winner set will be higher than the score when bounds // are set, confirming the trimming when using the same snapshot state. @@ -1894,11 +1961,13 @@ mod tests { ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| { assert_eq!(MaxBackersPerWinner::get(), u32::MAX); - let solution = Miner::::mine_solution_with_snapshot::< - ::Solver, - >(voters.clone(), targets.clone(), desired_targets) - .unwrap() - .0; + let (solution, _, _, trimming_status) = + Miner::::mine_solution_with_snapshot::<::Solver>( + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); let ready_solution = Miner::::feasibility_check( RawSolution { solution, score: expected_score_unbounded, round }, @@ -1921,17 +1990,22 @@ mod tests { (30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }), ] ); + + // no trimmed edges. + assert_eq!(trimming_status.trimmed_edges(), 0); }); // election with max 1 backer per winnner. ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| { assert_eq!(MaxBackersPerWinner::get(), 1); - let solution = Miner::::mine_solution_with_snapshot::< - ::Solver, - >(voters, targets, desired_targets) - .unwrap() - .0; + let (solution, _, _, trimming_status) = + Miner::::mine_solution_with_snapshot::<::Solver>( + voters, + targets, + desired_targets, + ) + .unwrap(); let ready_solution = Miner::::feasibility_check( RawSolution { solution, score: expected_score_bounded, round }, @@ -1950,14 +2024,110 @@ mod tests { assert_eq!( ready_solution.supports.into_iter().collect::>(), vec![ - (10, BoundedSupport { total: 6, voters: bounded_vec![(1, 6)] }), - (20, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), - (30, BoundedSupport { total: 2, voters: bounded_vec![(1, 2)] }), + (10, BoundedSupport { total: 10, voters: bounded_vec![(1, 10)] }), + (20, BoundedSupport { total: 10, voters: bounded_vec![(2, 10)] }), + (30, BoundedSupport { total: 10, voters: bounded_vec![(3, 10)] }), ] ); + + // four trimmed edges. + assert_eq!(trimming_status.trimmed_edges(), 4); }); } + #[test] + fn max_backers_edges_trims_lowest_stake() { + use crate::mock::MaxBackersPerWinner; + + ExtBuilder::default().build_and_execute(|| { + let targets = vec![10, 20, 30, 40]; + + let voters = vec![ + (1, 100, bounded_vec![10, 20]), + (2, 200, bounded_vec![10, 20, 30]), + (3, 300, bounded_vec![10, 30]), + (4, 400, bounded_vec![10, 30]), + (5, 500, bounded_vec![10, 20, 30]), + (6, 600, bounded_vec![10, 20, 30, 40]), + ]; + let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() }; + let (round, desired_targets) = (1, 4); + + let max_backers_bound = u32::MAX; + let trim_backers_bound = 2; + + // election with unbounded max backers per winnner. + MaxBackersPerWinner::set(max_backers_bound); + let (solution, score, _, trimming_status) = + Miner::::mine_solution_with_snapshot::<::Solver>( + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); + + assert_eq!(trimming_status.trimmed_edges(), 0); + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score, round }, + Default::default(), + desired_targets, + snapshot.clone(), + round, + Default::default(), + ) + .unwrap(); + + let full_supports = ready_solution.supports.into_iter().collect::>(); + + // gather the expected trimmed supports (lowest stake from supports with more backers + // than expected when MaxBackersPerWinner is 2) from the full, unbounded supports. + let expected_trimmed_supports = full_supports + .into_iter() + .filter(|(_, s)| s.voters.len() as u32 > trim_backers_bound) + .map(|(t, s)| (t, s.voters.into_iter().min_by(|a, b| a.1.cmp(&b.1)).unwrap())) + .collect::>(); + + // election with bounded 2 max backers per winnner. + MaxBackersPerWinner::set(trim_backers_bound); + let (solution, score, _, trimming_status) = + Miner::::mine_solution_with_snapshot::<::Solver>( + voters.clone(), + targets.clone(), + desired_targets, + ) + .unwrap(); + + assert_eq!(trimming_status.trimmed_edges(), 2); + + let ready_solution = Miner::::feasibility_check( + RawSolution { solution, score, round }, + Default::default(), + desired_targets, + snapshot.clone(), + round, + Default::default(), + ) + .unwrap(); + + let trimmed_supports = ready_solution.supports.into_iter().collect::>(); + + // gather all trimmed_supports edges from the trimmed solution. + let mut trimmed_supports_edges_full = vec![]; + for (t, s) in trimmed_supports { + for v in s.voters { + trimmed_supports_edges_full.push((t, v)); + } + } + + // expected trimmed supports set should be disjoint to the trimmed_supports full set of + // edges. + for edge in trimmed_supports_edges_full { + assert!(!expected_trimmed_supports.contains(&edge)); + } + }) + } + #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { From 478857933b031e5d703a8c9a1ed6047918ef4d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Mon, 9 Dec 2024 13:09:03 +0100 Subject: [PATCH 66/95] fixes overflowing tests --- substrate/frame/staking/src/pallet/mod.rs | 12 ++++++-- substrate/frame/staking/src/tests.rs | 36 +++++++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 31d25be0bd6bc..0966c0a42d669 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -917,11 +917,17 @@ pub mod pallet { mode: Forcing, }, /// Report of a controller batch deprecation. - ControllerBatchDeprecated { failures: u32 }, + ControllerBatchDeprecated { + failures: u32, + }, /// Validator has been disabled. - ValidatorDisabled { stash: T::AccountId }, + ValidatorDisabled { + stash: T::AccountId, + }, /// Validator has been re-enabled. - ValidatorReenabled { stash: T::AccountId }, + ValidatorReenabled { + stash: T::AccountId, + }, } #[pallet::error] diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c319c1c9a148d..82a5ac2f4e843 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2321,7 +2321,7 @@ fn phragmen_should_not_overflow() { #[test] fn reward_validator_slashing_validator_does_not_overflow() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().nominate(false).build_and_execute(|| { let stake = u64::MAX as Balance * 2; let reward_slash = u64::MAX as Balance * 2; @@ -2339,7 +2339,19 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Check reward ErasRewardPoints::::insert(0, reward); - EraInfo::::upsert_exposure(0, &11, exposure); + + // force exposure metadata to account for the overflowing `stake`. + ErasStakersOverview::::insert( + current_era(), + 11, + PagedExposureMetadata { total: stake, own: stake, nominator_count: 0, page_count: 0 }, + ); + + // we want to slash only self-stake, confirm that no others exposed. + let full_exposure_after = EraInfo::::get_full_exposure(current_era(), &11); + assert_eq!(full_exposure_after.total, stake); + assert_eq!(full_exposure_after.others, vec![]); + ErasValidatorReward::::insert(0, stake); assert_ok!(Staking::payout_stakers_by_page(RuntimeOrigin::signed(1337), 11, 0, 0)); assert_eq!(asset::total_balance::(&11), stake * 2); @@ -2350,13 +2362,19 @@ fn reward_validator_slashing_validator_does_not_overflow() { // only slashes out of bonded stake are applied. without this line, it is 0. Staking::bond(RuntimeOrigin::signed(2), stake - 1, RewardDestination::Staked).unwrap(); - // Override exposure of 11 - EraInfo::::upsert_exposure( - 0, - &11, - Exposure { - total: stake, - own: 1, + + // Override metadata and exposures of 11 so that it exposes minmal self stake and `stake` - + // 1 from nominator 2. + ErasStakersOverview::::insert( + current_era(), + 11, + PagedExposureMetadata { total: stake, own: 1, nominator_count: 1, page_count: 1 }, + ); + + ErasStakersPaged::::insert( + (current_era(), &11, 0), + ExposurePage { + page_total: stake - 1, others: vec![IndividualExposure { who: 2, value: stake - 1 }], }, ); From b792a6d8290cb363b5111b41dc55f4b06662e094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 11 Dec 2024 12:55:29 +0000 Subject: [PATCH 67/95] adds benchs and nits --- substrate/bin/node/runtime/src/lib.rs | 9 ++- .../src/unsigned.rs | 2 +- .../election-provider-support/src/lib.rs | 1 - .../frame/session/benchmarking/src/inner.rs | 2 + substrate/frame/staking/src/benchmarking.rs | 78 +++++++++++++++++-- substrate/frame/staking/src/pallet/impls.rs | 12 ++- substrate/frame/staking/src/pallet/mod.rs | 25 ++---- substrate/frame/staking/src/tests.rs | 1 - .../frame/staking/src/tests_paged_election.rs | 22 +++++- substrate/frame/staking/src/weights.rs | 27 ++++++- 10 files changed, 146 insertions(+), 33 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index faffcd23fbcf9..deafb01a19666 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -732,6 +732,7 @@ impl pallet_staking::Config for Runtime { type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; type MaxExposurePageSize = ConstU32<256>; + type MaxValidatorSet = MaxActiveValidators; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; type VoterList = VoterList; @@ -805,6 +806,8 @@ parameter_types! { // The maximum winners that can be elected by the Election pallet which is equivalent to the // maximum active validators the staking pallet can have. pub MaxActiveValidators: u32 = 1000; + // Unbounded number of backers per winner in the election solution. + pub MaxBackersPerWinner: u32 = u32::MAX; } /// The numbers configured here could always be more than the the maximum limits of staking pallet @@ -855,8 +858,10 @@ impl onchain::Config for OnChainSeqPhragmen { >; type DataProvider = ::DataProvider; type WeightInfo = frame_election_provider_support::weights::SubstrateWeight; - type MaxWinners = ::MaxWinners; type Bounds = ElectionBoundsOnChain; + type MaxBackersPerWinner = + ::MaxBackersPerWinner; + type MaxWinnersPerPage = MaxActiveValidators; } impl pallet_election_provider_multi_phase::MinerConfig for Runtime { @@ -867,6 +872,7 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { type MaxVotesPerVoter = <::DataProvider as ElectionDataProvider>::MaxVotesPerVoter; type MaxWinners = MaxActiveValidators; + type MaxBackersPerWinner = MaxBackersPerWinner; // The unsigned submissions have to respect the weight of the submit_unsigned call, thus their // weight estimate function is wired to this call's weight. @@ -905,6 +911,7 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type Solver = SequentialPhragmen, OffchainRandomBalancing>; type ForceOrigin = EnsureRootOrHalfCouncil; type MaxWinners = MaxActiveValidators; + type MaxBackersPerWinner = MaxBackersPerWinner; type ElectionBounds = ElectionBoundsMultiPhase; type BenchmarkingConfig = ElectionProviderBenchmarkConfig; type WeightInfo = pallet_election_provider_multi_phase::weights::SubstrateWeight; diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 6c2d55cac3dea..1a1245dbfd435 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -552,7 +552,7 @@ impl Miner { // filter out lowest stake edge in this support. // optimization note: collects edge voters to remove from assignments into a // btree set to optimize the search in the next loop. - let filtered: std::collections::BTreeSet<_> = support + let filtered: alloc::collections::BTreeSet<_> = support .voters .split_off(max_backers_per_winner) .into_iter() diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 49bd533cc8c3c..8b2edf4452a87 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -442,7 +442,6 @@ pub trait ElectionProvider { /// /// The result is returned in a target major format, namely as vector of supports. /// - /// TODO(gpestana): remove self-weighing? /// This should be implemented as a self-weighing function. The implementor should register its /// appropriate weight at the end of execution with the system pallet directly. fn elect(page: PageIndex) -> Result, Self::Error>; diff --git a/substrate/frame/session/benchmarking/src/inner.rs b/substrate/frame/session/benchmarking/src/inner.rs index 9789b6bb593d0..4c35f10789e9e 100644 --- a/substrate/frame/session/benchmarking/src/inner.rs +++ b/substrate/frame/session/benchmarking/src/inner.rs @@ -58,6 +58,7 @@ mod benchmarks { false, true, RewardDestination::Staked, + pallet_staking::CurrentEra::::get().unwrap(), )?; let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; @@ -82,6 +83,7 @@ mod benchmarks { false, true, RewardDestination::Staked, + pallet_staking::CurrentEra::::get().unwrap(), )?; let v_controller = pallet_staking::Pallet::::bonded(&v_stash).ok_or("not stash")?; let keys = T::Keys::decode(&mut TrailingZeroInput::zeroes()).unwrap(); diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 954f1bd02b47d..606c93e3fc00b 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -74,6 +74,7 @@ pub fn create_validator_with_nominators( dead_controller: bool, unique_controller: bool, destination: RewardDestination, + era: u32, ) -> Result<(T::AccountId, Vec<(T::AccountId, T::AccountId)>), &'static str> { // Clean up any existing state. clear_validators_and_nominators::(); @@ -129,14 +130,13 @@ pub fn create_validator_with_nominators( individual: points_individual.into_iter().collect(), }; - let current_era = CurrentEra::::get().unwrap(); - ErasRewardPoints::::insert(current_era, reward); + ErasRewardPoints::::insert(era, reward); // Create reward pool let total_payout = asset::existential_deposit::() .saturating_mul(upper_bound.into()) .saturating_mul(1000u32.into()); - >::insert(current_era, total_payout); + >::insert(era, total_payout); Ok((v_stash, nominators)) } @@ -224,6 +224,67 @@ const USER_SEED: u32 = 999666; mod benchmarks { use super::*; + #[benchmark] + fn on_initialize_noop() { + assert!(ElectableStashes::::get().is_empty()); + assert_eq!(ElectingStartedAt::::get(), None); + + #[block] + { + Pallet::::on_initialize(1_u32.into()); + } + + assert!(ElectableStashes::::get().is_empty()); + assert_eq!(ElectingStartedAt::::get(), None); + } + + #[benchmark] + fn do_elect_paged(v: Linear<1, { T::MaxValidatorSet::get() }>) -> Result<(), BenchmarkError> { + assert!(ElectableStashes::::get().is_empty()); + + create_validators_with_nominators_for_era::( + v, + 100, + MaxNominationsOf::::get() as usize, + false, + None, + )?; + + #[block] + { + Pallet::::do_elect_paged(0u32); + } + + assert!(!ElectableStashes::::get().is_empty()); + + Ok(()) + } + + #[benchmark] + fn clear_election_metadata( + v: Linear<1, { T::MaxValidatorSet::get() }>, + ) -> Result<(), BenchmarkError> { + use frame_support::BoundedBTreeSet; + + let mut stashes: BoundedBTreeSet = BoundedBTreeSet::new(); + for u in (0..v).into_iter() { + frame_support::assert_ok!(stashes.try_insert(account("stash", u, SEED))); + } + + ElectableStashes::::set(stashes); + ElectingStartedAt::::set(Some(10u32.into())); + + #[block] + { + Pallet::::clear_election_metadata() + } + + assert!(ElectingStartedAt::::get().is_none()); + assert!(ElectableStashes::::get().is_empty()); + + Ok(()) + } + #[benchmark] fn bond() { let stash = create_funded_user::("stash", USER_SEED, 100); @@ -696,15 +757,20 @@ mod benchmarks { fn payout_stakers_alive_staked( n: Linear<0, { T::MaxExposurePageSize::get() as u32 }>, ) -> Result<(), BenchmarkError> { + // reset genesis era 0 so that triggering the new genesis era works as expected. + CurrentEra::::set(Some(0)); + let current_era = CurrentEra::::get().unwrap(); + Staking::::clear_era_information(current_era); + let (validator, nominators) = create_validator_with_nominators::( n, T::MaxExposurePageSize::get() as u32, false, true, RewardDestination::Staked, + current_era, )?; - let current_era = CurrentEra::::get().unwrap(); // set the commission for this particular era as well. >::insert( current_era, @@ -989,7 +1055,7 @@ mod benchmarks { #[block] { // default bounds are unbounded. - targets = >::get_npos_targets(DataProviderBounds::default(), SINGLE_PAGE); + targets = >::get_npos_targets(DataProviderBounds::default()); } assert_eq!(targets.len() as u32, v); @@ -1185,6 +1251,7 @@ mod tests { false, false, RewardDestination::Staked, + CurrentEra::::get().unwrap(), ) .unwrap(); @@ -1217,6 +1284,7 @@ mod tests { false, false, RewardDestination::Staked, + CurrentEra::::get().unwrap(), ) .unwrap(); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index fb30e3f497d1e..5244af5081285 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -271,6 +271,7 @@ impl Pallet { })?; let history_depth = T::HistoryDepth::get(); + ensure!( era <= current_era && era >= current_era.saturating_sub(history_depth), Error::::InvalidEraToReward @@ -731,22 +732,24 @@ impl Pallet { /// If any new election winner does not fit in the electable stashes storage, it truncates the /// result of the election. We ensure that only the winners that are part of the electable /// stashes have exposures collected for the next era. - pub(crate) fn do_elect_paged(page: PageIndex) { + pub(crate) fn do_elect_paged(page: PageIndex) -> Weight { let paged_result = match ::elect(page) { Ok(result) => result, Err(e) => { log!(warn, "election provider page failed due to {:?} (page: {})", e, page); // election failed, clear election prep metadata. Self::clear_election_metadata(); - Self::deposit_event(Event::StakingElectionFailed); - return + + return T::WeightInfo::clear_election_metadata(); }, }; if let Err(_) = Self::do_elect_paged_inner(paged_result) { defensive!("electable stashes exceeded limit, unexpected but election proceeds."); }; + + T::WeightInfo::do_elect_paged(T::MaxValidatorSet::get()) } /// Inner implementation of [`Self::do_elect_paged`]. @@ -805,6 +808,7 @@ impl Pallet { // accumulate total stake. total_stake_page = total_stake_page.saturating_add(exposure.total); // set or update staker exposure for this era. + EraInfo::::upsert_exposure(new_planned_era, &stash, exposure); }); @@ -839,7 +843,7 @@ impl Pallet { /// /// Returns vec of all the exposures of a validator in `paged_supports`, bounded by the number /// of max winners per page returned by the election provider. - fn collect_exposures( + pub(crate) fn collect_exposures( supports: BoundedSupportsOf, ) -> BoundedVec< (T::AccountId, Exposure>), diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 0966c0a42d669..8785b7e59c1fc 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1010,20 +1010,11 @@ pub mod pallet { let pages: BlockNumberFor = Self::election_pages().into(); // election ongoing, fetch the next page. - if let Some(started_at) = ElectingStartedAt::::get() { + let inner_weight = if let Some(started_at) = ElectingStartedAt::::get() { let next_page = pages.saturating_sub(One::one()).saturating_sub(now.saturating_sub(started_at)); - // note: this pallet is expected to fetch all the solution pages starting from the - // most significant one through to the page 0. Fetching page zero is an indication - // that all the solution pages have been fetched. - if next_page == Zero::zero() { - crate::log!(trace, "elect(): finished fetching all paged solutions."); - Self::do_elect_paged(Zero::zero()); - } else { - crate::log!(trace, "elect(): progressing, {:?} remaining pages.", next_page); - Self::do_elect_paged(next_page.saturated_into::()); - } + Self::do_elect_paged(next_page.saturated_into::()) } else { // election isn't ongoing yet, check if it should start. let next_election = ::next_election_prediction(now); @@ -1031,19 +1022,18 @@ pub mod pallet { if now == (next_election.saturating_sub(pages)) { crate::log!( trace, - "elect(): start fetching solution pages. expected pages: {}", + "elect(): start fetching solution pages. expected pages: {:?}", pages ); ElectingStartedAt::::set(Some(now)); - Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)); + Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)) + } else { + Weight::default() } }; - // TODO: benchmark on_initialize - - // return the weight of the on_finalize. - T::DbWeight::get().reads(1) + T::WeightInfo::on_initialize_noop().saturating_add(inner_weight) } fn on_finalize(_n: BlockNumberFor) { @@ -1878,6 +1868,7 @@ pub mod pallet { era: EraIndex, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; + Self::do_payout_stakers(validator_stash, era) } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 82a5ac2f4e843..218fa682735ec 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -2331,7 +2331,6 @@ fn reward_validator_slashing_validator_does_not_overflow() { // Set staker let _ = asset::set_stakeable_balance::(&11, stake); - let exposure = Exposure:: { total: stake, own: stake, others: vec![] }; let reward = EraRewardPoints:: { total: 1, individual: vec![(11, 1)].into_iter().collect(), diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 2610b93916cfd..99652fa0f1e46 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -150,8 +150,7 @@ mod paged_on_initialize { assert_eq!(expected_elected.len(), 2); // 1. election prep hasn't started yet, election cursor and electable stashes are - // not - // set yet. + // not set yet. run_to_block(next_election - pages - 1); assert_eq!(ElectingStartedAt::::get(), None); assert!(ElectableStashes::::get().is_empty()); @@ -678,6 +677,25 @@ mod paged_snapshot { mod paged_exposures { use super::*; + #[test] + fn genesis_collect_exposures_works() { + ExtBuilder::default().multi_page_election_provider(3).build_and_execute(|| { + // first, clean up all the era data and metadata to mimic a genesis election next. + Staking::clear_era_information(current_era()); + + // genesis election is single paged. + let genesis_result = <::GenesisElectionProvider>::elect(0u32).unwrap(); + let expected_exposures = Staking::collect_exposures(genesis_result.clone()); + + Staking::try_trigger_new_era(0u32, true); + + // expected exposures are stored for the expected genesis validators. + for exposure in expected_exposures { + assert_eq!(EraInfo::::get_full_exposure(0, &exposure.0), exposure.1); + } + }) + } + #[test] fn store_stakers_info_elect_works() { ExtBuilder::default().exposures_page_size(2).build_and_execute(|| { diff --git a/substrate/frame/staking/src/weights.rs b/substrate/frame/staking/src/weights.rs index 56f561679cfc7..f0b9da081c1e6 100644 --- a/substrate/frame/staking/src/weights.rs +++ b/substrate/frame/staking/src/weights.rs @@ -51,6 +51,9 @@ use core::marker::PhantomData; /// Weight functions needed for `pallet_staking`. pub trait WeightInfo { + fn on_initialize_noop() -> Weight; + fn do_elect_paged(v: u32,) -> Weight; + fn clear_election_metadata() -> Weight; fn bond() -> Weight; fn bond_extra() -> Weight; fn unbond() -> Weight; @@ -88,6 +91,17 @@ pub trait WeightInfo { /// Weights for `pallet_staking` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { + // TODO: run CI bench bot + fn on_initialize_noop() -> Weight { + RocksDbWeight::get().reads(1) + } + fn do_elect_paged(_v: u32,) -> Weight { + RocksDbWeight::get().reads(1) + } + fn clear_election_metadata() -> Weight { + RocksDbWeight::get().reads(1) + } + /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) @@ -838,6 +852,17 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests. impl WeightInfo for () { + // TODO: run CI bench bot + fn on_initialize_noop() -> Weight { + RocksDbWeight::get().reads(1) + } + fn do_elect_paged(_v: u32,) -> Weight { + RocksDbWeight::get().reads(1) + } + fn clear_election_metadata() -> Weight { + RocksDbWeight::get().reads(1) + } + /// Storage: `Staking::Bonded` (r:1 w:1) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) /// Storage: `Staking::Ledger` (r:1 w:1) @@ -1584,4 +1609,4 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } -} \ No newline at end of file +} From 5ce51eaa86964ed90789d7f2bd6208c0860df835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 11 Dec 2024 14:32:22 +0000 Subject: [PATCH 68/95] pr review refactors and improvements --- substrate/frame/staking/src/lib.rs | 14 +- substrate/frame/staking/src/pallet/impls.rs | 130 ++++++++---------- .../frame/staking/src/tests_paged_election.rs | 2 +- 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 94b8e62577921..ff3621c394abf 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -384,7 +384,17 @@ macro_rules! log { }; } -/// Alias fo the maximum number of winners (aka. active validators), as defined in by this pallet's +/// Alias for a bounded set of exposures behind a validator, parameterized by this pallet's +/// election provider. +pub type BoundedExposuresOf = BoundedVec< + ( + ::AccountId, + Exposure<::AccountId, BalanceOf>, + ), + MaxWinnersPerPageOf<::ElectionProvider>, +>; + +/// Alias for the maximum number of winners (aka. active validators), as defined in by this pallet's /// config. pub type MaxWinnersOf = ::MaxValidatorSet; @@ -1336,7 +1346,7 @@ impl EraInfo { last_page.others.extend(exposures_append.others); ErasStakersPaged::::insert((era, &validator, last_page_idx), last_page); - // now handle the remainig exposures and append the exposure pages. The metadata update + // now handle the remaining exposures and append the exposure pages. The metadata update // has been already handled above. let (_, exposure_pages) = exposure.into_pages(page_size); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 5244af5081285..808e36aa039ba 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -51,10 +51,10 @@ use sp_staking::{ use crate::{ asset, election_size_tracker::StaticTracker, log, slashing, weights::WeightInfo, ActiveEraInfo, - BalanceOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, IndividualExposure, - LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, MaxWinnersPerPageOf, Nominations, - NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, SnapshotStatus, - StakingLedger, ValidatorPrefs, + BalanceOf, BoundedExposuresOf, EraInfo, EraPayout, Exposure, ExposureOf, Forcing, + IndividualExposure, LedgerIntegrityState, MaxNominationsOf, MaxWinnersOf, MaxWinnersPerPageOf, + Nominations, NominationsQuota, PositiveImbalanceOf, RewardDestination, SessionInterface, + SnapshotStatus, StakingLedger, ValidatorPrefs, }; use alloc::{boxed::Box, vec, vec::Vec}; @@ -671,7 +671,7 @@ impl Pallet { .unwrap_or_default(); // set stakers info for genesis era (0). - Self::store_stakers_info(exposures.into_inner(), Zero::zero()); + Self::store_stakers_info(exposures, Zero::zero()); validators } else { @@ -725,7 +725,7 @@ impl Pallet { /// /// Fetches the election page with index `page` from the election provider. /// - /// The results from the elect call shold be stored in the `ElectableStashes` storage. In + /// The results from the elect call should be stored in the `ElectableStashes` storage. In /// addition, it stores stakers' information for next planned era based on the paged solution /// data returned. /// @@ -765,10 +765,7 @@ impl Pallet { match Self::add_electables(supports.iter().map(|(s, _)| s.clone())) { Ok(_) => { - let _ = Self::store_stakers_info( - Self::collect_exposures(supports).into_inner(), - planning_era, - ); + let _ = Self::store_stakers_info(Self::collect_exposures(supports), planning_era); Ok(()) }, Err(not_included) => { @@ -782,10 +779,7 @@ impl Pallet { // storage bounds to prevent collecting their exposures. supports.retain(|(s, _)| !not_included.contains(s)); - let _ = Self::store_stakers_info( - Self::collect_exposures(supports).into_inner(), - planning_era, - ); + let _ = Self::store_stakers_info(Self::collect_exposures(supports), planning_era); Err(()) }, } @@ -795,7 +789,7 @@ impl Pallet { /// /// Store staking information for the new planned era of a single election page. pub fn store_stakers_info( - exposures: Vec<(T::AccountId, Exposure>)>, + exposures: BoundedExposuresOf, new_planned_era: EraIndex, ) -> BoundedVec> { // populate elected stash, stakers, exposures, and the snapshot of validator prefs. @@ -815,7 +809,7 @@ impl Pallet { let elected_stashes: BoundedVec<_, MaxWinnersPerPageOf> = elected_stashes_page .try_into() - .expect("elected_stashes.len() always equal to exposures.len(); qed"); + .expect("both typs are bounded by MaxWinnersPerPageOf; qed"); // adds to total stake in this era. EraInfo::::add_total_stake(new_planned_era, total_stake_page); @@ -845,10 +839,7 @@ impl Pallet { /// of max winners per page returned by the election provider. pub(crate) fn collect_exposures( supports: BoundedSupportsOf, - ) -> BoundedVec< - (T::AccountId, Exposure>), - MaxWinnersPerPageOf, - > { + ) -> BoundedExposuresOf { let total_issuance = asset::total_issuance::(); let to_currency = |e: frame_election_provider_support::ExtendedBalance| { T::CurrencyToVote::to_currency(e, total_issuance) @@ -1131,8 +1122,6 @@ impl Pallet { } else { *status = SnapshotStatus::Ongoing(last.clone()); } - } else { - debug_assert!(*status == SnapshotStatus::Consumed); } }, // do nothing. @@ -2174,54 +2163,57 @@ impl Pallet { let election_prep_started = now >= expect_election_start_at; - // check election metadata, electable targets and era exposures if election should have - // already started. - match election_prep_started { - // election prep should have been started. - true => - if let Some(started_at) = ElectingStartedAt::::get() { - ensure!( - started_at == expect_election_start_at, - "unexpected electing_started_at block number in storage." - ); - ensure!( - !ElectableStashes::::get().is_empty(), - "election should have been started and the electable stashes non empty." - ); + if !election_prep_started { + // election prep should have not been started yet, no metadata in storage. + ensure!( + ElectableStashes::::get().is_empty(), + "unexpected electable stashes in storage while election prep hasn't started." + ); + ensure!( + ElectingStartedAt::::get().is_none(), + "unexpected election metadata while election prep hasn't started.", + ); - // all the current electable stashes exposures should have been collected and - // stored for the next era, and their total exposure suhould be > 0. - for s in ElectableStashes::::get().iter() { - ensure!( - EraInfo::::get_paged_exposure( - Self::current_era().unwrap_or_default().saturating_add(1), - s, - 0 - ) - .defensive_proof("electable stash exposure does not exist, unexpected.") - .unwrap() - .exposure_metadata - .total != Zero::zero(), - "no exposures collected for an electable stash." - ); - } - } else { - return Err( - "election prep should have started already, no election metadata in storage." - .into(), - ); - }, - // election prep should have not been started. - false => { - ensure!( - ElectableStashes::::get().is_empty(), - "unexpected electable stashes in storage while election prep hasn't started." - ); - ensure!( - ElectingStartedAt::::get().is_none(), - "unexpected election metadata while election prep hasn't started.", - ); - }, + return Ok(()) + } + + // from now on, we expect the election to have started. check election metadata, electable + // targets and era exposures. + let maybe_electing_started = ElectingStartedAt::::get(); + + if maybe_electing_started.is_none() { + return Err( + "election prep should have started already, but no election metadata in storage." + .into(), + ); + } + + let started_at = maybe_electing_started.unwrap(); + + ensure!( + started_at == expect_election_start_at, + "unexpected electing_started_at block number in storage." + ); + ensure!( + !ElectableStashes::::get().is_empty(), + "election should have been started and the electable stashes non empty." + ); + + // all the current electable stashes exposures should have been collected and + // stored for the next era, and their total exposure should be > 0. + for s in ElectableStashes::::get().iter() { + ensure!( + EraInfo::::get_paged_exposure( + Self::current_era().unwrap_or_default().saturating_add(1), + s, + 0 + ) + .defensive_proof("electable stash exposure does not exist, unexpected.") + .unwrap() + .exposure_metadata + .total != Zero::zero(), + "no exposures collected for an electable stash." + ); } Ok(()) diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 99652fa0f1e46..4d85a1bd11fe8 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -531,7 +531,7 @@ mod paged_on_initialize { ElectingStartedAt::::kill(); assert_err!( Staking::ensure_snapshot_metadata_state(System::block_number()), - "election prep should have started already, no election metadata in storage." + "election prep should have started already, but no election metadata in storage." ); ElectingStartedAt::::set(Some(424242)); assert_err!( From 39e5c3d676b36d81934eb1adb7008fcf88cec560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 11 Dec 2024 16:02:44 +0000 Subject: [PATCH 69/95] improves add_electables and tests --- substrate/frame/staking/src/pallet/impls.rs | 26 ++++++++++--------- .../frame/staking/src/tests_paged_election.rs | 23 ++++++++-------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 808e36aa039ba..26cc1b3da8641 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -745,8 +745,12 @@ impl Pallet { }, }; - if let Err(_) = Self::do_elect_paged_inner(paged_result) { - defensive!("electable stashes exceeded limit, unexpected but election proceeds."); + if let Err(not_included) = Self::do_elect_paged_inner(paged_result) { + defensive!( + "electable stashes exceeded limit, unexpected but election proceeds.\ + {} stashes from election result discarded", + not_included.len() + ); }; T::WeightInfo::do_elect_paged(T::MaxValidatorSet::get()) @@ -755,10 +759,11 @@ impl Pallet { /// Inner implementation of [`Self::do_elect_paged`]. /// /// Returns an error if adding election winners to the electable stashes storage fails due to - /// exceeded bounds. + /// exceeded bounds. In case of error, it returns the stashes that were not included in the + /// electable stashes storage due to bounds contraints. pub(crate) fn do_elect_paged_inner( mut supports: BoundedSupportsOf, - ) -> Result<(), ()> { + ) -> Result<(), Vec> { // preparing the next era. Note: we expect `do_elect_paged` to be called *only* during a // non-genesis era, thus current era should be set by now. let planning_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); @@ -780,7 +785,7 @@ impl Pallet { supports.retain(|(s, _)| !not_included.contains(s)); let _ = Self::store_stakers_info(Self::collect_exposures(supports), planning_era); - Err(()) + Err(not_included) }, } } @@ -877,15 +882,12 @@ impl Pallet { /// Deduplicates stashes in place and returns an error if the bounds are exceeded. In case of /// error, it returns the stashes that were not added to the storage. pub(crate) fn add_electables( - mut stashes_iter: impl Iterator, + stashes_iter: impl Iterator + Clone, ) -> Result<(), Vec> { ElectableStashes::::mutate(|electable| { - while let Some(stash) = stashes_iter.next() { - if let Err(_) = (*electable).try_insert(stash.clone()) { - let mut not_included = stashes_iter.collect::>(); - not_included.push(stash); - - return Err(not_included); + for stash in stashes_iter.clone() { + if electable.try_insert(stash.clone()).is_err() { + return Err(stashes_iter.skip_while(|s| *s != stash).collect::>()); } } Ok(()) diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 4d85a1bd11fe8..38da0e94acbf4 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -29,7 +29,7 @@ mod electable_stashes { #[test] fn add_electable_stashes_work() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { MaxValidatorSet::set(5); assert_eq!(MaxValidatorSet::get(), 5); assert!(ElectableStashes::::get().is_empty()); @@ -47,28 +47,28 @@ mod electable_stashes { ElectableStashes::::get().into_inner().into_iter().collect::>(), vec![1, 2, 3, 4] ); - - // skip final try state checks. - SkipTryStateCheck::set(true); }) } #[test] fn add_electable_stashes_overflow_works() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { MaxValidatorSet::set(5); assert_eq!(MaxValidatorSet::get(), 5); assert!(ElectableStashes::::get().is_empty()); // adds stashes so that bounds are overflown, fails and internal state changes so that // all slots are filled. - assert!(Staking::add_electables(vec![1u64, 2, 3, 4, 5, 6].into_iter()).is_err()); + let expected_not_included = vec![6, 7, 8]; + assert_eq!( + Staking::add_electables(vec![1u64, 2, 3, 4, 5, 6, 7, 8].into_iter()), + Err(expected_not_included) + ); + // the included were added to the electable stashes, despite the error. assert_eq!( ElectableStashes::::get().into_inner().into_iter().collect::>(), vec![1, 2, 3, 4, 5] ); - - SkipTryStateCheck::set(true); }) } @@ -76,7 +76,7 @@ mod electable_stashes { fn overflow_electable_stashes_no_exposures_work() { // ensures exposures are stored only for the electable stashes that fit within the // electable stashes bounds in case of overflow. - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().try_state(false).build_and_execute(|| { MaxValidatorSet::set(2); assert_eq!(MaxValidatorSet::get(), 2); assert!(ElectableStashes::::get().is_empty()); @@ -92,7 +92,8 @@ mod electable_stashes { ]); // error due to bounds. - assert!(Staking::do_elect_paged_inner(supports).is_err()); + let expected_not_included = vec![3u64, 4]; + assert_eq!(Staking::do_elect_paged_inner(supports), Err(expected_not_included)); // electable stashes have been collected to the max bounds despite the error. assert_eq!(ElectableStashes::::get().into_iter().collect::>(), vec![1, 2]); @@ -105,8 +106,6 @@ mod electable_stashes { assert!(exposure_exists(2, 1)); assert!(!exposure_exists(3, 1)); assert!(!exposure_exists(4, 1)); - - SkipTryStateCheck::set(true); }) } } From 65cf87f912c26ac66eb66e6386041e6c07360b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Wed, 11 Dec 2024 16:27:22 +0000 Subject: [PATCH 70/95] improves add_electables --- substrate/frame/staking/src/pallet/impls.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 26cc1b3da8641..04fda942cac1c 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -885,12 +885,19 @@ impl Pallet { stashes_iter: impl Iterator + Clone, ) -> Result<(), Vec> { ElectableStashes::::mutate(|electable| { - for stash in stashes_iter.clone() { + let mut not_included = vec![]; + + for stash in stashes_iter { if electable.try_insert(stash.clone()).is_err() { - return Err(stashes_iter.skip_while(|s| *s != stash).collect::>()); + not_included.push(stash); } } - Ok(()) + + if not_included.len() != 0 { + Err(not_included) + } else { + Ok(()) + } }) } From 7d33c5c306dd78af2e4bdfe3cc2d101a5f1e0beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Thu, 12 Dec 2024 11:09:18 +0000 Subject: [PATCH 71/95] remove unecessary cloning --- substrate/frame/staking/src/pallet/impls.rs | 37 ++++++++----------- .../frame/staking/src/tests_paged_election.rs | 9 +++-- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 04fda942cac1c..f898b4544dc39 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -749,7 +749,7 @@ impl Pallet { defensive!( "electable stashes exceeded limit, unexpected but election proceeds.\ {} stashes from election result discarded", - not_included.len() + not_included ); }; @@ -763,7 +763,7 @@ impl Pallet { /// electable stashes storage due to bounds contraints. pub(crate) fn do_elect_paged_inner( mut supports: BoundedSupportsOf, - ) -> Result<(), Vec> { + ) -> Result<(), usize> { // preparing the next era. Note: we expect `do_elect_paged` to be called *only* during a // non-genesis era, thus current era should be set by now. let planning_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); @@ -773,18 +773,20 @@ impl Pallet { let _ = Self::store_stakers_info(Self::collect_exposures(supports), planning_era); Ok(()) }, - Err(not_included) => { + Err(not_included_idx) => { + let not_included = supports.len().saturating_sub(not_included_idx); + log!( warn, - "not all winners fit within the electable stashes, excluding tail: {:?}.", - not_included + "not all winners fit within the electable stashes, excluding {:?} accounts from solution.", + not_included, ); // filter out supports of stashes that do not fit within the electable stashes // storage bounds to prevent collecting their exposures. - supports.retain(|(s, _)| !not_included.contains(s)); - + supports.truncate(not_included_idx); let _ = Self::store_stakers_info(Self::collect_exposures(supports), planning_era); + Err(not_included) }, } @@ -880,24 +882,17 @@ impl Pallet { /// Adds a new set of stashes to the electable stashes. /// /// Deduplicates stashes in place and returns an error if the bounds are exceeded. In case of - /// error, it returns the stashes that were not added to the storage. + /// error, it returns the iter index of the element that failed to add. pub(crate) fn add_electables( - stashes_iter: impl Iterator + Clone, - ) -> Result<(), Vec> { + stashes_iter: impl Iterator, + ) -> Result<(), usize> { ElectableStashes::::mutate(|electable| { - let mut not_included = vec![]; - - for stash in stashes_iter { - if electable.try_insert(stash.clone()).is_err() { - not_included.push(stash); + for (idx, stash) in stashes_iter.enumerate() { + if electable.try_insert(stash).is_err() { + return Err(idx); } } - - if not_included.len() != 0 { - Err(not_included) - } else { - Ok(()) - } + Ok(()) }) } diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 38da0e94acbf4..bd91f6ca766bf 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -58,11 +58,12 @@ mod electable_stashes { assert!(ElectableStashes::::get().is_empty()); // adds stashes so that bounds are overflown, fails and internal state changes so that - // all slots are filled. - let expected_not_included = vec![6, 7, 8]; + // all slots are filled. error will return the idx of the first account that was not + // included. + let expected_idx_not_included = 5; // stash 6. assert_eq!( Staking::add_electables(vec![1u64, 2, 3, 4, 5, 6, 7, 8].into_iter()), - Err(expected_not_included) + Err(expected_idx_not_included) ); // the included were added to the electable stashes, despite the error. assert_eq!( @@ -92,7 +93,7 @@ mod electable_stashes { ]); // error due to bounds. - let expected_not_included = vec![3u64, 4]; + let expected_not_included = 2; assert_eq!(Staking::do_elect_paged_inner(supports), Err(expected_not_included)); // electable stashes have been collected to the max bounds despite the error. From d7817e0f993c4cecd8aaa5af614d0f8363f996fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pestana?= Date: Tue, 17 Dec 2024 18:41:17 +0000 Subject: [PATCH 72/95] migrations --- substrate/frame/staking/src/migrations.rs | 55 +++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 9dfa93c70b325..1f92dbb738f53 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -60,6 +60,61 @@ impl Default for ObsoleteReleases { #[storage_alias] type StorageVersion = StorageValue, ObsoleteReleases, ValueQuery>; +/// Migrates to multi-page election support. +/// +/// Important note: this migration should be released with the election provider configured by this +/// pallet supporting up to 1 page. Thus, +/// * `VoterSnapshotStatus` does not need migration, as it will always be `Status::Waiting` when +/// the number of election pages is 1. +/// * `ElectableStashes` must be populated iif there are collected exposures for a future era (i.e. +/// exposures have been collected but `fn try_trigger_new_era` was not called). +pub mod v17 { + use super::*; + + pub struct VersionedMigrateV16ToV17(core::marker::PhantomData); + impl OnRuntimeUpgrade for VersionedMigrateV16ToV17 { + fn on_runtime_upgrade() -> Weight { + // Populates the `ElectableStashes` with the exposures of the next planning era if it + // is initialized (i.e. if the there are exposures collected for the next planning + // era). + + // note: we expect the migration to be released with a single page config. + debug_assert!(Pallet::::election_pages() == 1); + + let next_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); + let prepared_exposures = ErasStakersOverview::::iter() + .filter(|(era_idx, _, _)| *era_idx == next_era) + .map(|(_, v, _)| v) + .collect::>(); + let migrated_stashes = prepared_exposures.len() as u32; + + let result = Pallet::::add_electables(prepared_exposures.into_iter()); + debug_assert!(result.is_ok()); + + T::DbWeight::get().reads_writes( + // 1x read per history depth and current era read. + (T::HistoryDepth::get() + 1u32).into(), + // 1x write per exposure migrated. + migrated_stashes.into(), + ) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!(Pallet::::on_chain_storage_version() >= 17, "v17 not applied"); + Ok(()) + } + + pub type MigrateV16ToV17 = VersionedMigration< + 16, + 17, + VersionedMigrateV16ToV17, + Pallet, + ::DbWeight, + >; +} + /// Migrating `DisabledValidators` from `Vec` to `Vec<(u32, OffenceSeverity)>` to track offense /// severity for re-enabling purposes. pub mod v16 { From de4f1da22de15e2a0fbf1f966df9e9cd12faed41 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Jan 2025 11:23:50 +0000 Subject: [PATCH 73/95] fix --- substrate/frame/staking/src/tests_paged_election.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index ef9d0eb866434..12dcfcfe6751d 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -685,6 +685,7 @@ mod paged_snapshot { assert_eq!(all_voters, single_page_voters); }) } +} mod paged_exposures { use super::*; From 06d33089722c625be236db4c16ed79d8a401fafa Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Jan 2025 11:36:52 +0000 Subject: [PATCH 74/95] fmt --- polkadot/runtime/westend/src/lib.rs | 3 ++- substrate/frame/staking/src/migrations.rs | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index ee1d2ce811bfe..88f722e75a9a3 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1150,7 +1150,8 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | + RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 1f92dbb738f53..b9219b4acb80e 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -62,6 +62,8 @@ type StorageVersion = StorageValue, ObsoleteReleases, Value /// Migrates to multi-page election support. /// +/// See: https://github.com/paritytech/polkadot-sdk/pull/6034 +/// /// Important note: this migration should be released with the election provider configured by this /// pallet supporting up to 1 page. Thus, /// * `VoterSnapshotStatus` does not need migration, as it will always be `Status::Waiting` when From 5426e880588c53695f8a63249114ab5478ec64a8 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:38:28 +0000 Subject: [PATCH 75/95] Update substrate/frame/election-provider-multi-phase/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/frame/election-provider-multi-phase/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index a2e46ecca3c7f..ae1d3edb794b2 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -514,7 +514,7 @@ pub enum ElectionError { DataProvider(&'static str), /// An error nested in the fallback. Fallback(FallbackErrorOf), - /// An error occurred when requesting an election result. The caller expects a mulit-paged + /// An error occurred when requesting an election result. The caller expects a multi-paged /// election, which this pallet does not support. MultiPageNotSupported, /// No solution has been queued. From c228dc4a9750f349d54b2b489f66340be3908f70 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Jan 2025 12:48:11 +0000 Subject: [PATCH 76/95] fix lock file --- Cargo.lock | 5971 +++++++++++++++++++++++++--------------------------- 1 file changed, 2814 insertions(+), 3157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95d06bf6cfce4..a19da6f71ad54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.28.1", + "gimli 0.28.0", ] [[package]] @@ -36,12 +36,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - [[package]] name = "adler32" version = "1.2.0" @@ -60,9 +54,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.4" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher 0.4.4", @@ -80,7 +74,7 @@ dependencies = [ "cipher 0.4.4", "ctr", "ghash", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -118,56 +112,56 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] [[package]] name = "allocator-api2" -version = "0.2.21" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "alloy-core" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0713007d14d88a6edb8e248cddab783b698dbb954a28b8eee4bab21cfb7e578" +checksum = "c618bd382f0bc2ac26a7e4bfae01c9b015ca8f21b37ca40059ae35a7e62b3dc6" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.15", "alloy-rlp", - "alloy-sol-types 0.8.18", + "alloy-sol-types 0.8.15", ] [[package]] name = "alloy-dyn-abi" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e3b98c37b3218924cd1d2a8570666b89662be54e5b182643855f783ea68b33" +checksum = "41056bde53ae10ffbbf11618efbe1e0290859e5eab0fe9ef82ebdb62f12a866f" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.15", "alloy-sol-type-parser", - "alloy-sol-types 0.8.18", + "alloy-sol-types 0.8.15", "const-hex", "itoa", "serde", "serde_json", - "winnow 0.6.24", + "winnow 0.6.18", ] [[package]] name = "alloy-json-abi" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731ea743b3d843bc657e120fb1d1e9cc94f5dab8107e35a82125a63e6420a102" +checksum = "c357da577dfb56998d01f574d81ad7a1958d248740a7981b205d69d65a7da404" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.15", "alloy-sol-type-parser", "serde", "serde_json", @@ -183,7 +177,7 @@ dependencies = [ "bytes", "cfg-if", "const-hex", - "derive_more 0.99.18", + "derive_more 0.99.17", "hex-literal", "itoa", "proptest", @@ -195,9 +189,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788bb18e8f61d5d9340b52143f27771daf7e1dccbaf2741621d2493f9debf52e" +checksum = "6259a506ab13e1d658796c31e6e39d2e2ee89243bcc505ddc613b35732e0a430" dependencies = [ "alloy-rlp", "bytes", @@ -206,6 +200,7 @@ dependencies = [ "derive_more 1.0.0", "foldhash", "hashbrown 0.15.2", + "hex-literal", "indexmap 2.7.0", "itoa", "k256", @@ -214,7 +209,7 @@ dependencies = [ "proptest", "rand", "ruint", - "rustc-hash 2.1.0", + "rustc-hash 2.0.0", "serde", "sha3 0.10.8", "tiny-keccak", @@ -222,12 +217,13 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.10" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" +checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "bytes", + "smol_str", ] [[package]] @@ -240,68 +236,68 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", "syn-solidity 0.4.2", "tiny-keccak", ] [[package]] name = "alloy-sol-macro" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07b74d48661ab2e4b50bb5950d74dbff5e61dd8ed03bb822281b706d54ebacb" +checksum = "d9d64f851d95619233f74b310f12bcf16e0cbc27ee3762b6115c14a84809280a" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19cc9c7f20b90f9be1a8f71a3d8e283a43745137b0837b1a1cb13159d37cad72" +checksum = "6bf7ed1574b699f48bf17caab4e6e54c6d12bc3c006ab33d58b1e227c1c3559f" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", "indexmap 2.7.0", "proc-macro-error2", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", - "syn-solidity 0.8.18", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "syn-solidity 0.8.15", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713b7e6dfe1cb2f55c80fb05fd22ed085a1b4e48217611365ed0ae598a74c6ac" +checksum = "8c02997ccef5f34f9c099277d4145f183b422938ed5322dc57a089fe9b9ad9ee" dependencies = [ "const-hex", "dunce", "heck 0.5.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", - "syn-solidity 0.8.18", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "syn-solidity 0.8.15", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eda2711ab2e1fb517fc6e2ffa9728c9a232e296d16810810e6957b781a1b8bc" +checksum = "ce13ff37285b0870d0a0746992a4ae48efaf34b766ae4c2640fa15e5305f8e73" dependencies = [ "serde", - "winnow 0.6.24", + "winnow 0.6.18", ] [[package]] @@ -318,13 +314,13 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b478bc9c0c4737a04cd976accde4df7eba0bdc0d90ad6ff43d58bc93cf79c1" +checksum = "1174cafd6c6d810711b4e00383037bdb458efc4fe3dbafafa16567e0320c54d8" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.18", - "alloy-sol-macro 0.8.18", + "alloy-primitives 0.8.15", + "alloy-sol-macro 0.8.15", "const-hex", "serde", ] @@ -367,59 +363,57 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "approx" @@ -439,16 +433,16 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" dependencies = [ "derive_arbitrary", ] @@ -459,7 +453,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -471,7 +465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" dependencies = [ "ark-bls12-377", - "ark-ec 0.4.2", + "ark-ec", "ark-models-ext", "ark-std 0.4.0", ] @@ -482,7 +476,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -495,7 +489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" dependencies = [ "ark-bls12-381", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-models-ext", "ark-serialize 0.4.2", @@ -509,7 +503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" dependencies = [ "ark-bls12-377", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -521,7 +515,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" dependencies = [ "ark-bw6-761", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-models-ext", "ark-std 0.4.0", @@ -534,7 +528,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff 0.4.2", - "ark-poly 0.4.2", + "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", @@ -545,27 +539,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ark-ec" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" -dependencies = [ - "ahash 0.8.11", - "ark-ff 0.5.0", - "ark-poly 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "educe", - "fnv", - "hashbrown 0.15.2", - "itertools 0.13.0", - "num-bigint", - "num-integer", - "num-traits", - "zeroize", -] - [[package]] name = "ark-ed-on-bls12-377" version = "0.4.0" @@ -573,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" dependencies = [ "ark-bls12-377", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -584,7 +557,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-377", "ark-ff 0.4.2", "ark-models-ext", @@ -598,7 +571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" dependencies = [ "ark-bls12-381", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -609,7 +582,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-381-bandersnatch", "ark-ff 0.4.2", "ark-models-ext", @@ -650,27 +623,7 @@ dependencies = [ "num-bigint", "num-traits", "paste", - "rustc_version 0.4.1", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" -dependencies = [ - "ark-ff-asm 0.5.0", - "ark-ff-macros 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "arrayvec 0.7.6", - "digest 0.10.7", - "educe", - "itertools 0.13.0", - "num-bigint", - "num-traits", - "paste", + "rustc_version 0.4.0", "zeroize", ] @@ -680,7 +633,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "syn 1.0.109", ] @@ -690,20 +643,10 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "syn 1.0.109", ] -[[package]] -name = "ark-ff-asm" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" -dependencies = [ - "quote 1.0.38", - "syn 2.0.96", -] - [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -712,7 +655,7 @@ checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint", "num-traits", - "quote 1.0.38", + "quote 1.0.37", "syn 1.0.109", ] @@ -724,31 +667,18 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] -[[package]] -name = "ark-ff-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - [[package]] name = "ark-models-ext" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -769,18 +699,17 @@ dependencies = [ ] [[package]] -name = "ark-poly" -version = "0.5.0" +name = "ark-scale" +version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" dependencies = [ - "ahash 0.8.11", - "ark-ff 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", - "educe", - "fnv", - "hashbrown 0.15.2", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "parity-scale-codec", + "scale-info", ] [[package]] @@ -789,7 +718,7 @@ version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f69c00b3b529be29528a6f2fd5fa7b1790f8bed81b9cdca17e326538545a179" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -802,7 +731,7 @@ name = "ark-secret-scalar" version = "0.0.2" source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -828,47 +757,23 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive 0.4.2", + "ark-serialize-derive", "ark-std 0.4.0", "digest 0.10.7", "num-bigint", ] -[[package]] -name = "ark-serialize" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" -dependencies = [ - "ark-serialize-derive 0.5.0", - "ark-std 0.5.0", - "arrayvec 0.7.6", - "digest 0.10.7", - "num-bigint", -] - [[package]] name = "ark-serialize-derive" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] -[[package]] -name = "ark-serialize-derive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - [[package]] name = "ark-std" version = "0.3.0" @@ -890,16 +795,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "ark-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" -dependencies = [ - "num-traits", - "rand", -] - [[package]] name = "ark-transcript" version = "0.0.2" @@ -915,15 +810,15 @@ dependencies = [ [[package]] name = "array-bytes" -version = "6.2.3" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5dde061bd34119e902bbb2d9b90c5692635cf59fb91d582c2b68043f1b8293" +checksum = "6f840fb7195bcfc5e17ea40c26e5ce6d5b9ce5d584466e17703209657e459ae0" [[package]] name = "arrayref" -version = "0.3.9" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -942,15 +837,15 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -958,19 +853,19 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", "synstructure 0.13.1", ] @@ -980,22 +875,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "assert_cmd" -version = "2.0.16" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" +checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" dependencies = [ "anstyle", "bstr", "doc-comment", - "libc", - "predicates 3.1.3", + "predicates 3.0.3", "predicates-core", "predicates-tree", "wait-timeout", @@ -1316,23 +1210,23 @@ dependencies = [ "cumulus-pallet-parachain-system 0.17.1", "cumulus-pallet-xcmp-queue 0.17.0", "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-assets 40.0.0", "pallet-balances 39.0.0", "pallet-collator-selection 19.0.0", "pallet-session 38.0.0", "pallet-timestamp 37.0.0", - "pallet-xcm 17.0.1", - "pallet-xcm-bridge-hub-router 0.15.3", + "pallet-xcm 17.0.0", + "pallet-xcm-bridge-hub-router 0.15.1", "parachains-common 18.0.0", "parachains-runtimes-test-utils 17.0.0", "parity-scale-codec", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-parachain-info 0.17.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "substrate-wasm-builder 24.0.1", ] @@ -1361,24 +1255,24 @@ dependencies = [ [[package]] name = "assets-common" -version = "0.18.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c540587f89a03003946b14decef4fcadb083edc4e62f968de245b82e5402e923" +checksum = "4556e56f9206b129c3f96249cd907b76e8d7ad5265fe368c228c708789a451a3" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "impl-trait-for-tuples", "log", "pallet-asset-conversion 20.0.0", "pallet-assets 40.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "parachains-common 18.0.0", "parity-scale-codec", "scale-info", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "substrate-wasm-builder 24.0.1", ] @@ -1389,7 +1283,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "syn 1.0.109", ] @@ -1406,11 +1300,12 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.3.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" dependencies = [ "concurrent-queue", + "event-listener 5.3.1", "event-listener-strategy", "futures-core", "pin-project-lite", @@ -1418,14 +1313,15 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" dependencies = [ + "async-lock 2.8.0", "async-task", "concurrent-queue", - "fastrand 2.3.0", - "futures-lite 2.6.0", + "fastrand 1.9.0", + "futures-lite 1.13.0", "slab", ] @@ -1449,21 +1345,21 @@ checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ "async-lock 3.4.0", "blocking", - "futures-lite 2.6.0", + "futures-lite 2.3.0", ] [[package]] name = "async-global-executor" -version = "2.4.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ - "async-channel 2.3.1", + "async-channel 1.9.0", "async-executor", - "async-io 2.4.0", - "async-lock 3.4.0", + "async-io 1.13.0", + "async-lock 2.8.0", "blocking", - "futures-lite 2.6.0", + "futures-lite 1.13.0", "once_cell", ] @@ -1481,29 +1377,29 @@ dependencies = [ "log", "parking", "polling 2.8.0", - "rustix 0.37.28", + "rustix 0.37.23", "slab", - "socket2 0.4.10", + "socket2 0.4.9", "waker-fn", ] [[package]] name = "async-io" -version = "2.4.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" dependencies = [ "async-lock 3.4.0", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.6.0", + "futures-lite 2.3.0", "parking", - "polling 3.7.4", - "rustix 0.38.43", + "polling 3.4.0", + "rustix 0.38.42", "slab", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1521,18 +1417,19 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.3.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-net" -version = "1.8.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0434b1ed18ce1cf5769b8ac540e33f01fa9471058b5e89da9e06f3c882a8c12f" +checksum = "4051e67316bc7eff608fe723df5d32ed639946adcd69e07df41fd42a7b411f1f" dependencies = [ "async-io 1.13.0", + "autocfg", "blocking", "futures-lite 1.13.0", ] @@ -1543,25 +1440,26 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io 2.4.0", + "async-io 2.3.3", "blocking", - "futures-lite 2.6.0", + "futures-lite 2.3.0", ] [[package]] name = "async-process" -version = "1.8.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6438ba0a08d81529c69b36700fa2f95837bfe3e776ab39cde9c14d9149da88" +checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9" dependencies = [ "async-io 1.13.0", "async-lock 2.8.0", - "async-signal", + "autocfg", "blocking", "cfg-if", - "event-listener 3.1.0", + "event-listener 2.5.3", "futures-lite 1.13.0", - "rustix 0.38.43", + "rustix 0.37.23", + "signal-hook", "windows-sys 0.48.0", ] @@ -1571,54 +1469,54 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ - "async-channel 2.3.1", - "async-io 2.4.0", + "async-channel 2.3.0", + "async-io 2.3.3", "async-lock 3.4.0", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener 5.4.0", - "futures-lite 2.6.0", - "rustix 0.38.43", + "event-listener 5.3.1", + "futures-lite 2.3.0", + "rustix 0.38.42", "tracing", ] [[package]] name = "async-signal" -version = "0.2.10" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" dependencies = [ - "async-io 2.4.0", + "async-io 2.3.3", "async-lock 3.4.0", "atomic-waker", "cfg-if", "futures-core", "futures-io", - "rustix 0.38.43", + "rustix 0.38.42", "signal-hook-registry", "slab", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "async-std" -version = "1.13.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 2.4.0", - "async-lock 3.4.0", + "async-io 1.13.0", + "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 2.6.0", - "gloo-timers 0.3.0", + "futures-lite 1.13.0", + "gloo-timers", "kv-log-macro", "log", "memchr", @@ -1631,9 +1529,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", @@ -1642,13 +1540,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -1659,13 +1557,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -1711,9 +1609,9 @@ checksum = "a8ab6b55fe97976e46f91ddbed8d147d966475dc29b2032757ba47e02376fbc3" [[package]] name = "atomic-waker" -version = "1.1.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "attohttpc" @@ -1721,7 +1619,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9a9bf8b79a749ee0b911b91b671cc2b6c670bdbc7e3dfd537576ddc94bb2a2" dependencies = [ - "http 0.2.12", + "http 0.2.9", "log", "url", ] @@ -1739,20 +1637,21 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.2.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-error", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backoff" @@ -1775,7 +1674,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object 0.32.2", "rustc-demangle", ] @@ -1786,7 +1685,7 @@ version = "0.0.4" source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ "ark-bls12-381", - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-381-bandersnatch", "ark-ff 0.4.2", "ark-serialize 0.4.2", @@ -1843,6 +1742,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db21524cad41c5591204d22d75e1970a2d1f71060214ca931dc7d5afe2c14e5" +dependencies = [ + "serde", +] + [[package]] name = "binary-merkle-tree" version = "13.0.0" @@ -1888,12 +1796,12 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -1908,7 +1816,7 @@ dependencies = [ "rand_core 0.6.4", "ripemd", "sha2 0.10.8", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -1957,7 +1865,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals", - "hex-conservative 0.1.2", + "hex-conservative 0.1.1", ] [[package]] @@ -1978,9 +1886,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.8.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -2047,8 +1955,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.6", - "constant_time_eq 0.3.1", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", ] [[package]] @@ -2064,26 +1972,26 @@ dependencies = [ [[package]] name = "blake2s_simd" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", - "arrayvec 0.7.6", - "constant_time_eq 0.3.1", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", ] [[package]] name = "blake3" -version = "1.5.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "cc", "cfg-if", - "constant_time_eq 0.3.1", + "constant_time_eq 0.3.0", ] [[package]] @@ -2113,15 +2021,17 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.6.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ - "async-channel 2.3.1", + "async-channel 1.9.0", + "async-lock 2.8.0", "async-task", - "futures-io", - "futures-lite 2.6.0", - "piper", + "atomic-waker", + "fastrand 1.9.0", + "futures-lite 1.13.0", + "log", ] [[package]] @@ -2143,7 +2053,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68534a48cbf63a4b1323c433cf21238c9ec23711e0df13b08c33e5c2082663ce" dependencies = [ - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -2284,13 +2194,13 @@ checksum = "890df97cea17ee61ff982466bb9e90cb6b1462adb45380999019388d05e4b92d" dependencies = [ "bp-runtime 0.18.0", "finality-grandpa", - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "scale-info", "serde", "sp-consensus-grandpa 21.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2331,7 +2241,7 @@ checksum = "7efabf94339950b914ba87249497f1a0e35a73849934d164fecae4b275928cf6" dependencies = [ "bp-header-chain 0.18.1", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "scale-info", "serde", @@ -2365,12 +2275,12 @@ dependencies = [ "bp-header-chain 0.18.1", "bp-polkadot-core 0.18.0", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2395,7 +2305,7 @@ dependencies = [ "bp-header-chain 0.18.1", "bp-polkadot-core 0.18.0", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "sp-api 34.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2442,14 +2352,14 @@ checksum = "345cf472bac11ef79d403e4846a666b7d22a13cd16d9c85b62cd6b5e16c4a042" dependencies = [ "bp-messages 0.18.0", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "parity-util-mem", "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2482,12 +2392,12 @@ dependencies = [ "bp-messages 0.18.0", "bp-parachains 0.18.0", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-utility 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2532,7 +2442,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "746d9464f912b278f8a5e2400f10541f95da7fc6c7d688a2788b9a46296146ee" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "hash-db", "impl-trait-for-tuples", @@ -2543,7 +2453,7 @@ dependencies = [ "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-state-machine 0.43.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", @@ -2585,7 +2495,7 @@ dependencies = [ "sp-application-crypto 38.0.0", "sp-consensus-grandpa 21.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", ] @@ -2620,13 +2530,13 @@ dependencies = [ [[package]] name = "bp-xcm-bridge-hub" -version = "0.4.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0873c54562b3d492541cbc8a7974c6854a5157d07880a2a71f8ba888a69e17e9" +checksum = "6909117ca87cb93703742939d5f0c4c93e9646d9cda22262e9709d68c929999b" dependencies = [ "bp-messages 0.18.0", "bp-runtime 0.18.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "scale-info", "serde", @@ -2656,7 +2566,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", ] @@ -2683,13 +2593,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c31b53c53d627e2da38f8910807944bf3121e154b5c0ac9e122995af9dfb13ed" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", - "pallet-message-queue 41.0.2", + "frame-support 38.0.0", + "pallet-message-queue 41.0.1", "parity-scale-codec", "scale-info", "snowbridge-core 0.10.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", ] @@ -2902,11 +2812,11 @@ dependencies = [ "bp-relayers 0.18.0", "bp-runtime 0.18.0", "bp-test-utils 0.18.0", - "bp-xcm-bridge-hub 0.4.2", - "bridge-runtime-common 0.18.2", + "bp-xcm-bridge-hub 0.4.0", + "bridge-runtime-common 0.18.0", "cumulus-pallet-parachain-system 0.17.1", "cumulus-pallet-xcmp-queue 0.17.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", @@ -2914,21 +2824,21 @@ dependencies = [ "pallet-bridge-grandpa 0.18.0", "pallet-bridge-messages 0.18.0", "pallet-bridge-parachains 0.18.0", - "pallet-bridge-relayers 0.18.2", + "pallet-bridge-relayers 0.18.0", "pallet-timestamp 37.0.0", "pallet-utility 38.0.0", - "pallet-xcm 17.0.1", - "pallet-xcm-bridge-hub 0.13.2", + "pallet-xcm 17.0.0", + "pallet-xcm-bridge-hub 0.13.0", "parachains-common 18.0.0", "parachains-runtimes-test-utils 17.0.0", "parity-scale-codec", "sp-core 34.0.0", "sp-io 38.0.0", "sp-keyring 39.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -3122,9 +3032,9 @@ dependencies = [ [[package]] name = "bridge-runtime-common" -version = "0.18.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86cf718057e18ce3e5f2c8e3fc318c38ad71d47ada91dc4b841c0f69c214ef04" +checksum = "c639aa22de6e904156a3e8b0e6b9e6af790cb27a1299688cc07997e1ffe5b648" dependencies = [ "bp-header-chain 0.18.1", "bp-messages 0.18.0", @@ -3132,20 +3042,20 @@ dependencies = [ "bp-polkadot-core 0.18.0", "bp-relayers 0.18.0", "bp-runtime 0.18.0", - "bp-xcm-bridge-hub 0.4.2", - "frame-support 38.2.0", + "bp-xcm-bridge-hub 0.4.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-bridge-grandpa 0.18.0", "pallet-bridge-messages 0.18.0", "pallet-bridge-parachains 0.18.0", - "pallet-bridge-relayers 0.18.2", - "pallet-transaction-payment 38.0.2", + "pallet-bridge-relayers 0.18.0", + "pallet-transaction-payment 38.0.0", "pallet-utility 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", "staging-xcm 14.2.0", @@ -3164,12 +3074,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.4.9", + "regex-automata 0.3.6", "serde", ] @@ -3184,9 +3094,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byte-slice-cast" @@ -3202,9 +3112,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.21.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -3214,9 +3124,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" dependencies = [ "serde", ] @@ -3257,24 +3167,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "846501f4575cd66766a40bb7ab6d8e960adc7eb49f753c8232bd8e0e09cf6ca2" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "camino" -version = "1.1.9" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.9" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -3287,10 +3197,10 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.24", + "semver 1.0.18", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -3307,9 +3217,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.2.9" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", @@ -3333,9 +3243,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.8" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" dependencies = [ "smallvec", ] @@ -3421,9 +3331,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", @@ -3431,14 +3341,14 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] name = "ciborium" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ "ciborium-io", "ciborium-ll", @@ -3447,15 +3357,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" [[package]] name = "ciborium-ll" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" dependencies = [ "ciborium-io", "half", @@ -3529,9 +3439,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.8.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", @@ -3548,69 +3458,108 @@ dependencies = [ "atty", "bitflags 1.3.2", "strsim 0.8.0", - "textwrap", - "unicode-width 0.1.14", + "textwrap 0.11.0", + "unicode-width", "vec_map", ] [[package]] name = "clap" -version = "4.5.26" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive 3.2.25", + "clap_lex 0.2.4", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap 0.16.0", +] + +[[package]] +name = "clap" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", - "clap_derive", + "clap_derive 4.5.13", ] [[package]] name = "clap-num" -version = "1.1.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" +checksum = "488557e97528174edaa2ee268b23a809e0c598213a4bbcb4f34575a46fda147e" dependencies = [ "num-traits", ] [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" dependencies = [ "anstream", "anstyle", - "clap_lex", + "clap_lex 0.7.0", "strsim 0.11.1", "terminal_size", ] [[package]] name = "clap_complete" -version = "4.5.42" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa3c596da3cf0983427b0df0dba359df9182c13bd5b519b585a482b0c351f4e8" +dependencies = [ + "clap 4.5.13", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ - "clap 4.5.26", + "heck 0.4.1", + "proc-macro-error", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cmd_lib" @@ -3619,7 +3568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "371c15a3c178d0117091bd84414545309ca979555b1aad573ef591ad58818d41" dependencies = [ "cmd_lib_macros", - "env_logger 0.10.2", + "env_logger 0.10.1", "faccess", "lazy_static", "log", @@ -3633,19 +3582,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb844bd05be34d91eb67101329aeba9d3337094c04fd8507d821db7ebb488eaf" dependencies = [ "proc-macro-error2", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "coarsetime" -version = "0.1.35" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4252bf230cb600c19826a575b31c8c9c84c6f11acfab6dfcad2e941b10b6f8e2" +checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" dependencies = [ "libc", - "wasix", + "once_cell", + "wasi", "wasm-bindgen", ] @@ -3656,7 +3606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ "termcolor", - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -3795,46 +3745,47 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.7" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" +checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.7" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" +checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.2.0" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" dependencies = [ + "is-terminal", "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] name = "combine" -version = "4.6.7" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -3842,13 +3793,13 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.3" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" +checksum = "7c64043d6c7b7a4c58e39e7efccfdea7b93d885a795d0c054a69dbbf4dd52686" dependencies = [ - "strum 0.26.3", - "strum_macros 0.26.4", - "unicode-width 0.2.0", + "strum 0.25.0", + "strum_macros 0.25.3", + "unicode-width", ] [[package]] @@ -3856,9 +3807,9 @@ name = "common" version = "0.1.0" source = "git+https://github.com/w3f/ring-proof?rev=665f5f5#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", - "ark-poly 0.4.2", + "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", "fflonk", @@ -3875,9 +3826,9 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "comparable" -version = "0.5.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8606f9aa5b5a2df738584b139c79413d0c1545ed0ffd16e76e0944d1de7388c0" +checksum = "eb513ee8037bf08c5270ecefa48da249f4c58e57a71ccfce0a5b0877d2a20eb2" dependencies = [ "comparable_derive", "comparable_helper", @@ -3887,25 +3838,25 @@ dependencies = [ [[package]] name = "comparable_derive" -version = "0.5.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f36ea7383b9a2a9ae0a4e225d8a9c1c3aeadde78c59cdc35bad5c02b4dad01" +checksum = "a54b9c40054eb8999c5d1d36fdc90e4e5f7ff0d1d9621706f360b3cbc8beb828" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "comparable_helper" -version = "0.5.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71c9b60259084f32c14d32476f3a299b4997e3c186e1473bd972ff8a8c83d1b4" +checksum = "fb5437e327e861081c91270becff184859f706e3e50f5301a9d4dc8eb50752c3" dependencies = [ "convert_case 0.6.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -3920,15 +3871,25 @@ dependencies = [ [[package]] name = "console" -version = "0.15.10" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", + "lazy_static", "libc", - "once_cell", - "unicode-width 0.2.0", - "windows-sys 0.59.0", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", ] [[package]] @@ -3946,27 +3907,29 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.6" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" -version = "0.1.18" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" dependencies = [ "const-random-macro", + "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.16" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ "getrandom", "once_cell", + "proc-macro-hack", "tiny-keccak", ] @@ -3978,15 +3941,21 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "constcat" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" +checksum = "f272d0c4cf831b4fa80ee529c7707f76585986e910e1fbce1d7921970bc1a241" [[package]] name = "contracts-rococo-runtime" @@ -4083,21 +4052,11 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" -version = "0.8.7" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core2" @@ -4320,9 +4279,9 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" dependencies = [ "cfg-if", ] @@ -4339,9 +4298,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -4440,7 +4399,7 @@ dependencies = [ "itertools 0.10.5", "log", "smallvec", - "wasmparser 0.102.0", + "wasmparser", "wasmtime-types", ] @@ -4461,9 +4420,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] @@ -4477,7 +4436,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.26", + "clap 4.5.13", "criterion-plot", "futures", "is-terminal", @@ -4508,37 +4467,42 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ + "autocfg", + "cfg-if", "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.12" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -4548,13 +4512,13 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -4586,7 +4550,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -4600,7 +4564,7 @@ dependencies = [ "generic-array 0.14.7", "poly1305", "salsa20", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -4617,7 +4581,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -4749,7 +4713,7 @@ dependencies = [ "sp-inherents 26.0.0", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -4933,7 +4897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cbe2735fc7cf2b6521eab00cb1a1ab025abc1575cc36887b36dc8c5cb1c9434" dependencies = [ "cumulus-pallet-parachain-system 0.17.1", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-aura 37.0.0", "pallet-timestamp 37.0.0", @@ -4941,7 +4905,7 @@ dependencies = [ "scale-info", "sp-application-crypto 38.0.0", "sp-consensus-aura 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -4970,13 +4934,13 @@ checksum = "97263a8e758d201ebe81db7cea7b278b4fb869c11442f77acef70138ac1a252f" dependencies = [ "cumulus-primitives-core 0.16.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", ] @@ -5040,11 +5004,11 @@ dependencies = [ "cumulus-primitives-proof-size-hostfunction 0.10.0", "environmental", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "parity-scale-codec", "polkadot-parachain-primitives 14.0.0", "polkadot-runtime-common 17.0.0", @@ -5054,13 +5018,13 @@ dependencies = [ "sp-externalities 0.29.0", "sp-inherents 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-state-machine 0.43.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", "sp-version 37.0.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "trie-db", ] @@ -5068,10 +5032,10 @@ dependencies = [ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -5080,10 +5044,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "befbaf3a1ce23ac8476481484fef5f4d500cbd15b4dad6380ce1d28134b0c1f7" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -5105,11 +5069,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18168570689417abfb514ac8812fca7e6429764d01942750e395d7d8ce0716ef" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-session 38.0.0", "parity-scale-codec", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -5133,13 +5097,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42c74548c8cab75da6f2479a953f044b582cfce98479862344a24df7bbd215" dependencies = [ "cumulus-pallet-parachain-system 0.17.1", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-sudo 38.0.0", "parity-scale-codec", "polkadot-primitives 16.0.0", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -5182,12 +5146,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e49231f6cd8274438b078305dc8ce44c54c0d3f4a28e902589bcbaa53d954608" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", ] @@ -5227,19 +5191,19 @@ dependencies = [ "bp-xcm-bridge-hub-router 0.14.1", "cumulus-primitives-core 0.16.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "parity-scale-codec", "polkadot-runtime-common 17.0.0", "polkadot-runtime-parachains 17.0.1", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -5265,11 +5229,11 @@ checksum = "f47128f797359951723e2d106a80e592d007bb7446c299958cdbafb1489ddbf0" dependencies = [ "cumulus-pallet-xcm 0.17.0", "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", ] @@ -5278,7 +5242,7 @@ name = "cumulus-pov-validator" version = "0.1.0" dependencies = [ "anyhow", - "clap 4.5.26", + "clap 4.5.13", "parity-scale-codec", "polkadot-node-primitives", "polkadot-parachain-primitives 6.0.0", @@ -5288,7 +5252,7 @@ dependencies = [ "sp-io 30.0.0", "sp-maybe-compressed-blob 11.0.0", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -5310,7 +5274,7 @@ dependencies = [ "polkadot-primitives 15.0.0", "sp-api 34.0.0", "sp-consensus-aura 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -5340,7 +5304,7 @@ dependencies = [ "polkadot-primitives 16.0.0", "scale-info", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-trie 37.0.0", "staging-xcm 14.2.0", ] @@ -5424,12 +5388,12 @@ dependencies = [ "cumulus-primitives-core 0.16.0", "cumulus-primitives-proof-size-hostfunction 0.10.0", "docify", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -5475,14 +5439,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bdcf4d46dd93f1e6d5dd6d379133566a44042ba6476d04bdcbdb4981c622ae4" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "log", "pallet-asset-conversion 20.0.0", "parity-scale-codec", "polkadot-runtime-common 17.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -5529,7 +5493,7 @@ dependencies = [ "sp-blockchain", "sp-state-machine 0.35.0", "sp-version 29.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -5600,7 +5564,7 @@ dependencies = [ "sp-storage 19.0.0", "sp-version 29.0.0", "substrate-prometheus-endpoint", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-util", "tracing", @@ -5665,7 +5629,7 @@ dependencies = [ "cumulus-primitives-core 0.16.0", "parity-scale-codec", "polkadot-primitives 16.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-state-machine 0.43.0", "sp-trie 37.0.0", ] @@ -5718,7 +5682,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.26", + "clap 4.5.13", "criterion", "cumulus-client-cli", "cumulus-client-collator", @@ -5797,24 +5761,24 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.47" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" +checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" dependencies = [ "curl-sys", "libc", "openssl-probe", "openssl-sys", "schannel", - "socket2 0.5.8", + "socket2 0.5.7", "windows-sys 0.52.0", ] [[package]] name = "curl-sys" -version = "0.4.78+curl-8.11.0" +version = "0.4.72+curl-8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" +checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" dependencies = [ "cc", "libc", @@ -5835,7 +5799,7 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -5850,20 +5814,20 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.1", - "subtle 2.6.1", + "rustc_version 0.4.0", + "subtle 2.5.0", "zeroize", ] [[package]] name = "curve25519-dalek-derive" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -5881,61 +5845,46 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.136" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad7c7515609502d316ab9a24f67dc045132d93bfd3f00713389e90d9898bf30d" +checksum = "28403c86fc49e3401fdf45499ba37fad6493d9329449d6449d7f0e10f4654d28" dependencies = [ "cc", - "cxxbridge-cmd", "cxxbridge-flags", "cxxbridge-macro", - "foldhash", "link-cplusplus", ] [[package]] name = "cxx-build" -version = "1.0.136" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfd16fca6fd420aebbd80d643c201ee4692114a0de208b790b9cd02ceae65fb" +checksum = "78da94fef01786dc3e0c76eafcd187abcaa9972c78e05ff4041e24fdf059c285" dependencies = [ "cc", "codespan-reporting", - "proc-macro2 1.0.93", - "quote 1.0.38", + "once_cell", + "proc-macro2 1.0.86", + "quote 1.0.37", "scratch", - "syn 2.0.96", -] - -[[package]] -name = "cxxbridge-cmd" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c33fd49f5d956a1b7ee5f7a9768d58580c6752838d92e39d0d56439efdedc35" -dependencies = [ - "clap 4.5.26", - "codespan-reporting", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] name = "cxxbridge-flags" -version = "1.0.136" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f1077278fac36299cce8446effd19fe93a95eedb10d39265f3bf67b3036c9" +checksum = "e2a6f5e1dfb4b34292ad4ea1facbfdaa1824705b231610087b00b17008641809" [[package]] name = "cxxbridge-macro" -version = "1.0.136" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da7e4d6e74af6b79031d264b2f13c3ea70af1978083741c41ffce9308f1f24f" +checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "rustversion", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -5956,10 +5905,10 @@ checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "strsim 0.11.1", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -5969,34 +5918,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", - "quote 1.0.38", - "syn 2.0.96", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "dashmap" -version = "5.5.3" +version = "5.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" dependencies = [ "cfg-if", "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.8", ] [[package]] name = "data-encoding" -version = "2.7.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "data-encoding-macro" -version = "0.1.16" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b16d9d0d88a5273d830dac8b78ceb217ffc9b1d5404e5597a3542515329405b" +checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -6004,12 +5953,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.14" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b" +checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" dependencies = [ "data-encoding", - "syn 2.0.96", + "syn 1.0.109", ] [[package]] @@ -6023,9 +5972,9 @@ dependencies = [ [[package]] name = "der" -version = "0.7.9" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ "const-oid", "pem-rfc7468", @@ -6061,8 +6010,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -6072,9 +6021,9 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -6083,33 +6032,33 @@ version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "derive_arbitrary" -version = "1.4.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case 0.4.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "rustc_version 0.4.1", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "rustc_version 0.4.0", + "syn 1.0.109", ] [[package]] @@ -6127,10 +6076,10 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", - "unicode-xid 0.2.6", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", + "unicode-xid 0.2.4", ] [[package]] @@ -6172,7 +6121,7 @@ dependencies = [ "block-buffer 0.10.4", "const-oid", "crypto-common", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -6228,46 +6177,44 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "dissimilar" -version = "1.0.9" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" [[package]] name = "dleq_vrf" version = "0.0.2" source = "git+https://github.com/w3f/ring-vrf?rev=0fef826#0fef8266d851932ad25d6b41bc4b34d834d1e11d" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", - "ark-scale", + "ark-scale 0.0.12", "ark-secret-scalar", "ark-serialize 0.4.2", "ark-std 0.4.0", "ark-transcript", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "zeroize", ] [[package]] name = "dlmalloc" -version = "0.2.7" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5e0d321d61de16390ed273b647ce51605b575916d3c25e6ddf27a1e140035" +checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" dependencies = [ - "cfg-if", "libc", - "windows-sys 0.59.0", ] [[package]] @@ -6294,10 +6241,10 @@ dependencies = [ "common-path", "derive-syn-parse", "once_cell", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", - "syn 2.0.96", + "syn 2.0.87", "termcolor", "toml 0.8.19", "walkdir", @@ -6326,9 +6273,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "downcast-rs" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" @@ -6338,9 +6285,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dunce" -version = "1.0.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clonable" @@ -6358,22 +6305,22 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" dependencies = [ "der", "digest 0.10.7", @@ -6386,9 +6333,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.2.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8", "signature", @@ -6405,7 +6352,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "sha2 0.10.8", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -6438,18 +6385,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "educe" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" -dependencies = [ - "enum-ordinalize", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - [[package]] name = "either" version = "1.13.0" @@ -6475,7 +6410,7 @@ dependencies = [ "rand_core 0.6.4", "sec1", "serdect", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -6516,87 +6451,67 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "1.0.0" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck 0.5.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - -[[package]] -name = "enum-ordinalize" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" -dependencies = [ - "enum-ordinalize-derive", -] - -[[package]] -name = "enum-ordinalize-derive" -version = "4.3.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "heck 0.4.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "enumflags2" -version = "0.7.10" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.10" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "enumn" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" dependencies = [ "log", "regex", @@ -6614,9 +6529,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" dependencies = [ "humantime", "is-terminal", @@ -6627,9 +6542,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.6" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ "anstream", "anstyle", @@ -6667,12 +6582,11 @@ dependencies = [ [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" dependencies = [ "serde", - "typeid", ] [[package]] @@ -6719,7 +6633,7 @@ dependencies = [ "serde", "serde_json", "sha3 0.10.8", - "thiserror 1.0.69", + "thiserror", "uint 0.9.5", ] @@ -6813,20 +6727,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.4.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", @@ -6835,11 +6738,11 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.3.1", "pin-project-lite", ] @@ -6862,16 +6765,16 @@ dependencies = [ "file-guard", "fs-err", "prettyplease", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "eyre" -version = "0.6.12" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" dependencies = [ "indenter", "once_cell", @@ -6921,18 +6824,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec 0.7.6", - "auto_impl", - "bytes", -] - -[[package]] -name = "fastrlp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" -dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "auto_impl", "bytes", ] @@ -6944,7 +6836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec6f82451ff7f0568c6181287189126d492b5654e30a788add08027b6363d019" dependencies = [ "fatality-proc-macro", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -6955,10 +6847,10 @@ checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", "indexmap 2.7.0", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -6968,7 +6860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182f7dbc2ef73d9ef67351c5fbbea084729c48362d3ce9dd44c28e32e277fe5" dependencies = [ "libc", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -6994,27 +6886,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "rand_core 0.6.4", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] name = "fflonk" -version = "0.1.1" -source = "git+https://github.com/w3f/fflonk#eda051ea3b80042e844a3ebd17c2f60536e6ee3f" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" dependencies = [ - "ark-ec 0.5.0", - "ark-ff 0.5.0", - "ark-poly 0.5.0", - "ark-serialize 0.5.0", - "ark-std 0.5.0", + "ark-ec", + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "merlin", ] [[package]] name = "fiat-crypto" -version = "0.2.9" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" [[package]] name = "file-guard" @@ -7032,20 +6924,20 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.2", + "env_logger 0.10.1", "log", ] [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", - "libredox", - "windows-sys 0.59.0", + "redox_syscall 0.3.5", + "windows-sys 0.48.0", ] [[package]] @@ -7122,12 +7014,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.35" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", - "miniz_oxide 0.8.3", + "miniz_oxide", ] [[package]] @@ -7158,9 +7050,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "foreign-types" @@ -7200,7 +7092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" dependencies = [ "nonempty", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -7254,7 +7146,7 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01bdd47c2d541b38bd892da647d1e972c9d85b4ecd7094ad64f7600175da54d" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-support-procedural 30.0.4", "frame-system 38.0.0", "linregress", @@ -7267,7 +7159,7 @@ dependencies = [ "sp-application-crypto 38.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-runtime-interface 28.0.0", "sp-storage 21.0.0", "static_assertions", @@ -7280,7 +7172,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.5.26", + "clap 4.5.13", "comfy-table", "cumulus-client-parachain-inherent", "cumulus-primitives-proof-size-hostfunction 0.2.0", @@ -7333,7 +7225,7 @@ dependencies = [ "substrate-test-runtime", "subxt", "subxt-signer", - "thiserror 1.0.69", + "thiserror", "thousands", "westend-runtime", ] @@ -7358,12 +7250,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ffde6f573a63eeb1ccb7d2667c5741a11ce93bc30f33712e5326b9d8a811c29" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -7387,12 +7279,12 @@ dependencies = [ "frame-election-provider-support 28.0.0", "frame-support 28.0.0", "parity-scale-codec", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "scale-info", "sp-arithmetic 23.0.0", - "syn 2.0.96", + "syn 2.0.87", "trybuild", ] @@ -7402,10 +7294,10 @@ version = "14.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8156f209055d352994ecd49e19658c6b469d7c6de923bd79868957d0dcfb6f71" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -7433,21 +7325,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c36f5116192c63d39f1b4556fa30ac7db5a6a52575fa241b045f7dfa82ecc2be" dependencies = [ "frame-election-provider-solution-type 14.0.1", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-npos-elections 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "frame-election-provider-solution-type 13.0.0", "frame-election-provider-support 28.0.0", "frame-support 28.0.0", @@ -7489,7 +7381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c365bf3879de25bbee28e9584096955a02fbe8d7e7624e10675800317f1cee5b" dependencies = [ "aquamarine", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "frame-try-runtime 0.44.0", "log", @@ -7497,7 +7389,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", ] @@ -7567,12 +7459,12 @@ checksum = "56ac71dbd97039c49fdd69f416a4dd5d8da3652fdcafc3738b45772ad79eb4ec" dependencies = [ "array-bytes", "docify", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -7580,7 +7472,7 @@ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ "assert_cmd", - "clap 4.5.26", + "clap 4.5.13", "cumulus-primitives-proof-size-hostfunction 0.2.0", "cumulus-test-runtime", "frame-benchmarking-cli", @@ -7592,7 +7484,7 @@ dependencies = [ "sp-statement-store 10.0.0", "sp-tracing 16.0.0", "tempfile", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -7667,9 +7559,9 @@ dependencies = [ [[package]] name = "frame-support" -version = "38.2.0" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dd8b9f161a8289e3b9fe6c1068519358dbff2270d38097a923d3d1b4459dca" +checksum = "1e44af69fa61bc5005ffe0339e198957e77f0f255704a9bee720da18a733e3dc" dependencies = [ "aquamarine", "array-bytes", @@ -7697,7 +7589,7 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-metadata-ir 0.7.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", "sp-state-machine 0.43.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -7724,8 +7616,8 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "proc-macro-warning", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", "scale-info", "sp-core 28.0.0", @@ -7734,7 +7626,7 @@ dependencies = [ "sp-metadata-ir 0.6.0", "sp-runtime 31.0.1", "static_assertions", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -7747,14 +7639,14 @@ dependencies = [ "cfg-expr", "derive-syn-parse", "expander", - "frame-support-procedural-tools 13.0.1", + "frame-support-procedural-tools 13.0.0", "itertools 0.11.0", "macro_magic", "proc-macro-warning", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -7762,32 +7654,32 @@ name = "frame-support-procedural-tools" version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive 11.0.0", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "frame-support-procedural-tools" -version = "13.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a088fd6fda5f53ff0c17fc7551ce8bd0ead14ba742228443c8196296a7369b" +checksum = "bead15a320be1764cdd50458c4cfacb23e0cee65f64f500f8e34136a94c7eeca" dependencies = [ "frame-support-procedural-tools-derive 12.0.0", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -7796,9 +7688,9 @@ version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed971c6435503a099bdac99fe4c5bea08981709e5b5a0a8535a1856f48561191" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -7891,14 +7783,14 @@ checksum = "e3c7fa02f8c305496d2ae52edaecdb9d165f11afa965e05686d7d7dd1ce93611" dependencies = [ "cfg-if", "docify", - "frame-support 38.2.0", + "frame-support 38.0.0", "log", "parity-scale-codec", "scale-info", "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-version 37.0.0", "sp-weights 31.0.0", @@ -7927,12 +7819,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9693b2a736beb076e673520e1e8dee4fc128b8d35b020ef3e8a4b1b5ad63d9f2" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -7971,20 +7863,17 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83c811a5a1f5429c7fb5ebbf6cf9502d8f9b673fd395c12cf46c44a30a7daf0e" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] name = "fs-err" -version = "2.11.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" [[package]] name = "fs2" @@ -8002,7 +7891,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.43", + "rustix 0.38.42", "windows-sys 0.48.0", ] @@ -8105,9 +7994,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ "fastrand 2.3.0", "futures-core", @@ -8122,9 +8011,9 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -8134,7 +8023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.21", + "rustls 0.23.18", "rustls-pki-types", ] @@ -8156,7 +8045,7 @@ version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ - "gloo-timers 0.2.6", + "gloo-timers", "send_wrapper", ] @@ -8232,15 +8121,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -8255,11 +8142,11 @@ dependencies = [ [[package]] name = "ghash" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "polyval", ] @@ -8276,9 +8163,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" dependencies = [ "fallible-iterator 0.3.0", "stable_deref_trait", @@ -8296,9 +8183,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "glob-match" @@ -8316,12 +8203,12 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.2.0", + "http 1.1.0", "js-sys", "pin-project", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -8339,18 +8226,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "gloo-utils" version = "0.2.0" @@ -8411,9 +8286,9 @@ dependencies = [ [[package]] name = "governor" -version = "0.6.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +checksum = "821239e5672ff23e2a7060901fa622950bbd80b649cdaadd78d1c1767ed14eb4" dependencies = [ "cfg-if", "dashmap", @@ -8422,11 +8297,9 @@ dependencies = [ "no-std-compat", "nonzero_ext", "parking_lot 0.12.3", - "portable-atomic", "quanta", "rand", "smallvec", - "spinning_top", ] [[package]] @@ -8437,7 +8310,7 @@ checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -8451,7 +8324,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.12", + "http 0.2.9", "indexmap 2.7.0", "slab", "tokio", @@ -8461,16 +8334,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.7" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http 1.1.0", "indexmap 2.7.0", "slab", "tokio", @@ -8480,26 +8353,22 @@ dependencies = [ [[package]] name = "half" -version = "2.4.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "5.1.2" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" dependencies = [ "log", "pest", "pest_derive", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -8552,8 +8421,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "allocator-api2", - "equivalent", "foldhash", "serde", ] @@ -8569,11 +8436,11 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.10.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.14.5", ] [[package]] @@ -8612,12 +8479,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - [[package]] name = "hex" version = "0.4.3" @@ -8629,9 +8490,9 @@ dependencies = [ [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" [[package]] name = "hex-conservative" @@ -8639,7 +8500,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", ] [[package]] @@ -8650,9 +8511,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hickory-proto" -version = "0.24.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" dependencies = [ "async-trait", "cfg-if", @@ -8661,12 +8522,12 @@ dependencies = [ "futures-channel", "futures-io", "futures-util", - "idna", + "idna 0.4.0", "ipnet", "once_cell", "rand", - "socket2 0.5.8", - "thiserror 1.0.69", + "socket2 0.5.7", + "thiserror", "tinyvec", "tokio", "tracing", @@ -8689,7 +8550,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", ] @@ -8735,23 +8596,23 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "honggfuzz" -version = "0.5.56" +version = "0.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c76b6234c13c9ea73946d1379d33186151148e0da231506b964b44f3d023505" +checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" dependencies = [ "arbitrary", "lazy_static", - "memmap2 0.9.5", - "rustc_version 0.4.1", + "memmap2 0.5.10", + "rustc_version 0.4.0", ] [[package]] @@ -8767,9 +8628,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.12" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -8778,9 +8639,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -8789,23 +8650,23 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http 0.2.12", + "http 0.2.9", "pin-project-lite", ] [[package]] name = "http-body" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http 1.2.0", + "http 1.1.0", ] [[package]] @@ -8816,8 +8677,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -8829,9 +8690,9 @@ checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" [[package]] name = "httparse" -version = "1.9.5" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -8847,22 +8708,22 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.32" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.8", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -8871,16 +8732,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", - "http 1.2.0", - "http-body 1.0.1", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", "httparse", "httpdate", "itoa", @@ -8897,10 +8758,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http 0.2.12", - "hyper 0.14.32", + "http 0.2.9", + "hyper 0.14.29", "log", - "rustls 0.21.12", + "rustls 0.21.7", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -8908,22 +8769,22 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.5" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.2.0", - "hyper 1.5.2", + "http 1.1.0", + "hyper 1.3.1", "hyper-util", "log", - "rustls 0.23.21", - "rustls-native-certs 0.8.1", + "rustls 0.23.18", + "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.7", + "webpki-roots 0.26.3", ] [[package]] @@ -8932,7 +8793,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.32", + "hyper 0.14.29", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -8945,7 +8806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.32", + "hyper 0.14.29", "native-tls", "tokio", "tokio-native-tls", @@ -8953,35 +8814,36 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", - "http-body 1.0.1", - "hyper 1.5.2", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.3.1", "pin-project-lite", - "socket2 0.5.8", + "socket2 0.5.7", "tokio", + "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "windows 0.48.0", ] [[package]] @@ -8994,181 +8856,58 @@ dependencies = [ ] [[package]] -name = "icu_collections" -version = "1.5.0" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "icu_locid" -version = "1.5.0" +name = "idna" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "idna" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", + "unicode-bidi", + "unicode-normalization", ] [[package]] -name = "icu_locid_transform_data" -version = "1.5.0" +name = "if-addrs" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] [[package]] -name = "icu_normalizer" -version = "1.5.0" +name = "if-watch" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "if-addrs" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "if-watch" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf9d64cfcf380606e64f9a0bcf493616b65331199f984151a6fa11a7b3cde38" -dependencies = [ - "async-io 2.4.0", - "core-foundation 0.9.4", - "fnv", - "futures", - "if-addrs", - "ipnet", - "log", - "netlink-packet-core", - "netlink-packet-route", - "netlink-proto", - "netlink-sys", - "rtnetlink", - "system-configuration 0.6.1", - "tokio", - "windows 0.53.0", + "async-io 2.3.3", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "system-configuration", + "tokio", + "windows 0.51.1", ] [[package]] @@ -9181,8 +8920,8 @@ dependencies = [ "attohttpc", "bytes", "futures", - "http 0.2.12", - "hyper 0.14.32", + "http 0.2.9", + "hyper 0.14.29", "log", "rand", "tokio", @@ -9268,32 +9007,32 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] name = "include_dir" -version = "0.7.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" dependencies = [ "include_dir_macros", ] [[package]] name = "include_dir_macros" -version = "0.7.4" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", ] [[package]] @@ -9332,15 +9071,15 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.9" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", + "instant", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", - "web-time", + "unicode-width", ] [[package]] @@ -9393,7 +9132,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.8", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -9405,7 +9144,7 @@ version = "0.21.3" source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" dependencies = [ "ipfs-unixfs", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9424,36 +9163,30 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", + "hermit-abi 0.3.9", + "rustix 0.38.42", + "windows-sys 0.48.0", ] [[package]] name = "is_executable" -version = "1.0.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" +checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" dependencies = [ "winapi", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "isahc" version = "1.7.2" @@ -9468,7 +9201,7 @@ dependencies = [ "encoding_rs", "event-listener 2.5.3", "futures-lite 1.13.0", - "http 0.2.12", + "http 0.2.9", "log", "mime", "once_cell", @@ -9519,9 +9252,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jemalloc_pprof" @@ -9550,7 +9283,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror 1.0.69", + "thiserror", "walkdir", ] @@ -9571,14 +9304,19 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ - "once_cell", "wasm-bindgen", ] +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + [[package]] name = "json-patch" version = "1.4.0" @@ -9587,7 +9325,7 @@ checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" dependencies = [ "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9600,7 +9338,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9642,16 +9380,16 @@ dependencies = [ "futures-channel", "futures-util", "gloo-net", - "http 1.2.0", + "http 1.1.0", "jsonrpsee-core", "pin-project", - "rustls 0.23.21", + "rustls 0.23.18", "rustls-pki-types", "rustls-platform-verifier", - "soketto 0.8.1", - "thiserror 1.0.69", + "soketto 0.8.0", + "thiserror", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.0", "tokio-util", "tracing", "url", @@ -9667,17 +9405,17 @@ dependencies = [ "bytes", "futures-timer", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http 1.1.0", + "http-body 1.0.0", "http-body-util", "jsonrpsee-types", "parking_lot 0.12.3", "pin-project", "rand", - "rustc-hash 2.1.0", + "rustc-hash 2.0.0", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -9692,19 +9430,19 @@ checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" dependencies = [ "async-trait", "base64 0.22.1", - "http-body 1.0.1", - "hyper 1.5.2", - "hyper-rustls 0.27.5", + "http-body 1.0.0", + "hyper 1.3.1", + "hyper-rustls 0.27.3", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.21", + "rustls 0.23.18", "rustls-platform-verifier", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tokio", - "tower 0.4.13", + "tower", "tracing", "url", ] @@ -9716,10 +9454,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -9729,10 +9467,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" dependencies = [ "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http 1.1.0", + "http-body 1.0.0", "http-body-util", - "hyper 1.5.2", + "hyper 1.3.1", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -9740,12 +9478,12 @@ dependencies = [ "route-recognizer", "serde", "serde_json", - "soketto 0.8.1", - "thiserror 1.0.69", + "soketto 0.8.0", + "thiserror", "tokio", "tokio-stream", "tokio-util", - "tower 0.4.13", + "tower", "tracing", ] @@ -9755,10 +9493,10 @@ version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" dependencies = [ - "http 1.2.0", + "http 1.1.0", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9778,7 +9516,7 @@ version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" dependencies = [ - "http 1.2.0", + "http 1.1.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -9815,9 +9553,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" dependencies = [ "cpufeatures", ] @@ -9901,9 +9639,9 @@ dependencies = [ "either", "futures", "home", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.29", "hyper-rustls 0.24.2", "hyper-timeout", "jsonpath-rust", @@ -9912,17 +9650,17 @@ dependencies = [ "pem 3.0.4", "pin-project", "rand", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "rustls 0.21.7", + "rustls-pemfile 1.0.3", "secrecy 0.8.0", "serde", "serde_json", "serde_yaml", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-tungstenite", "tokio-util", - "tower 0.4.13", + "tower", "tower-http 0.4.4", "tracing", ] @@ -9935,13 +9673,13 @@ checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae" dependencies = [ "chrono", "form_urlencoded", - "http 0.2.12", + "http 0.2.9", "json-patch", "k8s-openapi", "once_cell", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -9964,7 +9702,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-util", "tracing", @@ -10023,13 +9761,13 @@ dependencies = [ [[package]] name = "landlock" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9baa9eeb6e315942429397e617a190f4fdc696ef1ee0342939d641029cbb4ea7" +checksum = "1530c5b973eeed4ac216af7e24baf5737645a6272e361f1fb95710678b67d9cc" dependencies = [ "enumflags2", "libc", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -10081,35 +9819,36 @@ dependencies = [ [[package]] name = "libfuzzer-sys" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" dependencies = [ "arbitrary", "cc", + "once_cell", ] [[package]] name = "libloading" -version = "0.8.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "winapi", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libnghttp2-sys" -version = "0.1.11+1.64.0" +version = "0.1.9+1.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6c24e48a7167cffa7119da39d577fa482e66c688a4aac016bee862e1a713c4" +checksum = "b57e858af2798e167e709b9d969325b6d8e9d50232fcbc494d7d54f976854a64" dependencies = [ "cc", "libc", @@ -10144,10 +9883,10 @@ dependencies = [ "libp2p-upnp", "libp2p-websocket", "libp2p-yamux", - "multiaddr 0.18.2", + "multiaddr 0.18.1", "pin-project", "rw-stream-sink", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -10185,8 +9924,8 @@ dependencies = [ "futures", "futures-timer", "libp2p-identity", - "multiaddr 0.18.2", - "multihash 0.19.3", + "multiaddr 0.18.1", + "multihash 0.19.1", "multistream-select", "once_cell", "parking_lot 0.12.3", @@ -10195,7 +9934,7 @@ dependencies = [ "rand", "rw-stream-sink", "smallvec", - "thiserror 1.0.69", + "thiserror", "tracing", "unsigned-varint 0.8.0", "void", @@ -10232,29 +9971,29 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm", - "lru 0.12.5", + "lru 0.12.3", "quick-protobuf 0.8.1", "quick-protobuf-codec", "smallvec", - "thiserror 1.0.69", + "thiserror", "tracing", "void", ] [[package]] name = "libp2p-identity" -version = "0.2.10" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b5621d159b32282eac446bed6670c39c7dc68a200a992d8f056afa0066f6d" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" dependencies = [ "bs58", "ed25519-dalek", "hkdf", - "multihash 0.19.3", + "multihash 0.19.1", "quick-protobuf 0.8.1", "rand", "sha2 0.10.8", - "thiserror 1.0.69", + "thiserror", "tracing", "zeroize", ] @@ -10265,7 +10004,7 @@ version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced237d0bd84bbebb7c2cad4c073160dacb4fe40534963c32ed6d4c6bb7702a3" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "asynchronous-codec 0.7.0", "bytes", "either", @@ -10281,7 +10020,7 @@ dependencies = [ "rand", "sha2 0.10.8", "smallvec", - "thiserror 1.0.69", + "thiserror", "tracing", "uint 0.9.5", "void", @@ -10303,7 +10042,7 @@ dependencies = [ "libp2p-swarm", "rand", "smallvec", - "socket2 0.5.8", + "socket2 0.5.7", "tokio", "tracing", "void", @@ -10339,15 +10078,15 @@ dependencies = [ "futures", "libp2p-core", "libp2p-identity", - "multiaddr 0.18.2", - "multihash 0.19.3", + "multiaddr 0.18.1", + "multihash 0.19.1", "once_cell", "quick-protobuf 0.8.1", "rand", "sha2 0.10.8", "snow", "static_assertions", - "thiserror 1.0.69", + "thiserror", "tracing", "x25519-dalek", "zeroize", @@ -10388,9 +10127,9 @@ dependencies = [ "quinn", "rand", "ring 0.17.8", - "rustls 0.23.21", - "socket2 0.5.8", - "thiserror 1.0.69", + "rustls 0.23.18", + "socket2 0.5.7", + "thiserror", "tokio", "tracing", ] @@ -10428,7 +10167,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "libp2p-swarm-derive", - "lru 0.12.5", + "lru 0.12.3", "multistream-select", "once_cell", "rand", @@ -10446,9 +10185,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206e0aa0ebe004d778d79fb0966aa0de996c19894e2c0605ba2f8524dd4443d8" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -10463,7 +10202,7 @@ dependencies = [ "libc", "libp2p-core", "libp2p-identity", - "socket2 0.5.8", + "socket2 0.5.7", "tokio", "tracing", ] @@ -10480,9 +10219,9 @@ dependencies = [ "libp2p-identity", "rcgen 0.11.3", "ring 0.17.8", - "rustls 0.23.21", - "rustls-webpki 0.101.7", - "thiserror 1.0.69", + "rustls 0.23.18", + "rustls-webpki 0.101.4", + "thiserror", "x509-parser", "yasna", ] @@ -10517,11 +10256,11 @@ dependencies = [ "parking_lot 0.12.3", "pin-project-lite", "rw-stream-sink", - "soketto 0.8.1", - "thiserror 1.0.69", + "soketto 0.8.0", + "thiserror", "tracing", "url", - "webpki-roots 0.25.4", + "webpki-roots 0.25.2", ] [[package]] @@ -10533,21 +10272,10 @@ dependencies = [ "either", "futures", "libp2p-core", - "thiserror 1.0.69", + "thiserror", "tracing", "yamux 0.12.1", - "yamux 0.13.4", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.8.0", - "libc", - "redox_syscall 0.5.8", + "yamux 0.13.3", ] [[package]] @@ -10592,7 +10320,7 @@ checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", "digest 0.9.0", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -10626,9 +10354,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "libc", @@ -10653,18 +10381,18 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linked_hash_set" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae85b5be22d9843c80e5fc80e9b64c8a3b1f98f867c709956eca3efff4e92e2" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" dependencies = [ "linked-hash-map", ] [[package]] name = "linregress" -version = "0.5.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9eda9dcf4f2a99787827661f312ac3219292549c2ee992bf9a6248ffb066bf7" +checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" dependencies = [ "nalgebra", ] @@ -10683,9 +10411,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lioness" @@ -10717,12 +10445,6 @@ dependencies = [ "paste", ] -[[package]] -name = "litemap" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" - [[package]] name = "litep2p" version = "0.8.4" @@ -10740,7 +10462,7 @@ dependencies = [ "hickory-resolver", "indexmap 2.7.0", "libc", - "mockall 0.13.1", + "mockall 0.13.0", "multiaddr 0.17.1", "multihash 0.17.0", "network-interface", @@ -10758,9 +10480,9 @@ dependencies = [ "simple-dns", "smallvec", "snow", - "socket2 0.5.8", + "socket2 0.5.7", "static_assertions", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", "tokio-tungstenite", @@ -10783,9 +10505,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -10793,9 +10515,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.25" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "serde", "value-bag", @@ -10812,17 +10534,17 @@ dependencies = [ [[package]] name = "lru" -version = "0.11.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a83fb7698b3643a0e34f9ae6f2e8f0178c0fd42f8b59d493aa271ff3a5bf21" +checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" [[package]] name = "lru" -version = "0.12.5" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.15.2", + "hashbrown 0.14.5", ] [[package]] @@ -10836,18 +10558,19 @@ dependencies = [ [[package]] name = "lz4" -version = "1.28.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" dependencies = [ + "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.11.1+lz4-1.10.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" dependencies = [ "cc", "libc", @@ -10862,6 +10585,15 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + [[package]] name = "macro_magic" version = "0.5.1" @@ -10870,8 +10602,8 @@ checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" dependencies = [ "macro_magic_core", "macro_magic_macros", - "quote 1.0.38", - "syn 2.0.96", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -10883,9 +10615,9 @@ dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -10894,9 +10626,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -10906,8 +10638,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", - "quote 1.0.38", - "syn 2.0.96", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -10935,6 +10667,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matchers" version = "0.1.0" @@ -10946,9 +10687,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.9" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" +checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" dependencies = [ "autocfg", "rawpointer", @@ -10972,11 +10713,11 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.38.43", + "rustix 0.37.23", ] [[package]] @@ -10990,9 +10731,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" dependencies = [ "libc", ] @@ -11006,6 +10747,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "memory-db" version = "0.32.0" @@ -11065,16 +10815,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minicov" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" -dependencies = [ - "cc", - "walkdir", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -11085,7 +10825,7 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" name = "minimal-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "docify", "futures", "futures-timer", @@ -11108,28 +10848,20 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] -[[package]] -name = "miniz_oxide" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -11142,7 +10874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa3eb39495d8e2e2947a1d862852c90cc6a4a8845f8b41c8829cb9fcc047f4a" dependencies = [ "arrayref", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", @@ -11155,8 +10887,8 @@ dependencies = [ "rand", "rand_chacha", "rand_distr", - "subtle 2.6.1", - "thiserror 1.0.69", + "subtle 2.5.0", + "thiserror", "zeroize", ] @@ -11215,15 +10947,15 @@ dependencies = [ [[package]] name = "mockall" -version = "0.13.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" dependencies = [ "cfg-if", "downcast", "fragile", - "mockall_derive 0.13.1", - "predicates 3.1.3", + "mockall_derive 0.13.0", + "predicates 3.0.3", "predicates-tree", ] @@ -11234,21 +10966,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "mockall_derive" -version = "0.13.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -11278,20 +11010,20 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.18.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" +checksum = "8b852bc02a2da5feed68cd14fa50d0774b92790a5bdbfa932a813926c8472070" dependencies = [ "arrayref", "byteorder", "data-encoding", "libp2p-identity", "multibase 0.9.1", - "multihash 0.19.3", + "multihash 0.19.1", "percent-encoding", "serde", "static_assertions", - "unsigned-varint 0.8.0", + "unsigned-varint 0.7.2", "url", ] @@ -11339,7 +11071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ "blake2b_simd 1.0.2", - "blake2s_simd 1.0.2", + "blake2s_simd 1.0.1", "blake3", "core2", "digest 0.10.7", @@ -11356,7 +11088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd8a792c1694c6da4f68db0a9d707c72bd260994da179e6030a5dcee00bb815" dependencies = [ "blake2b_simd 1.0.2", - "blake2s_simd 1.0.2", + "blake2s_simd 1.0.1", "blake3", "core2", "digest 0.10.7", @@ -11368,33 +11100,33 @@ dependencies = [ [[package]] name = "multihash" -version = "0.19.3" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" dependencies = [ "core2", - "unsigned-varint 0.8.0", + "unsigned-varint 0.7.2", ] [[package]] name = "multihash-derive" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "synstructure 0.12.6", ] [[package]] name = "multimap" -version = "0.10.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" @@ -11412,12 +11144,13 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.33.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" dependencies = [ "approx", "matrixmultiply", + "nalgebra-macros", "num-complex", "num-rational", "num-traits", @@ -11425,12 +11158,24 @@ dependencies = [ "typenum", ] +[[package]] +name = "nalgebra-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "names" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc" dependencies = [ + "clap 3.2.25", "rand", ] @@ -11452,27 +11197,28 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "netlink-packet-core" -version = "0.7.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" dependencies = [ "anyhow", "byteorder", + "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" -version = "0.17.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053998cea5a306971f88580d0829e90f270f940befd7cf928da179d4187a5a66" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", "bitflags 1.3.2", @@ -11491,29 +11237,29 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror 1.0.69", + "thiserror", ] [[package]] name = "netlink-proto" -version = "0.11.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", - "thiserror 1.0.69", + "thiserror", "tokio", ] [[package]] name = "netlink-sys" -version = "0.8.7" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" dependencies = [ "bytes", "futures", @@ -11524,21 +11270,21 @@ dependencies = [ [[package]] name = "network-interface" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" +checksum = "ae72fd9dbd7f55dda80c00d66acc3b2130436fcba9ea89118fc508eaae48dfb0" dependencies = [ "cc", "libc", - "thiserror 1.0.69", + "thiserror", "winapi", ] [[package]] name = "nix" -version = "0.26.4" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ "bitflags 1.3.2", "cfg-if", @@ -11547,11 +11293,11 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "bitflags 2.8.0", + "bitflags 1.3.2", "cfg-if", "libc", ] @@ -11562,7 +11308,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -11586,8 +11332,8 @@ version = "0.9.0-dev" dependencies = [ "array-bytes", "async-trait", - "clap 4.5.26", - "derive_more 0.99.18", + "clap 4.5.13", + "derive_more 0.99.17", "fs_extra", "futures", "hash-db", @@ -11662,7 +11408,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "generate-bags", "kitchensink-runtime", ] @@ -11671,7 +11417,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "flate2", "fs_extra", "glob", @@ -11782,9 +11528,9 @@ dependencies = [ [[package]] name = "num" -version = "0.4.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint", "num-complex", @@ -11796,10 +11542,11 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ + "autocfg", "num-integer", "num-traits", ] @@ -11823,9 +11570,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" dependencies = [ "num-traits", ] @@ -11842,9 +11589,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -11853,24 +11600,25 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "itoa", ] [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ + "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" dependencies = [ "autocfg", "num-integer", @@ -11879,10 +11627,11 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ + "autocfg", "num-bigint", "num-integer", "num-traits", @@ -11946,33 +11695,33 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" dependencies = [ "asn1-rs", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "opaque-debug" @@ -11982,17 +11731,17 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -12007,9 +11756,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -12020,9 +11769,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -12049,7 +11798,7 @@ dependencies = [ "orchestra-proc-macro", "pin-project", "prioritized-metered-channel", - "thiserror 1.0.69", + "thiserror", "tracing", ] @@ -12063,9 +11812,9 @@ dependencies = [ "indexmap 2.7.0", "itertools 0.11.0", "petgraph", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -12088,6 +11837,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "os_str_bytes" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" + [[package]] name = "overload" version = "0.1.1" @@ -12127,7 +11882,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59378a648a0aa279a4b10650366c3389cd0a1239b1876f74bfecd268eecb086b" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-collective 38.0.0", @@ -12137,7 +11892,7 @@ dependencies = [ "sp-core 34.0.0", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12167,7 +11922,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33f0078659ae95efe6a1bf138ab5250bc41ab98f22ff3651d0208684f08ae797" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -12176,7 +11931,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12206,7 +11961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3edbeda834bcd6660f311d4eead3dabdf6d385b7308ac75b0fae941a960e6c3a" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-asset-conversion 20.0.0", @@ -12215,7 +11970,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12243,13 +11998,13 @@ version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab66c4c22ac0f20e620a954ce7ba050118d6d8011e2d02df599309502064e98" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-asset-conversion 20.0.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12274,12 +12029,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71b2149aa741bc39466bbcc92d9d0ab6e9adcf39d2790443a735ad573b3191e7" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12310,15 +12065,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "406a486466d15acc48c99420191f96f1af018f3381fde829c467aba489030f18" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12345,14 +12100,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f45f4eb6027fc34c4650e0ed6a7e57ed3335cc364be74b4531f714237676bcee" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12379,13 +12134,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "127adc2250b89416b940850ce2175dab10a9297b503b1fcb05dc555bd9bd3207" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-assets 40.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12404,13 +12159,13 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15906a685adeabe6027e49c814a34066222dd6136187a8a79c213d0d739b6634" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12436,7 +12191,7 @@ version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b31da6e794d655d1f9c4da6557a57399538d75905a7862a2ed3f7e5fb711d7e4" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-timestamp 37.0.0", @@ -12444,7 +12199,7 @@ dependencies = [ "scale-info", "sp-application-crypto 38.0.0", "sp-consensus-aura 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12469,14 +12224,14 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffb0208f0538d58dcb78ce1ff5e6e8641c5f37b23b20b05587e51da30ab13541" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-session 38.0.0", "parity-scale-codec", "scale-info", "sp-application-crypto 38.0.0", "sp-authority-discovery 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12499,12 +12254,12 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625d47577cabbe1318ccec5d612e2379002d1b6af1ab6edcef3243c66ec246df" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12541,7 +12296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ee096c0def13832475b340d00121025e0225de29604d44bc6dfcaa294c995b4" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -12553,7 +12308,7 @@ dependencies = [ "sp-consensus-babe 0.40.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", ] @@ -12588,7 +12343,7 @@ dependencies = [ "docify", "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", @@ -12596,7 +12351,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", ] @@ -12653,12 +12408,12 @@ checksum = "5c6945b078919acb14d126490e4b0973a688568b30142476ca69c6df2bed27ad" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12694,7 +12449,7 @@ version = "39.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "014d177a3aba19ac144fc6b2b5eb94930b9874734b91fd014902b6706288bb5f" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -12703,7 +12458,7 @@ dependencies = [ "scale-info", "serde", "sp-consensus-beefy 22.1.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", ] @@ -12742,7 +12497,7 @@ dependencies = [ "array-bytes", "binary-merkle-tree 15.0.1", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-beefy 39.0.0", @@ -12755,7 +12510,7 @@ dependencies = [ "sp-consensus-beefy 22.1.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-state-machine 0.43.0", ] @@ -12783,7 +12538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1163f9cd8bbc47ec0c6900a3ca67689d8d7b40bedfa6aa22b1b3c6027b1090e" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-treasury 37.0.0", @@ -12791,7 +12546,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -12848,13 +12603,13 @@ dependencies = [ "bp-runtime 0.18.0", "bp-test-utils 0.18.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-consensus-grandpa 21.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -12891,12 +12646,12 @@ dependencies = [ "bp-messages 0.18.0", "bp-runtime 0.18.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", ] @@ -12934,13 +12689,13 @@ dependencies = [ "bp-polkadot-core 0.18.0", "bp-runtime 0.18.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-bridge-grandpa 0.18.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -12976,26 +12731,26 @@ dependencies = [ [[package]] name = "pallet-bridge-relayers" -version = "0.18.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe3be7077b7ddee7178b1b12e9171435da73778d093788e10b1bdfad1e10962" +checksum = "2faead05455a965a0a0ec69ffa779933479b599e40bda809c0aa1efa72a39281" dependencies = [ "bp-header-chain 0.18.1", "bp-messages 0.18.0", "bp-relayers 0.18.0", "bp-runtime 0.18.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-bridge-grandpa 0.18.0", "pallet-bridge-messages 0.18.0", "pallet-bridge-parachains 0.18.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -13021,13 +12776,13 @@ dependencies = [ [[package]] name = "pallet-broker" -version = "0.17.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "018b477d7d464c451b1d09a4ce9e792c3c65b15fd764b23da38ff9980e786065" +checksum = "3043c90106d88cb93fcf0d9b6d19418f11f44cc2b11873414aec3b46044a24ea" dependencies = [ "bitvec", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -13035,7 +12790,7 @@ dependencies = [ "sp-api 34.0.0", "sp-arithmetic 26.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13063,7 +12818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f3bc38ae6584b5f57e4de3e49e5184bfc0f20692829530ae1465ffe04e09e7" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-bounties 37.0.0", @@ -13072,7 +12827,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13106,7 +12861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658798d70c9054165169f6a6a96cfa9d6a5e7d24a524bc19825bf17fcbc5cc5a" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -13115,7 +12870,7 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -13143,14 +12898,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e149f1aefd444c9a1da6ec5a94bc8a7671d7a33078f85dd19ae5b06e3438e60" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13174,12 +12929,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38a6a5cbe781d9c711be74855ba32ef138f3779d6c54240c08e6d1b4bbba4d1d" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13235,13 +12990,13 @@ dependencies = [ "bitflags 1.3.2", "environmental", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", "pallet-balances 39.0.0", - "pallet-contracts-proc-macro 23.0.2", - "pallet-contracts-uapi 12.0.1", + "pallet-contracts-proc-macro 23.0.1", + "pallet-contracts-uapi 12.0.0", "parity-scale-codec", "paste", "rand", @@ -13251,10 +13006,10 @@ dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "wasm-instrument", "wasmi 0.32.3", ] @@ -13315,19 +13070,19 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "309666537ed001c61a99f59fa7b98680f4a6e4e361ed3bc64f7b0237da3e3e06" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-assets 40.0.0", "pallet-balances 39.0.0", "pallet-contracts 38.0.0", - "pallet-contracts-proc-macro 23.0.2", - "pallet-contracts-uapi 12.0.1", + "pallet-contracts-proc-macro 23.0.1", + "pallet-contracts-uapi 12.0.0", "pallet-insecure-randomness-collective-flip 26.0.0", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "pallet-proxy 38.0.0", "pallet-timestamp 37.0.0", "pallet-utility 38.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "parity-scale-codec", "polkadot-parachain-primitives 14.0.0", "polkadot-primitives 16.0.0", @@ -13337,10 +13092,10 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "xcm-simulator 17.0.0", ] @@ -13349,20 +13104,20 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "pallet-contracts-proc-macro" -version = "23.0.2" +version = "23.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3170e2f4a3d95f2ace274b703a72630294f0a27c687a4adbad9590e2b3e5fe82" +checksum = "94226cbd48516b7c310eb5dae8d50798c1ce73a7421dc0977c55b7fc2237a283" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -13377,13 +13132,14 @@ dependencies = [ [[package]] name = "pallet-contracts-uapi" -version = "12.0.1" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3e13d72cda1a30083a1c080acc56fc5f286d09c89d9d91e8e4942a230c58c8" +checksum = "16f74b000590c33fadea48585d3ae3f4b7867e99f0a524c444d5779f36b9a1b6" dependencies = [ "bitflags 1.3.2", "parity-scale-codec", "paste", + "polkavm-derive 0.9.1", "scale-info", ] @@ -13413,13 +13169,13 @@ checksum = "999c242491b74395b8c5409ef644e782fe426d87ae36ad92240ffbf21ff0a76e" dependencies = [ "assert_matches", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "serde", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13441,21 +13197,21 @@ dependencies = [ [[package]] name = "pallet-core-fellowship" -version = "22.2.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93052dd8d5910e1b939441541cec416e629b2c0ab92680124c2e5a137e12c285" +checksum = "d063b41df454bd128d6fefd5800af8a71ac383c9dd6f20096832537efc110a8a" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", - "pallet-ranked-collective 38.2.0", + "pallet-ranked-collective 38.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13500,13 +13256,13 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117f003a97f980514c6db25a50c22aaec2a9ccb5664b3cb32f52fb990e0b0c12" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -13536,7 +13292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6d1dc655f50b7c65bb2fb14086608ba11af02ef2936546f7a67db980ec1f133" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -13544,7 +13300,7 @@ dependencies = [ "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13568,14 +13324,14 @@ version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1d8050c09c5e003d502c1addc7fdfbde21a854bd57787e94447078032710c8" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13636,7 +13392,7 @@ checksum = "62f9ad5ae0c13ba3727183dadf1825b6b7b0b0598ed5c366f8697e13fd540f7d" dependencies = [ "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-election-provider-support-benchmarking 37.0.0", @@ -13647,7 +13403,7 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-npos-elections 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "strum 0.26.3", ] @@ -13674,7 +13430,7 @@ dependencies = [ "frame-system 38.0.0", "parity-scale-codec", "sp-npos-elections 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13704,7 +13460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "705c66d6c231340c6d085a0df0319a6ce42a150f248171e88e389ab1e3ce20f5" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -13712,7 +13468,7 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-npos-elections 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -13902,13 +13658,13 @@ dependencies = [ "docify", "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -13938,7 +13694,7 @@ checksum = "a1c79ab340890f6ab088a638c350ac1173a1b2a79c18004787523032025582b4" dependencies = [ "blake2 0.10.6", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -13946,7 +13702,7 @@ dependencies = [ "sp-core 34.0.0", "sp-inherents 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -13985,7 +13741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d3a570a4aac3173ea46b600408183ca2bcfdaadc077f802f11e6055963e2449" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -13996,7 +13752,7 @@ dependencies = [ "sp-consensus-grandpa 21.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", ] @@ -14027,13 +13783,13 @@ checksum = "e3a4288548de9a755e39fcb82ffb9024b6bb1ba0f582464a44423038dd7a892e" dependencies = [ "enumflags2", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14062,7 +13818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fd95270cf029d16cb40fe6bd9f8ab9c78cd966666dccbca4d8bfec35c5bba5" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -14071,7 +13827,7 @@ dependencies = [ "sp-application-crypto 38.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -14098,14 +13854,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5e4b97de630427a39d50c01c9e81ab8f029a00e56321823958b39b438f7b940" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", "sp-keyring 39.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14128,12 +13884,12 @@ version = "26.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dce7ad80675d78bd38a7a66ecbbf2d218dd32955e97f8e301d0afe6c87b0f251" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "safe-mix", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14159,11 +13915,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae0920ee53cf7b0665cfb6d275759ae0537dc3850ec78da5f118d814c99d3562" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14188,14 +13944,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1868b5dca4bbfd1f4a222cbb80735a5197020712a71577b496bbb7e19aaa5394" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14223,13 +13979,13 @@ dependencies = [ [[package]] name = "pallet-message-queue" -version = "41.0.2" +version = "41.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983f7d1be18e9a089a3e23670918f5085705b4403acd3fdde31878d57b76a1a8" +checksum = "0faa48b29bf5a178580c164ef00de87319a37da7547a9cd6472dfd160092811a" dependencies = [ "environmental", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -14237,7 +13993,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", ] @@ -14273,14 +14029,14 @@ checksum = "9b417fc975636bce94e7c6d707e42d0706d67dfa513e72f5946918e1044beef1" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14312,7 +14068,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3fa2b7f759a47f698a403ab40c54bc8935e2969387947224cbdb4e2bc8a28a" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -14322,7 +14078,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-io 38.0.0", "sp-mixnet 0.12.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14351,7 +14107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6932dfb85f77a57c2d1fdc28a7b3a59ffe23efd8d5bb02dc3039d91347e4a3b" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -14359,7 +14115,7 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-mmr-primitives 34.1.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14380,13 +14136,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e5099c9a4442efcc1568d88ca1d22d624e81ab96358f99f616c67fbd82532d2" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14414,14 +14170,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168792cf95a32fa3baf9b874efec82a45124da0a79cee1ae3c98a823e6841959" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-assets 40.0.0", "pallet-nfts 32.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14450,14 +14206,14 @@ checksum = "59e2aad461a0849d7f0471576eeb1fe3151795bcf2ec9e15eca5cca5b9d743b2" dependencies = [ "enumflags2", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14503,13 +14259,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ac349e119880b7df1a7c4c36d919b33a498d0e9548af3c237365c654ae0c73d" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14528,14 +14284,14 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec3133be9e767b8feafbb26edd805824faa59956da008d2dc7fcf4b4720e56" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14557,11 +14313,11 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" -version = "35.0.2" +version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d04f050ab02af6cbe058e101abb8706be7f8ea7958e5bf1d4cd8caa6b66c71" +checksum = "c42906923f9f2b65b22f1211136b57c6878296ba6f6228a075c4442cc1fc1659" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", @@ -14569,7 +14325,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", "sp-tracing 17.0.1", ] @@ -14606,15 +14362,15 @@ checksum = "38d2eaca0349bcda923343226b8b64d25a80b67e0a1ebaaa5b0ab1e1b3b225bc" dependencies = [ "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-bags-list 37.0.0", "pallet-delegated-staking 5.0.0", - "pallet-nomination-pools 35.0.2", + "pallet-nomination-pools 35.0.0", "pallet-staking 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-runtime-interface 28.0.0", "sp-staking 36.0.0", ] @@ -14645,11 +14401,11 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" -version = "33.0.2" +version = "33.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03eea431eba0658ca763a078bd849e0622c37c85eddd011b8e886460b50c0827" +checksum = "7a9e1cb89cc2e6df06ce274a7fc814e5e688aad04c43902a10191fa3d2a56a96" dependencies = [ - "pallet-nomination-pools 35.0.2", + "pallet-nomination-pools 35.0.0", "parity-scale-codec", "sp-api 34.0.0", ] @@ -14724,14 +14480,14 @@ version = "37.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c4379cf853465696c1c5c03e7e8ce80aeaca0a6139d698abe9ecb3223fd732a" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", "parity-scale-codec", "scale-info", "serde", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -14769,7 +14525,7 @@ checksum = "69aa1b24cdffc3fa8c89cdea32c83f1bf9c1c82a87fa00e57ae4be8e85f5e24f" dependencies = [ "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-babe 38.0.0", @@ -14781,7 +14537,7 @@ dependencies = [ "pallet-staking 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -14809,14 +14565,14 @@ checksum = "c8e099fb116068836b17ca4232dc52f762b69dc8cd4e33f509372d958de278b0" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", "sp-metadata-ir 0.7.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14866,14 +14622,14 @@ checksum = "b9aba424d55e17b2a2bec766a41586eab878137704d4803c04bebd6a4743db7b" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "paste", "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14899,14 +14655,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "407828bc48c6193ac076fdf909b2fadcaaecd65f42b0b0a04afe22fe8e563834" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14927,12 +14683,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d39df395f0dbcf07dafe842916adea3266a87ce36ed87b5132184b6bcd746393" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14954,12 +14710,12 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" -version = "38.2.0" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a640e732164203eb5298823cc8c29cfc563763c43c9114e76153b3166b8b9d" +checksum = "c2b38708feaed202debf1ac6beffaa5e20c99a9825c5ca0991753c2d4eaaf3ac" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", @@ -14968,7 +14724,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -14993,12 +14749,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "406a116aa6d05f88f3c10d79ff89cf577323680a48abd8e5550efb47317e67fa" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15029,7 +14785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3008c20531d1730c9b457ae77ecf0e3c9b07aaf8c4f5d798d61ef6f0b9e2d4b" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -15037,7 +14793,7 @@ dependencies = [ "serde", "sp-arithmetic 26.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15062,14 +14818,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e8cae0e20888065ec73dda417325c6ecabf797f4002329484b59c25ecc34d4" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15078,7 +14834,7 @@ version = "0.1.0" dependencies = [ "array-bytes", "assert_matches", - "derive_more 0.99.18", + "derive_more 0.99.17", "environmental", "ethereum-types 0.15.1", "frame-benchmarking 28.0.0", @@ -15126,13 +14882,13 @@ dependencies = [ "bitflags 1.3.2", "environmental", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", "pallet-balances 39.0.0", "pallet-revive-fixtures 0.2.0", - "pallet-revive-proc-macro 0.1.2", + "pallet-revive-proc-macro 0.1.1", "pallet-revive-uapi 0.1.1", "parity-scale-codec", "paste", @@ -15142,10 +14898,10 @@ dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -15153,8 +14909,8 @@ name = "pallet-revive-eth-rpc" version = "0.1.0" dependencies = [ "anyhow", - "clap 4.5.26", - "env_logger 0.11.6", + "clap 4.5.13", + "env_logger 0.11.3", "ethabi", "futures", "hex", @@ -15178,7 +14934,7 @@ dependencies = [ "substrate-prometheus-endpoint", "subxt", "subxt-signer", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -15203,7 +14959,7 @@ dependencies = [ "frame-system 38.0.0", "parity-wasm", "polkavm-linker 0.10.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "tempfile", "toml 0.8.19", ] @@ -15245,18 +15001,18 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60e74591d44dbd78db02c8593f5caa75bd61bcc4d63999302150223fb969ae37" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-assets 40.0.0", "pallet-balances 39.0.0", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "pallet-proxy 38.0.0", "pallet-revive 0.2.0", - "pallet-revive-proc-macro 0.1.2", + "pallet-revive-proc-macro 0.1.1", "pallet-revive-uapi 0.1.1", "pallet-timestamp 37.0.0", "pallet-utility 38.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "parity-scale-codec", "polkadot-parachain-primitives 14.0.0", "polkadot-primitives 16.0.0", @@ -15266,10 +15022,10 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "xcm-simulator 17.0.0", ] @@ -15278,20 +15034,20 @@ dependencies = [ name = "pallet-revive-proc-macro" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "pallet-revive-proc-macro" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8aee42afa416be6324cf6650c137da9742f27dc7be3c7ed39ad9748baf3b9ae" +checksum = "0cc16d1f7cee6a1ee6e8cd710e16230d59fb4935316c1704cf770e4d2335f8d4" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -15345,13 +15101,13 @@ version = "35.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35774b830928daaeeca7196cead7c56eeed952a6616ad6dc5ec068d8c85c81a" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-session 38.0.0", "pallet-staking 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -15374,13 +15130,13 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be95e7c320ac1d381715364cd721e67ab3152ab727f8e4defd3a92e41ebbc880" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15410,7 +15166,7 @@ checksum = "6d3e67dd4644c168cedbf257ac3dd2527aad81acf4a0d413112197094e549f76" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-balances 39.0.0", "pallet-proxy 38.0.0", @@ -15418,7 +15174,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15434,21 +15190,21 @@ dependencies = [ [[package]] name = "pallet-salary" -version = "23.2.0" +version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af2d92b1fef1c379c0692113b505c108c186e09c25c72b38e879b6e0f172ebe" +checksum = "0544a71dba06a9a29da0778ba8cb37728c3b9a8377ac9737c4b1bc48c618bc2f" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", - "pallet-ranked-collective 38.2.0", + "pallet-ranked-collective 38.0.0", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15496,13 +15252,13 @@ checksum = "26899a331e7ab5f7d5966cbf203e1cf5bd99cd110356d7ddcaa7597087cdc0b5" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", ] @@ -15526,12 +15282,12 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f84b48bb4702712c902f43931c4077d3a1cb6773c8d8c290d4a6251f6bc2a5c" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15560,7 +15316,7 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8474b62b6b7622f891e83d922a589e2ad5be5471f5ca47d45831a797dba0b3f4" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", @@ -15569,7 +15325,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", "sp-state-machine 0.43.0", @@ -15605,13 +15361,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aadce7df0fee981721983795919642648b846dab5ab9096f82c2cea781007d0" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-session 38.0.0", "pallet-staking 38.0.0", "parity-scale-codec", "rand", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", ] @@ -15632,11 +15388,11 @@ version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c2cb0dae13d2c2d2e76373f337d408468f571459df1900cbd7458f21cf6c01" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15666,7 +15422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1dc69fea8a8de343e71691f009d5fece6ae302ed82b7bb357882b2ea6454143" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -15674,7 +15430,7 @@ dependencies = [ "scale-info", "sp-arithmetic 26.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15714,7 +15470,7 @@ checksum = "c870d123f4f053b56af808a4beae1ffc4309a696e829796c26837936c926db3b" dependencies = [ "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-authorship 38.0.0", @@ -15724,7 +15480,7 @@ dependencies = [ "serde", "sp-application-crypto 38.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -15732,11 +15488,11 @@ dependencies = [ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "sp-runtime 31.0.1", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -15808,14 +15564,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138c15b4200b9dc4c3e031def6a865a235cdc76ff91ee96fba19ca1787c9dda6" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15841,7 +15597,7 @@ version = "20.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e03e147efa900e75cd106337f36da3d7dcd185bd9e5f5c3df474c08c3c37d16" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -15849,7 +15605,7 @@ dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-statement-store 18.0.0", ] @@ -15876,12 +15632,12 @@ checksum = "1574fe2aed3d52db4a389b77b53d8c9758257b121e3e7bbe24c4904e11681e0e" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15925,14 +15681,14 @@ checksum = "a9ba9b71bbfd33ae672f23ba7efaeed2755fdac37b8f946cb7474fc37841b7e1" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-inherents 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-storage 21.0.0", "sp-timestamp 34.0.0", ] @@ -15963,7 +15719,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa1d4371a70c309ba11624933f8f5262fe4edad0149c556361d31f26190da936" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-treasury 37.0.0", @@ -15972,7 +15728,7 @@ dependencies = [ "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -15994,18 +15750,18 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" -version = "38.0.2" +version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdb86580c72b58145f9cddba21a0c1814742ca56abc9caac3c1ac72f6bde649" +checksum = "47b1aa3498107a30237f941b0f02180db3b79012c3488878ff01a4ac3e8ee04e" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16040,10 +15796,10 @@ version = "38.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49fdf5ab71e9dbcadcf7139736b6ea6bac8ec4a83985d46cbd130e1eec770e41" dependencies = [ - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "parity-scale-codec", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", ] @@ -16074,7 +15830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c337a972a6a796c0a0acc6c03b5e02901c43ad721ce79eb87b45717d75c93b" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", @@ -16083,7 +15839,7 @@ dependencies = [ "serde", "sp-inherents 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-transaction-storage-proof 34.0.0", ] @@ -16115,7 +15871,7 @@ checksum = "98bfdd3bb9b58fb010bcd419ff5bf940817a8e404cdbf7886a53ac730f5dda2b" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "pallet-balances 39.0.0", @@ -16123,7 +15879,7 @@ dependencies = [ "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16152,14 +15908,14 @@ checksum = "cee153f5be5efc84ebd53aa581e5361cde17dc3669ef80d8ad327f4041d89ebe" dependencies = [ "docify", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-balances 39.0.0", "pallet-proxy 38.0.0", "pallet-utility 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16185,12 +15941,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2b13cdaedf2d5bd913a5f6e637cb52b5973d8ed4b8d45e56d921bc4d627006f" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16218,13 +15974,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fdcade6efc0b66fc7fc4138964802c02d0ffb7380d894e26b9dd5073727d2b3" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16269,12 +16025,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "807df2ef13ab6bf940879352c3013bfa00b670458b4c125c2f60e5753f68e3d5" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16301,12 +16057,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ef17df925290865cf37096dd0cb76f787df11805bba01b1d0ca3e106d06280b" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -16336,13 +16092,13 @@ dependencies = [ [[package]] name = "pallet-xcm" -version = "17.0.1" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989676964dbda5f5275650fbdcd3894fe7fac626d113abf89d572b4952adcc36" +checksum = "0b1760b6589e53f4ad82216c72c0e38fcb4df149c37224ab3301dc240c85d1d4" dependencies = [ "bounded-collections", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", @@ -16351,12 +16107,11 @@ dependencies = [ "serde", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", - "tracing", - "xcm-runtime-apis 0.4.2", + "xcm-runtime-apis 0.4.0", ] [[package]] @@ -16389,15 +16144,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da423463933b42f4a4c74175f9e9295a439de26719579b894ce533926665e4a" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -16430,24 +16185,24 @@ dependencies = [ [[package]] name = "pallet-xcm-bridge-hub" -version = "0.13.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f336403f9e9bf22a0e1fdb90aa5093c52599c9a0639591fbcc1e979b58862d1b" +checksum = "d5f9670065b7cba92771060a4a3925b6650ff67611443ccfccd5aa356f7d5aac" dependencies = [ "bp-messages 0.18.0", "bp-runtime 0.18.0", - "bp-xcm-bridge-hub 0.4.2", - "frame-support 38.2.0", + "bp-xcm-bridge-hub 0.4.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-bridge-messages 0.18.0", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -16472,29 +16227,29 @@ dependencies = [ [[package]] name = "pallet-xcm-bridge-hub-router" -version = "0.15.3" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabf1fdcf451ac79995f11cb9b6a0761924c57bb79442c2d91b3bbefe4dfa081" +checksum = "f3b5347c826b721098ef39afb0d750e621c77538044fc1e865af1a8747824fdf" dependencies = [ "bp-xcm-bridge-hub-router 0.14.1", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", ] [[package]] name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "color-print", "docify", "futures", @@ -16563,7 +16318,7 @@ checksum = "c9460a69f409be27c62161d8b4d36ffc32735d09a4f9097f9c789db0cca7196c" dependencies = [ "cumulus-primitives-core 0.16.0", "cumulus-primitives-utility 0.17.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-asset-tx-payment 38.0.0", @@ -16571,15 +16326,15 @@ dependencies = [ "pallet-authorship 38.0.0", "pallet-balances 39.0.0", "pallet-collator-selection 19.0.0", - "pallet-message-queue 41.0.2", - "pallet-xcm 17.0.1", + "pallet-message-queue 41.0.1", + "pallet-xcm 17.0.0", "parity-scale-codec", "polkadot-primitives 16.0.0", "scale-info", "sp-consensus-aura 0.40.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-parachain-info 0.17.0", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -16644,19 +16399,19 @@ dependencies = [ "cumulus-primitives-core 0.16.0", "cumulus-primitives-parachain-inherent 0.16.0", "cumulus-test-relay-sproof-builder 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-balances 39.0.0", "pallet-collator-selection 19.0.0", "pallet-session 38.0.0", "pallet-timestamp 37.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "parity-scale-codec", "polkadot-parachain-primitives 14.0.0", "sp-consensus-aura 0.40.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-tracing 17.0.1", "staging-parachain-info 0.17.0", "staging-xcm 14.2.0", @@ -16685,9 +16440,9 @@ checksum = "16b56e3a2420138bdb970f84dfb9c774aea80fa0e7371549eedec0d80c209c67" [[package]] name = "parity-db" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" +checksum = "59e9ab494af9e6e813c72170f0d3c1de1500990d62c97cc05cc7576f91aa402f" dependencies = [ "blake2 0.10.6", "crc32fast", @@ -16701,7 +16456,6 @@ dependencies = [ "rand", "siphasher 0.3.11", "snap", - "winapi", ] [[package]] @@ -16710,7 +16464,7 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "bitvec", "byte-slice-cast", "bytes", @@ -16725,9 +16479,9 @@ version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -16755,7 +16509,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ - "proc-macro2 1.0.93", + "proc-macro2 1.0.86", "syn 1.0.109", "synstructure 0.12.6", ] @@ -16790,7 +16544,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.8", ] [[package]] @@ -16809,15 +16563,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.3.5", "smallvec", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -16834,7 +16588,7 @@ checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", "rand_core 0.6.4", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -17178,20 +16932,19 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.15" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" dependencies = [ - "memchr", - "thiserror 2.0.11", + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.15" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" dependencies = [ "pest", "pest_generator", @@ -17199,22 +16952,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.15" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "pest_meta" -version = "2.7.15" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" dependencies = [ "once_cell", "pest", @@ -17223,9 +16976,9 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.5" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", "indexmap 2.7.0", @@ -17233,29 +16986,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.8" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.8" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -17263,17 +17016,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand 2.3.0", - "futures-io", -] - [[package]] name = "pkcs1" version = "0.7.5" @@ -17297,21 +17039,21 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.5.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43467300237085a4f9e864b937cf0bc012cef7740be12be1a48b10d2c8a3701" +checksum = "0e4c7666f2019727f9e8e14bf14456e99c707d780922869f1ba473eee101fa49" [[package]] name = "plotters" -version = "0.3.7" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", @@ -17322,15 +17064,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.7" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" -version = "0.3.7" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] @@ -17417,7 +17159,7 @@ name = "polkadot-availability-distribution" version = "7.0.0" dependencies = [ "assert_matches", - "derive_more 0.99.18", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", @@ -17439,7 +17181,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17471,7 +17213,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring 31.0.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing-gum", ] @@ -17491,7 +17233,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.26", + "clap 4.5.13", "frame-benchmarking-cli", "futures", "log", @@ -17512,7 +17254,7 @@ dependencies = [ "sp-maybe-compressed-blob 11.0.0", "sp-runtime 31.0.1", "substrate-build-script-utils", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -17541,7 +17283,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tokio-util", "tracing-gum", ] @@ -17565,7 +17307,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -17575,7 +17317,7 @@ dependencies = [ "assert_matches", "async-channel 1.9.0", "async-trait", - "derive_more 0.99.18", + "derive_more 0.99.17", "fatality", "futures", "futures-timer", @@ -17596,7 +17338,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17612,7 +17354,7 @@ dependencies = [ "reed-solomon-novelpoly", "sp-core 28.0.0", "sp-trie 29.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -17670,7 +17412,7 @@ dependencies = [ "sp-consensus", "sp-core 28.0.0", "sp-keyring 31.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17693,7 +17435,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring 31.0.0", "sp-maybe-compressed-blob 11.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17704,7 +17446,7 @@ dependencies = [ "assert_matches", "async-trait", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.17", "futures", "futures-timer", "itertools 0.11.0", @@ -17737,7 +17479,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17779,7 +17521,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17808,7 +17550,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keyring 31.0.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17837,7 +17579,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17852,7 +17594,7 @@ dependencies = [ "polkadot-primitives 7.0.0", "polkadot-primitives-test-helpers", "sp-keystore 0.34.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", "wasm-timer", ] @@ -17922,7 +17664,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives 7.0.0", "sp-core 28.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17950,7 +17692,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17966,7 +17708,7 @@ dependencies = [ "polkadot-primitives 7.0.0", "sp-blockchain", "sp-inherents 26.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -17986,7 +17728,7 @@ dependencies = [ "rstest", "sp-core 28.0.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18008,7 +17750,7 @@ dependencies = [ "schnellru", "sp-application-crypto 30.0.0", "sp-keystore 0.34.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18053,7 +17795,7 @@ dependencies = [ "tempfile", "test-parachain-adder", "test-parachain-halt", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing-gum", ] @@ -18077,7 +17819,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-keystore 0.34.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18104,7 +17846,7 @@ dependencies = [ "sp-io 30.0.0", "sp-tracing 16.0.0", "tempfile", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18179,7 +17921,7 @@ dependencies = [ "futures", "futures-timer", "http-body-util", - "hyper 1.5.2", + "hyper 1.3.1", "hyper-util", "log", "parity-scale-codec", @@ -18205,7 +17947,7 @@ dependencies = [ "async-channel 1.9.0", "async-trait", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.17", "fatality", "futures", "hex", @@ -18219,7 +17961,7 @@ dependencies = [ "sc-network-types", "sp-runtime 31.0.1", "strum 0.26.3", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18245,7 +17987,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-maybe-compressed-blob 11.0.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", "zstd 0.12.4", ] @@ -18284,7 +18026,7 @@ version = "7.0.0" dependencies = [ "async-trait", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.17", "fatality", "futures", "orchestra", @@ -18303,7 +18045,7 @@ dependencies = [ "sp-consensus-babe 0.32.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -18312,7 +18054,7 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "derive_more 0.99.18", + "derive_more 0.99.17", "fatality", "futures", "futures-channel", @@ -18343,7 +18085,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keystore 0.34.0", "tempfile", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -18362,7 +18104,7 @@ version = "0.1.0" dependencies = [ "assert_cmd", "async-trait", - "clap 4.5.26", + "clap 4.5.13", "color-print", "cumulus-client-cli", "cumulus-client-collator", @@ -18503,7 +18245,7 @@ name = "polkadot-parachain-primitives" version = "6.0.0" dependencies = [ "bounded-collections", - "derive_more 0.99.18", + "derive_more 0.99.17", "parity-scale-codec", "polkadot-core-primitives 7.0.0", "scale-info", @@ -18520,13 +18262,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52b5648a2e8ce1f9a0f8c41c38def670cefd91932cd793468e1a5b0b0b4e4af1" dependencies = [ "bounded-collections", - "derive_more 0.99.18", + "derive_more 0.99.17", "parity-scale-codec", "polkadot-core-primitives 15.0.0", "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", ] @@ -18555,7 +18297,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-staking 26.0.0", "sp-std 14.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -18581,7 +18323,7 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 34.0.0", ] @@ -18608,7 +18350,7 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -18722,7 +18464,7 @@ dependencies = [ "bitvec", "frame-benchmarking 38.0.0", "frame-election-provider-support 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "libsecp256k1", @@ -18730,7 +18472,7 @@ dependencies = [ "pallet-asset-rate 17.0.0", "pallet-authorship 38.0.0", "pallet-balances 39.0.0", - "pallet-broker 0.17.2", + "pallet-broker 0.17.0", "pallet-election-provider-multi-phase 37.0.0", "pallet-fast-unstake 37.0.0", "pallet-identity 38.0.0", @@ -18738,7 +18480,7 @@ dependencies = [ "pallet-staking 38.0.0", "pallet-staking-reward-fn 22.0.0", "pallet-timestamp 37.0.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "pallet-treasury 37.0.0", "pallet-vesting 38.0.0", "parity-scale-codec", @@ -18754,11 +18496,11 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-npos-elections 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "static_assertions", ] @@ -18794,7 +18536,7 @@ dependencies = [ "assert_matches", "bitflags 1.3.2", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.17", "frame-benchmarking 28.0.0", "frame-support 28.0.0", "frame-support-test", @@ -18855,9 +18597,9 @@ checksum = "bd58e3a17e5df678f5737b018cbfec603af2c93bec56bbb9f8fb8b2b017b54b1" dependencies = [ "bitflags 1.3.2", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.17", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", @@ -18865,8 +18607,8 @@ dependencies = [ "pallet-authorship 38.0.0", "pallet-babe 38.0.0", "pallet-balances 39.0.0", - "pallet-broker 0.17.2", - "pallet-message-queue 41.0.2", + "pallet-broker 0.17.0", + "pallet-message-queue 41.0.1", "pallet-mmr 38.0.0", "pallet-session 38.0.0", "pallet-staking 38.0.0", @@ -18888,7 +18630,7 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-staking 36.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -19286,7 +19028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb819108697967452fa6d8d96ab4c0d48cbaa423b3156499dcb24f1cf95d6775" dependencies = [ "asset-test-utils 18.0.0", - "assets-common 0.18.3", + "assets-common 0.18.0", "binary-merkle-tree 15.0.1", "bp-header-chain 0.18.1", "bp-messages 0.18.0", @@ -19296,11 +19038,11 @@ dependencies = [ "bp-relayers 0.18.0", "bp-runtime 0.18.0", "bp-test-utils 0.18.0", - "bp-xcm-bridge-hub 0.4.2", + "bp-xcm-bridge-hub 0.4.0", "bp-xcm-bridge-hub-router 0.14.1", "bridge-hub-common 0.10.0", "bridge-hub-test-utils 0.18.0", - "bridge-runtime-common 0.18.2", + "bridge-runtime-common 0.18.0", "cumulus-pallet-aura-ext 0.17.0", "cumulus-pallet-dmp-queue 0.17.0", "cumulus-pallet-parachain-system 0.17.1", @@ -19323,7 +19065,7 @@ dependencies = [ "frame-election-provider-support 38.0.0", "frame-executive 38.0.0", "frame-metadata-hash-extension 0.6.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-support-procedural 30.0.4", "frame-system 38.0.0", "frame-system-benchmarking 38.0.0", @@ -19350,8 +19092,8 @@ dependencies = [ "pallet-bridge-grandpa 0.18.0", "pallet-bridge-messages 0.18.0", "pallet-bridge-parachains 0.18.0", - "pallet-bridge-relayers 0.18.2", - "pallet-broker 0.17.2", + "pallet-bridge-relayers 0.18.0", + "pallet-broker 0.17.0", "pallet-child-bounties 37.0.0", "pallet-collator-selection 19.0.0", "pallet-collective 38.0.0", @@ -19359,7 +19101,7 @@ dependencies = [ "pallet-contracts 38.0.0", "pallet-contracts-mock-network 14.0.0", "pallet-conviction-voting 38.0.0", - "pallet-core-fellowship 22.2.0", + "pallet-core-fellowship 22.0.0", "pallet-delegated-staking 5.0.0", "pallet-democracy 38.0.0", "pallet-dev-mode 20.0.0", @@ -19375,7 +19117,7 @@ dependencies = [ "pallet-insecure-randomness-collective-flip 26.0.0", "pallet-lottery 38.0.0", "pallet-membership 38.0.0", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "pallet-migrations 8.0.0", "pallet-mixnet 0.14.0", "pallet-mmr 38.0.0", @@ -19385,16 +19127,16 @@ dependencies = [ "pallet-nfts-runtime-api 24.0.0", "pallet-nis 38.0.0", "pallet-node-authorization 38.0.0", - "pallet-nomination-pools 35.0.2", + "pallet-nomination-pools 35.0.0", "pallet-nomination-pools-benchmarking 36.0.0", - "pallet-nomination-pools-runtime-api 33.0.2", + "pallet-nomination-pools-runtime-api 33.0.0", "pallet-offences 37.0.0", "pallet-offences-benchmarking 38.0.0", "pallet-paged-list 0.16.0", "pallet-parameters 0.9.0", "pallet-preimage 38.0.0", "pallet-proxy 38.0.0", - "pallet-ranked-collective 38.2.0", + "pallet-ranked-collective 38.0.0", "pallet-recovery 38.0.0", "pallet-referenda 38.0.0", "pallet-remark 38.0.0", @@ -19404,7 +19146,7 @@ dependencies = [ "pallet-root-offences 35.0.0", "pallet-root-testing 14.0.0", "pallet-safe-mode 19.0.0", - "pallet-salary 23.2.0", + "pallet-salary 23.0.0", "pallet-scheduler 39.0.0", "pallet-scored-pool 38.0.0", "pallet-session 38.0.0", @@ -19419,7 +19161,7 @@ dependencies = [ "pallet-sudo 38.0.0", "pallet-timestamp 37.0.0", "pallet-tips 37.0.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "pallet-transaction-payment-rpc-runtime-api 38.0.0", "pallet-transaction-storage 37.0.0", "pallet-treasury 37.0.0", @@ -19428,10 +19170,10 @@ dependencies = [ "pallet-utility 38.0.0", "pallet-vesting 38.0.0", "pallet-whitelist 37.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "pallet-xcm-benchmarks 17.0.0", - "pallet-xcm-bridge-hub 0.13.2", - "pallet-xcm-bridge-hub-router 0.15.3", + "pallet-xcm-bridge-hub 0.13.0", + "pallet-xcm-bridge-hub-router 0.15.1", "parachains-common 18.0.0", "parachains-runtimes-test-utils 17.0.0", "polkadot-core-primitives 15.0.0", @@ -19486,7 +19228,7 @@ dependencies = [ "sp-mmr-primitives 34.1.0", "sp-npos-elections 34.0.0", "sp-offchain 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-runtime-interface 28.0.0", "sp-session 36.0.0", "sp-staking 36.0.0", @@ -19504,11 +19246,11 @@ dependencies = [ "sp-weights 31.0.0", "staging-parachain-info 0.17.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", "substrate-bip39 0.6.0", "testnet-parachains-constants 10.0.0", - "xcm-runtime-apis 0.4.2", + "xcm-runtime-apis 0.4.0", ] [[package]] @@ -19685,7 +19427,7 @@ dependencies = [ "docify", "frame-benchmarking 38.0.0", "frame-executive 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "frame-system-benchmarking 38.0.0", "frame-system-rpc-runtime-api 34.0.0", @@ -19702,7 +19444,7 @@ dependencies = [ "sp-inherents 34.0.0", "sp-io 38.0.0", "sp-offchain 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-session 36.0.0", "sp-storage 21.0.0", "sp-transaction-pool 34.0.0", @@ -19818,7 +19560,7 @@ dependencies = [ "staging-xcm 7.0.0", "substrate-prometheus-endpoint", "tempfile", - "thiserror 1.0.69", + "thiserror", "tracing-gum", "westend-runtime", "westend-runtime-constants 7.0.0", @@ -19829,7 +19571,7 @@ dependencies = [ name = "polkadot-statement-distribution" version = "7.0.0" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "assert_matches", "async-channel 1.9.0", "bitvec", @@ -19857,7 +19599,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-staking 26.0.0", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing-gum", ] @@ -19879,7 +19621,7 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.26", + "clap 4.5.13", "clap-num", "color-eyre", "colored", @@ -19981,7 +19723,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.26", + "clap 4.5.13", "color-eyre", "futures", "futures-timer", @@ -20123,7 +19865,7 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "generate-bags", "sp-io 30.0.0", "westend-runtime", @@ -20134,7 +19876,7 @@ name = "polkadot-zombienet-sdk-tests" version = "0.1.0" dependencies = [ "anyhow", - "env_logger 0.11.6", + "env_logger 0.11.3", "log", "parity-scale-codec", "polkadot-primitives 7.0.0", @@ -20277,9 +20019,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ "polkavm-common 0.9.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -20289,21 +20031,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7855353a5a783dd5d09e3b915474bddf66575f5a3cf45dec8d1c5e051ba320dc" dependencies = [ "polkavm-common 0.10.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "polkavm-derive-impl" -version = "0.18.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f2116a92e6e96220a398930f4c8a6cda1264206f3e2034fc9982bfd93f261f7" +checksum = "12d2840cc62a0550156b1676fed8392271ddf2fab4a00661db56231424674624" dependencies = [ "polkavm-common 0.18.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -20313,7 +20055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -20323,7 +20065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9324fe036de37c17829af233b46ef6b5562d4a0c09bb7fdb9f8378856dee30cf" dependencies = [ "polkavm-derive-impl 0.10.0", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -20332,8 +20074,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c16669ddc7433e34c1007d31080b80901e3e8e523cb9d4b441c3910cf9294b" dependencies = [ - "polkavm-derive-impl 0.18.1", - "syn 2.0.96", + "polkavm-derive-impl 0.18.0", + "syn 2.0.87", ] [[package]] @@ -20342,7 +20084,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ - "gimli 0.28.1", + "gimli 0.28.0", "hashbrown 0.14.5", "log", "object 0.32.2", @@ -20357,10 +20099,10 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d704edfe7bdcc876784f19436d53d515b65eb07bc9a0fae77085d552c2dbbb5" dependencies = [ - "gimli 0.28.1", + "gimli 0.28.0", "hashbrown 0.14.5", "log", - "object 0.36.7", + "object 0.36.1", "polkavm-common 0.10.0", "regalloc2 0.9.3", "rustc-demangle", @@ -20376,7 +20118,7 @@ dependencies = [ "gimli 0.31.1", "hashbrown 0.14.5", "log", - "object 0.36.7", + "object 0.36.1", "polkavm-common 0.18.0", "regalloc2 0.9.3", "rustc-demangle", @@ -20418,17 +20160,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.4" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.43", + "rustix 0.38.42", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -20438,27 +20179,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "universal-hash", ] [[package]] name = "polyval" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "portpicker" @@ -20476,23 +20217,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "pprof2" -version = "0.13.1" +name = "pprof" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8961ed0a916b512e565f8070eb0dfa05773dd140160b45ac9a5ad339b557adeb" +checksum = "978385d59daf9269189d052ca8a84c1acfd0715c0599a5d5188d4acc078ca46a" dependencies = [ "backtrace", "cfg-if", "findshlibs", "libc", "log", - "nix 0.27.1", + "nix 0.26.4", "once_cell", "parking_lot 0.12.3", "smallvec", "symbolic-demangle", "tempfile", - "thiserror 2.0.11", + "thiserror", ] [[package]] @@ -20510,12 +20251,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "predicates" @@ -20533,26 +20271,27 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.3" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" dependencies = [ "anstyle", "difflib", + "itertools 0.10.5", "predicates-core", ] [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", @@ -20560,9 +20299,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", "yansi", @@ -20570,12 +20309,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.29" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ - "proc-macro2 1.0.93", - "syn 2.0.96", + "proc-macro2 1.0.86", + "syn 2.0.87", ] [[package]] @@ -20616,31 +20355,31 @@ checksum = "a172e6cc603231f2cf004232eabcecccc0da53ba576ab286ef7baa0cfc7927ad" dependencies = [ "coarsetime", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.17", "futures", "futures-timer", "nanorand", - "thiserror 1.0.69", + "thiserror", "tracing", ] [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "thiserror 1.0.69", - "toml 0.5.11", + "once_cell", + "toml_edit 0.19.15", ] [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.21.0", ] [[package]] @@ -20650,8 +20389,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "version_check", ] @@ -20662,8 +20401,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "version_check", ] @@ -20673,8 +20412,8 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", ] [[package]] @@ -20684,20 +20423,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ "proc-macro-error-attr2", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro-warning" -version = "1.0.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" +checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -20711,9 +20456,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -20724,13 +20469,13 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "chrono", "flate2", "hex", "lazy_static", "procfs-core", - "rustix 0.38.43", + "rustix 0.38.42", ] [[package]] @@ -20739,23 +20484,23 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "chrono", "hex", ] [[package]] name = "prometheus" -version = "0.13.4" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d33c28a30771f7f96db69893f78b857f7450d7e0237e9c8fc6427a81bae7ed1" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ "cfg-if", "fnv", "lazy_static", "memchr", "parking_lot 0.12.3", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -20776,32 +20521,32 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "prometheus-parse" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "811031bea65e5a401fb2e1f37d802cca6601e204ac463809a3189352d13b78a5" +checksum = "0c2aa5feb83bf4b2c8919eaf563f51dbab41183de73ba2353c0e03cd7b6bd892" dependencies = [ "chrono", - "itertools 0.12.1", + "itertools 0.10.5", "once_cell", "regex", ] [[package]] name = "proptest" -version = "1.5.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.8.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", @@ -20835,20 +20580,21 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0fef6c4230e4ccf618a35c59d7ede15dea37de8427500f50aff708806e42ec" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", - "prost-derive 0.13.4", + "prost-derive 0.13.2", ] [[package]] name = "prost-build" -version = "0.13.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b" +checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ + "bytes", "heck 0.5.0", "itertools 0.13.0", "log", @@ -20856,10 +20602,10 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost 0.13.4", + "prost 0.13.2", "prost-types", "regex", - "syn 2.0.96", + "syn 2.0.87", "tempfile", ] @@ -20871,8 +20617,8 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -20884,80 +20630,81 @@ checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", "itertools 0.12.1", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "prost-derive" -version = "0.13.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", "itertools 0.13.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "prost-types" -version = "0.13.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2f1e56baa61e93533aebc21af4d2134b70f66275e0fcdf3cbe43d77ff7e8fc" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ - "prost 0.13.4", + "prost 0.13.2", ] [[package]] name = "psm" -version = "0.1.24" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] [[package]] name = "pyroscope" -version = "0.5.8" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a5f63b0d2727095db59045e6a0ef3259b28b90d481ae88f0e3d866d0234ce8" +checksum = "ac8a53ce01af1087eaeee6ce7c4fbf50ea4040ab1825c0115c4bafa039644ba9" dependencies = [ + "json", "libc", "libflate", "log", "names", "prost 0.11.9", - "reqwest 0.12.12", - "serde_json", - "thiserror 1.0.69", + "reqwest 0.11.27", + "thiserror", "url", "winapi", ] [[package]] name = "pyroscope_pprofrs" -version = "0.2.8" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614a25777053da6bdca9d84a67892490b5a57590248dbdee3d7bf0716252af70" +checksum = "43f010b2a981a7f8449a650f25f309e520b5206ea2d89512dcb146aaa5518ff4" dependencies = [ "log", - "pprof2", + "pprof", "pyroscope", - "thiserror 1.0.69", + "thiserror", ] [[package]] name = "quanta" -version = "0.12.5" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" dependencies = [ "crossbeam-utils", "libc", + "mach2", "once_cell", "raw-cpuid", "wasi", @@ -20998,7 +20745,7 @@ dependencies = [ "asynchronous-codec 0.7.0", "bytes", "quick-protobuf 0.8.1", - "thiserror 1.0.69", + "thiserror", "unsigned-varint 0.8.0", ] @@ -21026,55 +20773,51 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.6" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "futures-io", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.0", - "rustls 0.23.21", - "socket2 0.5.8", - "thiserror 2.0.11", + "rustc-hash 2.0.0", + "rustls 0.23.18", + "socket2 0.5.7", + "thiserror", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.9" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", - "getrandom", "rand", "ring 0.17.8", - "rustc-hash 2.1.0", - "rustls 0.23.21", - "rustls-pki-types", + "rustc-hash 2.0.0", + "rustls 0.23.18", "slab", - "thiserror 2.0.11", + "thiserror", "tinyvec", "tracing", - "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ - "cfg_aliases 0.2.1", "libc", "once_cell", - "socket2 0.5.8", + "socket2 0.5.7", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -21088,11 +20831,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.38" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.93", + "proc-macro2 1.0.86", ] [[package]] @@ -21168,11 +20911,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.3.0" +version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ - "bitflags 2.8.0", + "bitflags 1.3.2", ] [[package]] @@ -21254,24 +20997,33 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "libredox", - "thiserror 1.0.69", + "redox_syscall 0.2.16", + "thiserror", ] [[package]] @@ -21280,10 +21032,10 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87413ebb313323d431e85d0afc5a68222aaed972843537cbfe5f061cf1b4bcab" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.17", "fs-err", "static_init", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -21301,9 +21053,9 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -21339,7 +21091,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", + "regex-automata 0.4.8", "regex-syntax 0.8.5", ] @@ -21354,9 +21106,15 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" + +[[package]] +name = "regex-automata" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -21377,9 +21135,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" -version = "1.9.3" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" [[package]] name = "relay-substrate-client" @@ -21417,7 +21175,7 @@ dependencies = [ "sp-trie 29.0.0", "sp-version 29.0.0", "staging-xcm 7.0.0", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -21442,7 +21200,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "sysinfo", - "thiserror 1.0.69", + "thiserror", "time", "tokio", ] @@ -21451,7 +21209,7 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "frame-system 28.0.0", "log", "pallet-bags-list-remote-tests", @@ -21474,9 +21232,10 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.32", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.29", + "hyper-rustls 0.24.2", "hyper-tls", "ipnet", "js-sys", @@ -21486,38 +21245,41 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 1.0.4", + "rustls 0.21.7", + "rustls-pemfile 1.0.3", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration 0.5.1", + "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 0.25.2", "winreg", ] [[package]] name = "reqwest" -version = "0.12.12" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.2.0", - "http-body 1.0.1", + "http 1.1.0", + "http-body 1.0.0", "http-body-util", - "hyper 1.5.2", - "hyper-rustls 0.27.5", + "hyper 1.3.1", + "hyper-rustls 0.27.3", "hyper-util", "ipnet", "js-sys", @@ -21527,22 +21289,21 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.21", - "rustls-pemfile 2.2.0", + "rustls 0.23.18", + "rustls-pemfile 2.0.0", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper 1.0.1", "tokio", - "tokio-rustls 0.26.1", - "tower 0.5.2", + "tokio-rustls 0.26.0", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.7", + "webpki-roots 0.26.3", "windows-registry", ] @@ -21563,7 +21324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ "hmac 0.12.1", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -21571,12 +21332,12 @@ name = "ring" version = "0.1.0" source = "git+https://github.com/w3f/ring-proof?rev=665f5f5#665f5f51af5734c7b6d90b985dd6861d4c5b4752" dependencies = [ - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", - "ark-poly 0.4.2", + "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "blake2 0.10.6", "common", "fflonk", @@ -21854,15 +21615,15 @@ version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1ec6683a2e52fe3be2eaf942a80619abd99eb36e973c5ab4489a2f3b100db5c" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "polkadot-primitives 16.0.0", "polkadot-runtime-common 17.0.0", "smallvec", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -21900,20 +21661,20 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.3.1" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "winapi", ] [[package]] name = "rsa" -version = "0.9.7" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +checksum = "af6c4b23d99685a1408194da11270ef8e9809aff951cc70ec9b17350b087e474" dependencies = [ "const-oid", "digest 0.10.7", @@ -21925,7 +21686,7 @@ dependencies = [ "rand_core 0.6.4", "signature", "spki", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -21938,7 +21699,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.1", + "rustc_version 0.4.0", ] [[package]] @@ -21949,57 +21710,52 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", "relative-path", - "rustc_version 0.4.1", - "syn 2.0.96", + "rustc_version 0.4.0", + "syn 2.0.87", "unicode-ident", ] [[package]] name = "rtnetlink" -version = "0.13.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a552eb82d19f38c3beed3f786bd23aa434ceb9ac43ab44419ca6d67a7e186c0" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" dependencies = [ "futures", "log", - "netlink-packet-core", "netlink-packet-route", - "netlink-packet-utils", "netlink-proto", - "netlink-sys", - "nix 0.26.4", - "thiserror 1.0.69", + "nix 0.24.3", + "thiserror", "tokio", ] [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", - "windows-sys 0.48.0", + "winapi", ] [[package]] name = "ruint" -version = "1.12.4" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp 0.3.1", - "fastrlp 0.4.0", + "fastrlp", "num-bigint", - "num-integer", "num-traits", "parity-scale-codec", "primitive-types 0.12.2", @@ -22020,9 +21776,9 @@ checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" @@ -22032,9 +21788,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc-hex" @@ -22062,11 +21818,11 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.24", + "semver 1.0.18", ] [[package]] @@ -22080,9 +21836,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.17" +version = "0.36.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" dependencies = [ "bitflags 1.3.2", "errno", @@ -22094,9 +21850,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.28" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ "bitflags 1.3.2", "errno", @@ -22108,14 +21864,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.15", + "linux-raw-sys 0.4.14", "windows-sys 0.59.0", ] @@ -22132,13 +21888,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.12" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ "log", - "ring 0.17.8", - "rustls-webpki 0.101.7", + "ring 0.16.20", + "rustls-webpki 0.101.4", "sct", ] @@ -22152,22 +21908,22 @@ dependencies = [ "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] [[package]] name = "rustls" -version = "0.23.21" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "log", "once_cell", "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -22178,98 +21934,97 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.4", + "rustls-pemfile 1.0.3", "schannel", - "security-framework 2.11.1", + "security-framework", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile 2.2.0", + "rustls-pemfile 2.0.0", "rustls-pki-types", "schannel", - "security-framework 2.11.1", + "security-framework", ] [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", + "rustls-pemfile 2.0.0", "rustls-pki-types", "schannel", - "security-framework 3.2.0", + "security-framework", ] [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ "base64 0.21.7", ] [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" dependencies = [ + "base64 0.21.7", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" -dependencies = [ - "web-time", -] +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-platform-verifier" -version = "0.3.4" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" dependencies = [ - "core-foundation 0.9.4", + "core-foundation", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.21", - "rustls-native-certs 0.7.3", + "rustls 0.23.18", + "rustls-native-certs 0.7.0", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", - "webpki-roots 0.26.7", + "webpki-roots 0.26.3", "winapi", ] [[package]] name = "rustls-platform-verifier-android" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +checksum = "84e217e7fdc8466b5b35d30f8c0a30febd29173df4a3a0c2115d306b9c4117ad" [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -22285,9 +22040,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -22319,7 +22074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" dependencies = [ "byteorder", - "derive_more 0.99.18", + "derive_more 0.99.17", ] [[package]] @@ -22335,9 +22090,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "safe-mix" @@ -22350,9 +22105,9 @@ dependencies = [ [[package]] name = "safe_arch" -version = "0.7.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" dependencies = [ "bytemuck", ] @@ -22382,7 +22137,7 @@ dependencies = [ "log", "sp-core 28.0.0", "sp-wasm-interface 20.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22394,7 +22149,7 @@ dependencies = [ "log", "sp-core 33.0.1", "sp-wasm-interface 21.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22406,7 +22161,7 @@ dependencies = [ "log", "sp-core 34.0.0", "sp-wasm-interface 21.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22419,7 +22174,7 @@ dependencies = [ "ip_network", "linked_hash_set", "log", - "multihash 0.19.3", + "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", "prost-build", @@ -22437,7 +22192,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22486,10 +22241,10 @@ name = "sc-chain-spec" version = "28.0.0" dependencies = [ "array-bytes", - "clap 4.5.26", + "clap 4.5.13", "docify", "log", - "memmap2 0.9.5", + "memmap2 0.9.3", "parity-scale-codec", "regex", "sc-chain-spec-derive", @@ -22517,10 +22272,10 @@ dependencies = [ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -22529,7 +22284,7 @@ version = "0.36.0" dependencies = [ "array-bytes", "chrono", - "clap 4.5.26", + "clap 4.5.13", "fdlimit", "futures", "futures-timer", @@ -22563,7 +22318,7 @@ dependencies = [ "sp-tracing 16.0.0", "sp-version 29.0.0", "tempfile", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22593,7 +22348,7 @@ dependencies = [ "sp-trie 29.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22650,7 +22405,7 @@ dependencies = [ "sp-state-machine 0.35.0", "sp-test-primitives", "substrate-prometheus-endpoint", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -22687,7 +22442,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22729,7 +22484,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22757,7 +22512,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22800,7 +22555,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.69", + "thiserror", "tokio", "wasm-timer", ] @@ -22823,7 +22578,7 @@ dependencies = [ "sp-core 28.0.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22885,7 +22640,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22909,7 +22664,7 @@ dependencies = [ "sp-keyring 31.0.0", "sp-runtime 31.0.1", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22947,7 +22702,7 @@ dependencies = [ "substrate-prometheus-endpoint", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -22972,7 +22727,7 @@ dependencies = [ "sp-inherents 26.0.0", "sp-runtime 31.0.1", "substrate-prometheus-endpoint", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23033,7 +22788,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "wat", ] @@ -23053,7 +22808,7 @@ dependencies = [ "sp-core 33.0.1", "sp-externalities 0.28.0", "sp-io 36.0.0", - "sp-panic-handler 13.0.1", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-runtime-interface 27.0.0", "sp-trie 35.0.0", "sp-version 35.0.0", @@ -23077,7 +22832,7 @@ dependencies = [ "sp-core 34.0.0", "sp-externalities 0.29.0", "sp-io 38.0.0", - "sp-panic-handler 13.0.1", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-runtime-interface 28.0.0", "sp-trie 37.0.0", "sp-version 37.0.0", @@ -23093,7 +22848,7 @@ dependencies = [ "sc-allocator 23.0.0", "sp-maybe-compressed-blob 11.0.0", "sp-wasm-interface 20.0.0", - "thiserror 1.0.69", + "thiserror", "wasm-instrument", ] @@ -23107,7 +22862,7 @@ dependencies = [ "sc-allocator 28.0.0", "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-wasm-interface 21.0.1", - "thiserror 1.0.69", + "thiserror", "wasm-instrument", ] @@ -23121,7 +22876,7 @@ dependencies = [ "sc-allocator 29.0.0", "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-wasm-interface 21.0.1", - "thiserror 1.0.69", + "thiserror", "wasm-instrument", ] @@ -23171,7 +22926,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "rustix 0.36.17", + "rustix 0.36.15", "sc-allocator 23.0.0", "sc-executor-common 0.29.0", "sc-runtime-test", @@ -23194,7 +22949,7 @@ dependencies = [ "libc", "log", "parking_lot 0.12.3", - "rustix 0.36.17", + "rustix 0.36.15", "sc-allocator 28.0.0", "sc-executor-common 0.34.0", "sp-runtime-interface 27.0.0", @@ -23213,7 +22968,7 @@ dependencies = [ "libc", "log", "parking_lot 0.12.3", - "rustix 0.36.17", + "rustix 0.36.15", "sc-allocator 29.0.0", "sc-executor-common 0.35.0", "sp-runtime-interface 28.0.0", @@ -23248,7 +23003,7 @@ dependencies = [ "sp-core 28.0.0", "sp-keystore 0.34.0", "tempfile", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23256,14 +23011,14 @@ name = "sc-mixnet" version = "0.4.0" dependencies = [ "array-bytes", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "blake2 0.10.6", "bytes", "futures", "futures-timer", "log", "mixnet", - "multiaddr 0.18.2", + "multiaddr 0.18.1", "parity-scale-codec", "parking_lot 0.12.3", "sc-client-api", @@ -23276,7 +23031,7 @@ dependencies = [ "sp-keystore 0.34.0", "sp-mixnet 0.4.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23334,7 +23089,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", "tokio-test", @@ -23403,7 +23158,7 @@ dependencies = [ "sp-blockchain", "sp-core 28.0.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23460,7 +23215,7 @@ dependencies = [ "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", ] @@ -23525,11 +23280,11 @@ dependencies = [ "libp2p-kad", "litep2p", "log", - "multiaddr 0.18.2", - "multihash 0.19.3", + "multiaddr 0.18.1", + "multihash 0.19.1", "quickcheck", "rand", - "thiserror 1.0.69", + "thiserror", "zeroize", ] @@ -23544,8 +23299,8 @@ dependencies = [ "futures", "futures-timer", "http-body-util", - "hyper 1.5.2", - "hyper-rustls 0.27.5", + "hyper 1.3.1", + "hyper-rustls 0.27.3", "hyper-util", "log", "num_cpus", @@ -23553,7 +23308,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "rand", - "rustls 0.23.21", + "rustls 0.23.18", "sc-block-builder", "sc-client-api", "sc-client-db", @@ -23641,7 +23396,7 @@ dependencies = [ "sp-rpc", "sp-runtime 31.0.1", "sp-version 29.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23652,9 +23407,9 @@ dependencies = [ "forwarded-header-value", "futures", "governor", - "http 1.2.0", + "http 1.1.0", "http-body-util", - "hyper 1.5.2", + "hyper 1.3.1", "ip_network", "jsonrpsee", "log", @@ -23663,7 +23418,7 @@ dependencies = [ "serde_json", "substrate-prometheus-endpoint", "tokio", - "tower 0.4.13", + "tower", "tower-http 0.5.2", ] @@ -23707,7 +23462,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", ] @@ -23739,7 +23494,7 @@ dependencies = [ "sp-version 29.0.0", "sp-wasm-interface 20.0.0", "subxt", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -23801,7 +23556,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "tempfile", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", "tracing-futures", @@ -23877,11 +23632,11 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "fs4", "log", "sp-core 28.0.0", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -23900,14 +23655,14 @@ dependencies = [ "serde_json", "sp-blockchain", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] name = "sc-sysinfo" version = "27.0.0" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.17", "futures", "libc", "log", @@ -23938,7 +23693,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "wasm-timer", ] @@ -23965,20 +23720,20 @@ dependencies = [ "sp-rpc", "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "thiserror 1.0.69", + "thiserror", "tracing", - "tracing-log", - "tracing-subscriber", + "tracing-log 0.2.0", + "tracing-subscriber 0.3.18", ] [[package]] name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -24014,7 +23769,7 @@ dependencies = [ "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", ] @@ -24032,7 +23787,7 @@ dependencies = [ "sp-blockchain", "sp-core 28.0.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -24067,7 +23822,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.17", "parity-scale-codec", "scale-bits", "scale-type-resolver", @@ -24096,9 +23851,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed9401effa946b493f9f84dc03714cca98119b230497df6f3df6b84a2b03648" dependencies = [ "darling", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -24123,10 +23878,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "102fbc6236de6c53906c0b262f12c7aa69c2bdc604862c12728f5f4d370bc137" dependencies = [ "darling", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -24149,10 +23904,10 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -24171,11 +23926,11 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc4c70c7fea2eef1740f0081d3fe385d8bee1eef11e9272d3bec7dc8e5438e0" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "scale-info", - "syn 2.0.96", - "thiserror 1.0.69", + "syn 2.0.87", + "thiserror", ] [[package]] @@ -24200,18 +23955,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "763f8cd0d4c71ed8389c90cb8100cba87e763bd01a8e614d4f0af97bcd50a161" dependencies = [ "dyn-clone", "schemars_derive", @@ -24221,21 +23976,21 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "serde_derive_internals", - "syn 2.0.96", + "syn 1.0.109", ] [[package]] name = "schnellru" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -24249,7 +24004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d" dependencies = [ "arrayref", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "curve25519-dalek-ng", "merlin", "rand_core 0.6.4", @@ -24266,17 +24021,23 @@ checksum = "8de18f6d8ba0aad7045f5feae07ec29899c1112584a38509a84ad7b04451eaa0" dependencies = [ "aead", "arrayref", - "arrayvec 0.7.6", + "arrayvec 0.7.4", "curve25519-dalek 4.1.3", "getrandom_or_panic", "merlin", "rand_core 0.6.4", "serde_bytes", "sha2 0.10.8", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" @@ -24303,12 +24064,12 @@ dependencies = [ [[package]] name = "sct" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -24322,7 +24083,7 @@ dependencies = [ "generic-array 0.14.7", "pkcs8", "serdect", - "subtle 2.6.1", + "subtle 2.5.0", "zeroize", ] @@ -24394,36 +24155,23 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.9.4", + "bitflags 2.6.0", + "core-foundation", "core-foundation-sys", "libc", "num-bigint", "security-framework-sys", ] -[[package]] -name = "security-framework" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.10.0", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -24453,14 +24201,14 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.3", + "semver-parser 0.10.2", ] [[package]] name = "semver" -version = "1.0.24" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" dependencies = [ "serde", ] @@ -24473,9 +24221,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "semver-parser" -version = "0.10.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" dependencies = [ "pest", ] @@ -24494,9 +24242,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.217" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -24522,33 +24270,33 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.15" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.217" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "serde_derive_internals" -version = "0.29.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] @@ -24562,9 +24310,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.7.0", "itoa", @@ -24575,9 +24323,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -24627,7 +24375,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", ] [[package]] @@ -24651,7 +24399,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", ] [[package]] @@ -24674,7 +24422,7 @@ dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", "keccak", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", ] [[package]] @@ -24699,9 +24447,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.7" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] @@ -24712,20 +24460,30 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "2.2.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", "rand_core 0.6.4", @@ -24733,9 +24491,9 @@ dependencies = [ [[package]] name = "simba" -version = "0.9.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" dependencies = [ "approx", "num-complex", @@ -24750,7 +24508,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c80e565e7dcc4f1ef247e2f395550d4cf7d777746d5988e7e4e3156b71077fc" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", ] [[package]] @@ -24810,14 +24568,14 @@ dependencies = [ "enumn", "parity-scale-codec", "paste", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] name = "slotmap" -version = "1.0.7" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" dependencies = [ "version_check", ] @@ -24853,8 +24611,8 @@ dependencies = [ "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-net 1.8.0", - "async-process 1.8.1", + "async-net 1.7.0", + "async-process 1.7.0", "blocking", "futures-lite 1.13.0", ] @@ -24865,15 +24623,24 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.3.0", "async-executor", "async-fs 2.1.2", - "async-io 2.4.0", + "async-io 2.3.3", "async-lock 3.4.0", "async-net 2.0.0", "async-process 2.3.0", "blocking", - "futures-lite 2.6.0", + "futures-lite 2.3.0", +] + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", ] [[package]] @@ -24882,7 +24649,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0bb30cf57b7b5f6109ce17c3164445e2d6f270af2cb48f6e4d31c2967c9a9f5" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "async-lock 2.8.0", "atomic-take", "base64 0.21.7", @@ -24891,7 +24658,7 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.17", "ed25519-zebra 4.0.3", "either", "event-listener 2.5.3", @@ -24936,7 +24703,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "966e72d77a3b2171bb7461d0cb91f43670c63558c62d7cf42809cae6c8b6b818" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "async-lock 3.4.0", "atomic-take", "base64 0.22.1", @@ -24945,12 +24712,12 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.17", "ed25519-zebra 4.0.3", "either", - "event-listener 5.4.0", + "event-listener 5.3.1", "fnv", - "futures-lite 2.6.0", + "futures-lite 2.3.0", "futures-util", "hashbrown 0.14.5", "hex", @@ -24977,7 +24744,7 @@ dependencies = [ "siphasher 1.0.1", "slab", "smallvec", - "soketto 0.8.1", + "soketto 0.8.0", "twox-hash", "wasmi 0.32.3", "x25519-dalek", @@ -24994,7 +24761,7 @@ dependencies = [ "async-lock 2.8.0", "base64 0.21.7", "blake2-rfc", - "derive_more 0.99.18", + "derive_more 0.99.17", "either", "event-listener 2.5.3", "fnv", @@ -25005,7 +24772,7 @@ dependencies = [ "hex", "itertools 0.11.0", "log", - "lru 0.11.1", + "lru 0.11.0", "no-std-net", "parking_lot 0.12.3", "pin-project", @@ -25026,23 +24793,23 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a33b06891f687909632ce6a4e3fd7677b24df930365af3d0bcb078310129f3f" dependencies = [ - "async-channel 2.3.1", + "async-channel 2.3.0", "async-lock 3.4.0", "base64 0.22.1", "blake2-rfc", "bs58", - "derive_more 0.99.18", + "derive_more 0.99.17", "either", - "event-listener 5.4.0", + "event-listener 5.3.1", "fnv", "futures-channel", - "futures-lite 2.6.0", + "futures-lite 2.3.0", "futures-util", "hashbrown 0.14.5", "hex", "itertools 0.13.0", "log", - "lru 0.12.5", + "lru 0.12.3", "parking_lot 0.12.3", "pin-project", "rand", @@ -25058,9 +24825,9 @@ dependencies = [ [[package]] name = "snap" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" @@ -25074,9 +24841,9 @@ dependencies = [ "curve25519-dalek 4.1.3", "rand_core 0.6.4", "ring 0.17.8", - "rustc_version 0.4.1", + "rustc_version 0.4.0", "sha2 0.10.8", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -25118,7 +24885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10bd720997e558beb556d354238fa90781deb38241cf31c1b6368738ef21c279" dependencies = [ "byte-slice-cast", - "frame-support 38.2.0", + "frame-support 38.0.0", "hex", "parity-scale-codec", "rlp 0.5.2", @@ -25128,7 +24895,7 @@ dependencies = [ "snowbridge-milagro-bls", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ssz_rs", "ssz_rs_derive", @@ -25165,7 +24932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6be61e4db95d1e253a1d5e722953b2d2f6605e5f9761f0a919e5d3fbdbff9da9" dependencies = [ "ethabi-decode 1.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "hex-literal", "parity-scale-codec", @@ -25176,10 +24943,10 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -25221,7 +24988,7 @@ dependencies = [ "serde", "serde-big-array", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -25264,7 +25031,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -25285,7 +25052,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d27b8d9cb8022637a5ce4f52692520fa75874f393e04ef5cd75bd8795087f6" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "snowbridge-core 0.10.0", "snowbridge-outbound-queue-merkle-tree 0.9.1", @@ -25327,7 +25094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d53d32d8470c643f9f8c1f508e1e34263f76297e4c9150e10e8f2e0b63992e1" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-timestamp 37.0.0", @@ -25340,7 +25107,7 @@ dependencies = [ "snowbridge-pallet-ethereum-client-fixtures 0.18.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions", ] @@ -25406,7 +25173,7 @@ dependencies = [ "alloy-primitives 0.4.2", "alloy-sol-types 0.4.2", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "pallet-balances 39.0.0", @@ -25419,7 +25186,7 @@ dependencies = [ "snowbridge-router-primitives 0.16.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -25481,7 +25248,7 @@ dependencies = [ "bridge-hub-common 0.10.0", "ethabi-decode 1.0.0", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", @@ -25491,7 +25258,7 @@ dependencies = [ "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -25528,7 +25295,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "674db59b3c8013382e5c07243ad9439b64d81d2e8b3c4f08d752b55aa5de697e" dependencies = [ "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "log", "parity-scale-codec", @@ -25536,7 +25303,7 @@ dependencies = [ "snowbridge-core 0.10.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -25566,7 +25333,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "025f1e6805753821b1db539369f1fb183fd59fd5df7023f7633a4c0cfd3e62f9" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "hex-literal", "log", "parity-scale-codec", @@ -25574,7 +25341,7 @@ dependencies = [ "snowbridge-core 0.10.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -25601,14 +25368,14 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6093f0e73d6cfdd2eea8712155d1d75b5063fc9b1d854d2665b097b4bb29570d" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "log", "parity-scale-codec", "snowbridge-core 0.10.0", "sp-arithmetic 26.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -25649,15 +25416,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "893480d6cde2489051c65efb5d27fa87efe047b3b61216d8e27bb2f0509b7faf" dependencies = [ "cumulus-pallet-parachain-system 0.17.1", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "pallet-balances 39.0.0", "pallet-collator-selection 19.0.0", - "pallet-message-queue 41.0.2", + "pallet-message-queue 41.0.1", "pallet-session 38.0.0", "pallet-timestamp 37.0.0", "pallet-utility 38.0.0", - "pallet-xcm 17.0.1", + "pallet-xcm 17.0.0", "parachains-runtimes-test-utils 17.0.0", "parity-scale-codec", "snowbridge-core 0.10.0", @@ -25668,7 +25435,7 @@ dependencies = [ "sp-core 34.0.0", "sp-io 38.0.0", "sp-keyring 39.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-parachain-info 0.17.0", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -25700,9 +25467,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.10" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -25710,9 +25477,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.8" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -25735,14 +25502,14 @@ dependencies = [ [[package]] name = "soketto" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" dependencies = [ "base64 0.22.1", "bytes", "futures", - "http 1.2.0", + "http 1.1.0", "httparse", "log", "rand", @@ -25753,7 +25520,7 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "frame-benchmarking-cli", "frame-metadata-hash-extension 0.1.0", "frame-system 28.0.0", @@ -25851,7 +25618,7 @@ dependencies = [ "sp-test-primitives", "sp-trie 29.0.0", "sp-version 29.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -25874,7 +25641,7 @@ dependencies = [ "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 35.0.0", "sp-version 35.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -25892,12 +25659,12 @@ dependencies = [ "sp-core 34.0.0", "sp-externalities 0.29.0", "sp-metadata-ir 0.7.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-runtime-interface 28.0.0", "sp-state-machine 0.43.0", "sp-trie 37.0.0", "sp-version 37.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -25908,10 +25675,10 @@ dependencies = [ "assert_matches", "blake2 0.10.6", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -25923,10 +25690,10 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -25938,10 +25705,10 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -26081,7 +25848,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-bls12-381-ext", - "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-crypto-ec-utils 0.4.1", ] [[package]] @@ -26090,7 +25857,7 @@ version = "0.4.2" source = "git+https://github.com/paritytech/arkworks-substrate#caa2eed74beb885dd07c7db5f916f2281dad818f" dependencies = [ "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils 0.10.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-crypto-ec-utils 0.4.1", ] [[package]] @@ -26114,7 +25881,7 @@ dependencies = [ "scale-info", "sp-api 34.0.0", "sp-application-crypto 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -26134,7 +25901,7 @@ checksum = "74738809461e3d4bd707b5b94e0e0c064a623a74a6a8fe5c98514417a02858dd" dependencies = [ "sp-api 34.0.0", "sp-inherents 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -26151,7 +25918,7 @@ dependencies = [ "sp-database", "sp-runtime 31.0.1", "sp-state-machine 0.35.0", - "thiserror 1.0.69", + "thiserror", "tracing", ] @@ -26167,7 +25934,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-state-machine 0.35.0", "sp-test-primitives", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -26198,7 +25965,7 @@ dependencies = [ "sp-application-crypto 38.0.0", "sp-consensus-slots 0.40.1", "sp-inherents 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-timestamp 34.0.0", ] @@ -26234,7 +26001,7 @@ dependencies = [ "sp-consensus-slots 0.40.1", "sp-core 34.0.0", "sp-inherents 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-timestamp 34.0.0", ] @@ -26276,7 +26043,7 @@ dependencies = [ "sp-io 38.0.0", "sp-keystore 0.40.0", "sp-mmr-primitives 34.1.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "strum 0.26.3", ] @@ -26312,7 +26079,7 @@ dependencies = [ "sp-application-crypto 38.0.0", "sp-core 34.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -26334,7 +26101,7 @@ dependencies = [ "parity-scale-codec", "sp-api 34.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -26416,7 +26183,7 @@ dependencies = [ "sp-storage 19.0.0", "ss58-registry", "substrate-bip39 0.4.7", - "thiserror 1.0.69", + "thiserror", "tracing", "w3f-bls", "zeroize", @@ -26463,7 +26230,7 @@ dependencies = [ "sp-storage 21.0.0", "ss58-registry", "substrate-bip39 0.6.0", - "thiserror 1.0.69", + "thiserror", "tracing", "w3f-bls", "zeroize", @@ -26510,7 +26277,7 @@ dependencies = [ "sp-storage 21.0.0", "ss58-registry", "substrate-bip39 0.6.0", - "thiserror 1.0.69", + "thiserror", "tracing", "w3f-bls", "zeroize", @@ -26557,7 +26324,7 @@ dependencies = [ "sp-storage 21.0.0", "ss58-registry", "substrate-bip39 0.6.0", - "thiserror 1.0.69", + "thiserror", "tracing", "w3f-bls", "zeroize", @@ -26597,7 +26364,8 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" -version = "0.10.0" +version = "0.4.1" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -26605,19 +26373,19 @@ dependencies = [ "ark-bls12-381-ext", "ark-bw6-761", "ark-bw6-761-ext", - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale", - "sp-runtime-interface 24.0.0", + "ark-scale 0.0.11", + "sp-runtime-interface 17.0.0", + "sp-std 8.0.0", ] [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -26625,13 +26393,13 @@ dependencies = [ "ark-bls12-381-ext", "ark-bw6-761", "ark-bw6-761-ext", - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale", - "sp-runtime-interface 24.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "ark-scale 0.0.12", + "sp-runtime-interface 24.0.0", ] [[package]] @@ -26646,12 +26414,12 @@ dependencies = [ "ark-bls12-381-ext", "ark-bw6-761", "ark-bw6-761-ext", - "ark-ec 0.4.2", + "ark-ec", "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", "ark-ed-on-bls12-381-bandersnatch", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale", + "ark-scale 0.0.12", "sp-runtime-interface 28.0.0", ] @@ -26687,9 +26455,9 @@ dependencies = [ name = "sp-crypto-hashing-proc-macro" version = "0.1.0" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "sp-crypto-hashing 0.1.0", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -26698,9 +26466,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -26713,51 +26481,52 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "14.0.0" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sp-externalities" -version = "0.25.0" +version = "0.19.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 19.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", ] [[package]] name = "sp-externalities" version = "0.25.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "environmental", "parity-scale-codec", - "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-storage 19.0.0", ] [[package]] @@ -26803,7 +26572,7 @@ dependencies = [ "scale-info", "serde_json", "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -26816,7 +26585,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -26829,8 +26598,8 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", - "thiserror 1.0.69", + "sp-runtime 39.0.2", + "thiserror", ] [[package]] @@ -26955,7 +26724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c0e20624277f578b27f44ecfbe2ebc2e908488511ee2c900c5281599f700ab3" dependencies = [ "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "strum 0.26.3", ] @@ -27011,7 +26780,7 @@ dependencies = [ name = "sp-maybe-compressed-blob" version = "11.0.0" dependencies = [ - "thiserror 1.0.69", + "thiserror", "zstd 0.12.4", ] @@ -27021,7 +26790,7 @@ version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c768c11afbe698a090386876911da4236af199cd38a5866748df4d8628aeff" dependencies = [ - "thiserror 1.0.69", + "thiserror", "zstd 0.12.4", ] @@ -27081,7 +26850,7 @@ dependencies = [ "sp-core 28.0.0", "sp-debug-derive 14.0.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -27098,8 +26867,8 @@ dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-runtime 39.0.5", - "thiserror 1.0.69", + "sp-runtime 39.0.2", + "thiserror", ] [[package]] @@ -27127,14 +26896,14 @@ dependencies = [ "serde", "sp-arithmetic 26.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "honggfuzz", "rand", "sp-npos-elections 26.0.0", @@ -27158,7 +26927,7 @@ checksum = "2d9de237d72ecffd07f90826eef18360208b16d8de939d54e61591fac0fcbf99" dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -27171,11 +26940,12 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "13.0.1" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81478b3740b357fa0ea10fcdc1ee02ebae7734e50f80342c4743476d9f78eeea" +checksum = "d8f5a17a0a11de029a8b811cb6e8b32ce7e02183cc04a3e965c383246798c416" dependencies = [ "backtrace", + "lazy_static", "regex", ] @@ -27276,9 +27046,9 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "39.0.5" +version = "39.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e00503b83cf48fffe48746b91b9b832d6785d4e2eeb0941558371eac6baac6" +checksum = "658f23be7c79a85581029676a73265c107c5469157e3444c8c640fdbaa8bfed0" dependencies = [ "docify", "either", @@ -27301,6 +27071,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "sp-runtime-interface" +version = "17.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types 0.12.2", + "sp-externalities 0.19.0", + "sp-runtime-interface-proc-macro 11.0.0", + "sp-std 8.0.0", + "sp-storage 13.0.0", + "sp-tracing 10.0.0", + "sp-wasm-interface 14.0.0", + "static_assertions", +] + [[package]] name = "sp-runtime-interface" version = "24.0.0" @@ -27325,25 +27113,6 @@ dependencies = [ "trybuild", ] -[[package]] -name = "sp-runtime-interface" -version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "polkavm-derive 0.18.0", - "primitive-types 0.13.1", - "sp-externalities 0.25.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-runtime-interface-proc-macro 17.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-storage 19.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "sp-wasm-interface 20.0.0 (git+https://github.com/paritytech/polkadot-sdk)", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "27.0.0" @@ -27386,27 +27155,26 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "17.0.0" +version = "11.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "Inflector", - "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -27417,10 +27185,10 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -27484,7 +27252,7 @@ dependencies = [ "sp-api 34.0.0", "sp-core 34.0.0", "sp-keystore 0.40.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-staking 36.0.0", ] @@ -27511,7 +27279,7 @@ dependencies = [ "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -27525,7 +27293,7 @@ dependencies = [ "scale-info", "serde", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -27547,7 +27315,7 @@ dependencies = [ "sp-panic-handler 13.0.0", "sp-runtime 31.0.1", "sp-trie 29.0.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", ] @@ -27566,9 +27334,9 @@ dependencies = [ "smallvec", "sp-core 32.0.0", "sp-externalities 0.28.0", - "sp-panic-handler 13.0.1", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 34.0.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", ] @@ -27587,9 +27355,9 @@ dependencies = [ "smallvec", "sp-core 33.0.1", "sp-externalities 0.28.0", - "sp-panic-handler 13.0.1", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 35.0.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", ] @@ -27608,9 +27376,9 @@ dependencies = [ "smallvec", "sp-core 34.0.0", "sp-externalities 0.29.0", - "sp-panic-handler 13.0.1", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-trie 37.0.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", ] @@ -27634,7 +27402,7 @@ dependencies = [ "sp-externalities 0.25.0", "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", - "thiserror 1.0.69", + "thiserror", "x25519-dalek", ] @@ -27657,48 +27425,49 @@ dependencies = [ "sp-core 34.0.0", "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-externalities 0.29.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-runtime-interface 28.0.0", - "thiserror 1.0.69", + "thiserror", "x25519-dalek", ] [[package]] name = "sp-std" -version = "14.0.0" +version = "8.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" [[package]] name = "sp-std" version = "14.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" [[package]] name = "sp-storage" -version = "19.0.0" +version = "13.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "impl-serde 0.5.0", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 14.0.0", + "sp-debug-derive 8.0.0", + "sp-std 8.0.0", ] [[package]] name = "sp-storage" version = "19.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "impl-serde 0.5.0", "parity-scale-codec", "ref-cast", "serde", - "sp-debug-derive 14.0.0 (git+https://github.com/paritytech/polkadot-sdk)", + "sp-debug-derive 14.0.0", ] [[package]] @@ -27734,7 +27503,7 @@ dependencies = [ "parity-scale-codec", "sp-inherents 26.0.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -27746,29 +27515,30 @@ dependencies = [ "async-trait", "parity-scale-codec", "sp-inherents 34.0.0", - "sp-runtime 39.0.5", - "thiserror 1.0.69", + "sp-runtime 39.0.2", + "thiserror", ] [[package]] name = "sp-tracing" -version = "16.0.0" +version = "10.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "parity-scale-codec", + "sp-std 8.0.0", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] name = "sp-tracing" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -27780,7 +27550,7 @@ dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -27798,7 +27568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4bf251059485a7dd38fe4afeda8792983511cc47f342ff4695e2dcae6b5247" dependencies = [ "sp-api 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -27825,7 +27595,7 @@ dependencies = [ "scale-info", "sp-core 34.0.0", "sp-inherents 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-trie 37.0.0", ] @@ -27847,7 +27617,7 @@ dependencies = [ "sp-core 28.0.0", "sp-externalities 0.25.0", "sp-runtime 31.0.1", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-bench", "trie-db", @@ -27873,7 +27643,7 @@ dependencies = [ "schnellru", "sp-core 32.0.0", "sp-externalities 0.28.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", "trie-root", @@ -27897,7 +27667,7 @@ dependencies = [ "schnellru", "sp-core 33.0.1", "sp-externalities 0.28.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", "trie-root", @@ -27921,7 +27691,7 @@ dependencies = [ "schnellru", "sp-core 34.0.0", "sp-externalities 0.29.0", - "thiserror 1.0.69", + "thiserror", "tracing", "trie-db", "trie-root", @@ -27940,7 +27710,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-version-proc-macro 13.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -27958,7 +27728,7 @@ dependencies = [ "sp-runtime 37.0.0", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-version-proc-macro 14.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -27973,10 +27743,10 @@ dependencies = [ "scale-info", "serde", "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-version-proc-macro 14.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -27985,10 +27755,10 @@ version = "13.0.0" dependencies = [ "parity-scale-codec", "proc-macro-warning", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "sp-version 29.0.0", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -27998,31 +27768,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aee8f6730641a65fcf0c8f9b1e448af4b3bb083d08058b47528188bccc7b7a7" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sp-wasm-interface" -version = "20.0.0" +version = "14.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", + "sp-std 8.0.0", "wasmtime", ] [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#f798111afc15f464a772cd7ed37910cc6208b713" dependencies = [ "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", + "wasmtime", ] [[package]] @@ -28094,29 +27866,30 @@ dependencies = [ ] [[package]] -name = "spinning_top" -version = "0.3.0" +name = "spki" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ - "lock_api", + "base64ct", + "der", ] [[package]] -name = "spki" -version = "0.7.3" +name = "sqlformat" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "base64ct", - "der", + "nom", + "unicode_categories", ] [[package]] name = "sqlx" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -28127,31 +27900,37 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ + "atoi", + "byteorder", "bytes", "crc", "crossbeam-queue", "either", - "event-listener 5.4.0", + "event-listener 5.3.1", + "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.2", - "hashlink 0.10.0", + "hashbrown 0.14.5", + "hashlink 0.9.1", + "hex", "indexmap 2.7.0", "log", "memchr", "once_cell", + "paste", "percent-encoding", "serde", "serde_json", "sha2 0.10.8", "smallvec", - "thiserror 2.0.11", + "sqlformat", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -28160,30 +27939,30 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "sqlx-core", "sqlx-macros-core", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] name = "sqlx-macros-core" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", "heck 0.5.0", "hex", "once_cell", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "serde", "serde_json", "sha2 0.10.8", @@ -28191,7 +27970,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.96", + "syn 2.0.87", "tempfile", "tokio", "url", @@ -28199,13 +27978,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.8.0", + "bitflags 2.6.0", "byteorder", "bytes", "crc", @@ -28234,26 +28013,27 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.11", + "thiserror", "tracing", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.8.0", + "bitflags 2.6.0", "byteorder", "crc", "dotenvy", "etcetera", "futures-channel", "futures-core", + "futures-io", "futures-util", "hex", "hkdf", @@ -28271,16 +28051,16 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.11", + "thiserror", "tracing", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "flume", @@ -28301,17 +28081,17 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.51.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19409f13998e55816d1c728395af0b52ec066206341d939e22e7766df9b494b8" +checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "serde", "serde_json", - "unicode-xid 0.2.6", + "unicode-xid 0.2.4", ] [[package]] @@ -28332,8 +28112,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -28347,7 +28127,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "cmd_lib", "docify", "log", @@ -28364,7 +28144,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.5.26", + "clap 4.5.13", "clap_complete", "criterion", "futures", @@ -28385,7 +28165,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "soketto 0.8.1", + "soketto 0.8.0", "sp-keyring 31.0.0", "staging-node-inspect", "substrate-cli-test-utils", @@ -28401,7 +28181,7 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -28411,7 +28191,7 @@ dependencies = [ "sp-io 30.0.0", "sp-runtime 31.0.1", "sp-statement-store 10.0.0", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -28433,11 +28213,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d28266dfddbfff721d70ad2f873380845b569adfab32f257cf97d9cedd894b68" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "scale-info", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", ] [[package]] @@ -28482,7 +28262,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "xcm-procedural 10.1.0", ] @@ -28520,22 +28300,22 @@ dependencies = [ [[package]] name = "staging-xcm-builder" -version = "17.0.3" +version = "17.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f7a92cfaec55a5ed0f9cbbb9076aa8ec0aff1ba90b9804cc5c8f2369fde59c" +checksum = "a3746adbbae27b1e6763f0cca622e15482ebcb94835a9e078c212dd7be896e35" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "impl-trait-for-tuples", "log", "pallet-asset-conversion 20.0.0", - "pallet-transaction-payment 38.0.2", + "pallet-transaction-payment 38.0.0", "parity-scale-codec", "polkadot-parachain-primitives 14.0.0", "scale-info", "sp-arithmetic 26.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "staging-xcm 14.2.0", "staging-xcm-executor 17.0.0", @@ -28568,14 +28348,14 @@ checksum = "79dd0c5332a5318e58f0300b20768b71cf9427c906f94a743c9dc7c3ee9e7fa9" dependencies = [ "environmental", "frame-benchmarking 38.0.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", "sp-arithmetic 26.0.0", "sp-core 34.0.0", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "staging-xcm 14.2.0", "tracing", @@ -28604,14 +28384,14 @@ dependencies = [ [[package]] name = "static_init_macro" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f" +checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases 0.1.1", "memchr", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -28643,6 +28423,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -28668,8 +28454,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -28682,6 +28468,12 @@ dependencies = [ "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + [[package]] name = "strum" version = "0.26.3" @@ -28698,12 +28490,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustversion", "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "rustversion", + "syn 2.0.87", +] + [[package]] name = "strum_macros" version = "0.26.4" @@ -28711,17 +28516,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustversion", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "sc-cli", ] @@ -28796,7 +28601,7 @@ dependencies = [ "scale-info", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "wasm-testbed", ] @@ -28846,11 +28651,11 @@ name = "substrate-prometheus-endpoint" version = "0.17.0" dependencies = [ "http-body-util", - "hyper 1.5.2", + "hyper 1.3.1", "hyper-util", "log", "prometheus", - "thiserror 1.0.69", + "thiserror", "tokio", ] @@ -28894,7 +28699,7 @@ dependencies = [ "sp-trie 29.0.0", "structopt", "strum 0.26.3", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -28924,7 +28729,7 @@ dependencies = [ "sp-io 35.0.0", "sp-runtime 36.0.0", "sp-wasm-interface 21.0.1", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -29052,7 +28857,7 @@ dependencies = [ "sp-blockchain", "sp-runtime 31.0.1", "substrate-test-runtime-client", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -29123,9 +28928,9 @@ checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" -version = "2.6.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "subtle-ng" @@ -29145,14 +28950,14 @@ dependencies = [ "log", "num-format", "rand", - "reqwest 0.12.12", + "reqwest 0.12.9", "scale-info", - "semver 1.0.24", + "semver 1.0.18", "serde", "serde_json", "sp-version 35.0.0", "substrate-differ", - "thiserror 1.0.69", + "thiserror", "url", "uuid", "wasm-loader", @@ -29188,7 +28993,7 @@ dependencies = [ "subxt-lightclient", "subxt-macro", "subxt-metadata", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-util", "tracing", @@ -29205,13 +29010,13 @@ checksum = "3cfcfb7d9589f3df0ac87c4988661cf3fb370761fcb19f2fd33104cc59daf22a" dependencies = [ "heck 0.5.0", "parity-scale-codec", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.96", - "thiserror 1.0.69", + "syn 2.0.87", + "thiserror", ] [[package]] @@ -29254,7 +29059,7 @@ dependencies = [ "serde", "serde_json", "smoldot-light 0.16.2", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-stream", "tracing", @@ -29269,11 +29074,11 @@ dependencies = [ "darling", "parity-scale-codec", "proc-macro-error2", - "quote 1.0.38", + "quote 1.0.37", "scale-typegen", "subxt-codegen", "subxt-utils-fetchmetadata", - "syn 2.0.96", + "syn 2.0.87", ] [[package]] @@ -29327,20 +29132,20 @@ checksum = "3082b17a86e3c3fe45d858d94d68f6b5247caace193dad6201688f24db8ba9bb" dependencies = [ "hex", "parity-scale-codec", - "thiserror 1.0.69", + "thiserror", ] [[package]] name = "sval" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c2f18f53c889ec3dfe1c08b20fd51406d09b14bf18b366416718763ccff05a" +checksum = "8b031320a434d3e9477ccf9b5756d57d4272937b8d22cb88af80b7633a1b78b1" [[package]] name = "sval_buffer" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8cb1bb48d0bed828b908e6b99e7ab8c7244994dc27948a2e31d42e8c4d77c1" +checksum = "6bf7e9412af26b342f3f2cc5cc4122b0105e9d16eb76046cd14ed10106cf6028" dependencies = [ "sval", "sval_ref", @@ -29348,18 +29153,18 @@ dependencies = [ [[package]] name = "sval_dynamic" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba574872d4ad653071a9db76c49656082db83a37cd5f559874273d36b4a02b9d" +checksum = "a0ef628e8a77a46ed3338db8d1b08af77495123cc229453084e47cd716d403cf" dependencies = [ "sval", ] [[package]] name = "sval_fmt" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944450b2dbbf8aae98537776b399b23d72b19243ee42522cfd110305f3c9ba5a" +checksum = "7dc09e9364c2045ab5fa38f7b04d077b3359d30c4c2b3ec4bae67a358bd64326" dependencies = [ "itoa", "ryu", @@ -29368,65 +29173,55 @@ dependencies = [ [[package]] name = "sval_json" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "411bbd543c413796ccfbaa44f6676e20032b6c69e4996cb6c3e6ef30c79b96d1" +checksum = "ada6f627e38cbb8860283649509d87bc4a5771141daa41c78fd31f2b9485888d" dependencies = [ "itoa", "ryu", "sval", ] -[[package]] -name = "sval_nested" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30582d2a90869b380f8260559138c1b68ac3e0765520959f22a1a1fdca31769" -dependencies = [ - "sval", - "sval_buffer", - "sval_ref", -] - [[package]] name = "sval_ref" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762d3fbf3c0869064b7c93808c67ad2ed0292dde9b060ac282817941d4707dff" +checksum = "703ca1942a984bd0d9b5a4c0a65ab8b4b794038d080af4eb303c71bc6bf22d7c" dependencies = [ "sval", ] [[package]] name = "sval_serde" -version = "2.14.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "752d307438c6a6a3d095a2fecf6950cfb946d301a5bd6b57f047db4f6f8d97b9" +checksum = "830926cd0581f7c3e5d51efae4d35c6b6fc4db583842652891ba2f1bed8db046" dependencies = [ "serde", "sval", - "sval_nested", + "sval_buffer", + "sval_fmt", ] [[package]] name = "symbolic-common" -version = "12.13.2" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8150eae9699e3c73a3e6431dc1f80d87748797c0457336af23e94c1de619ed24" +checksum = "167a4ffd7c35c143fd1030aa3c2caf76ba42220bd5a6b5f4781896434723b8c3" dependencies = [ "debugid", - "memmap2 0.9.5", + "memmap2 0.5.10", "stable_deref_trait", "uuid", ] [[package]] name = "symbolic-demangle" -version = "12.13.2" +version = "12.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f4a9846f7a8933b6d198c022faa2c9bd89e1a970bed9d9a98d25708bf8de17" +checksum = "e378c50e80686c1c5c205674e1f86a2858bec3d2a7dfdd690331a8a19330f293" dependencies = [ - "cpp_demangle 0.4.4", + "cpp_demangle 0.4.3", "rustc-demangle", "symbolic-common", ] @@ -29448,19 +29243,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.96" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "unicode-ident", ] @@ -29471,21 +29266,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "syn-solidity" -version = "0.8.18" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e89d8bf2768d277f40573c83a02a099e96d96dd3104e13ea676194e61ac4b0" +checksum = "219389c1ebe89f8333df8bdfb871f6631c552ff399c23cac02480b6088aad8f0" dependencies = [ "paste", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -29496,9 +29291,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.2" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" dependencies = [ "futures-core", ] @@ -29509,10 +29304,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", - "unicode-xid 0.2.6", + "unicode-xid 0.2.4", ] [[package]] @@ -29521,16 +29316,16 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "sysinfo" -version = "0.30.13" +version = "0.30.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" dependencies = [ "cfg-if", "core-foundation-sys", @@ -29548,19 +29343,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.8.0", - "core-foundation 0.9.4", - "system-configuration-sys 0.6.0", + "core-foundation", + "system-configuration-sys", ] [[package]] @@ -29573,16 +29357,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -29591,9 +29365,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.43" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" dependencies = [ "filetime", "libc", @@ -29602,27 +29376,20 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "target-triple" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "tempfile" -version = "3.15.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand 2.3.0", - "getrandom", "once_cell", - "rustix 0.38.43", + "rustix 0.38.42", "windows-sys 0.59.0", ] @@ -29631,7 +29398,7 @@ name = "template-zombienet-tests" version = "0.0.0" dependencies = [ "anyhow", - "env_logger 0.11.6", + "env_logger 0.11.3", "log", "tokio", "zombienet-sdk", @@ -29639,28 +29406,28 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" -version = "0.4.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.43", - "windows-sys 0.59.0", + "rustix 0.38.42", + "windows-sys 0.48.0", ] [[package]] name = "termtree" -version = "0.5.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test-log" @@ -29668,9 +29435,9 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" dependencies = [ - "env_logger 0.11.6", + "env_logger 0.11.3", "test-log-macros", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -29679,9 +29446,9 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -29700,7 +29467,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "futures", "futures-timer", "log", @@ -29747,7 +29514,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.26", + "clap 4.5.13", "futures", "futures-timer", "log", @@ -29811,11 +29578,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94bceae6f7c89d47daff6c7e05f712551a01379f61b07d494661941144878589" dependencies = [ "cumulus-primitives-core 0.16.0", - "frame-support 38.2.0", + "frame-support 38.0.0", "polkadot-core-primitives 15.0.0", "rococo-runtime-constants 17.0.0", "smallvec", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "staging-xcm 14.2.0", "westend-runtime-constants 17.0.0", ] @@ -29826,67 +29593,53 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.14", + "unicode-width", ] [[package]] -name = "thiserror" -version = "1.0.69" +name = "textwrap" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "2.0.11" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl", ] [[package]] name = "thiserror-core" -version = "1.0.50" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c001ee18b7e5e3f62cbf58c7fe220119e68d902bb7443179c0c8aef30090e999" +checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" dependencies = [ "thiserror-core-impl", ] [[package]] name = "thiserror-core-impl" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c60d69f36615a077cc7663b9cb8e42275722d23e58a7fa3d2c7f2915d09d04" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -29897,9 +29650,9 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ "cfg-if", "once_cell", @@ -29947,9 +29700,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -29970,9 +29723,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", @@ -29987,16 +29740,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -30009,9 +29752,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -30024,9 +29767,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -30035,7 +29778,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.8", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.52.0", ] @@ -30052,13 +29795,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -30088,25 +29831,26 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.12", + "rustls 0.21.7", "tokio", ] [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.21", + "rustls 0.23.18", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -30135,7 +29879,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.12", + "rustls 0.21.7", "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", @@ -30144,9 +29888,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -30195,7 +29939,18 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.7.0", "toml_datetime", - "winnow 0.5.40", + "winnow 0.5.15", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.7.0", + "toml_datetime", + "winnow 0.5.15", ] [[package]] @@ -30208,7 +29963,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.24", + "winnow 0.6.18", ] [[package]] @@ -30228,21 +29983,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 1.0.2", - "tokio", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-http" version = "0.4.4" @@ -30250,12 +29990,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "base64 0.21.7", - "bitflags 2.8.0", + "bitflags 2.6.0", "bytes", "futures-core", "futures-util", - "http 0.2.12", - "http-body 0.4.6", + "http 0.2.9", + "http-body 0.4.5", "http-range-header", "mime", "pin-project-lite", @@ -30270,10 +30010,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.8.0", + "bitflags 2.6.0", "bytes", - "http 1.2.0", - "http-body 1.0.1", + "http 1.1.0", + "http-body 1.0.0", "http-body-util", "pin-project-lite", "tower-layer", @@ -30282,21 +30022,21 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" [[package]] name = "tower-service" -version = "0.3.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", @@ -30306,20 +30046,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -30351,10 +30091,21 @@ version = "5.0.0" dependencies = [ "assert_matches", "expander", - "proc-macro-crate 3.2.0", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", ] [[package]] @@ -30368,14 +30119,46 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" dependencies = [ + "ansi_term", "chrono", - "matchers", + "lazy_static", + "matchers 0.0.1", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log 0.1.3", + "tracing-serde", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "chrono", + "matchers 0.1.0", "nu-ansi-term", "once_cell", "parking_lot 0.12.3", @@ -30386,7 +30169,7 @@ dependencies = [ "time", "tracing", "tracing-core", - "tracing-log", + "tracing-log 0.2.0", ] [[package]] @@ -30438,24 +30221,24 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "trybuild" -version = "1.0.101" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" +checksum = "9a9d3ba662913483d6722303f619e75ea10b7855b0f8e0d72799cf8621bb488f" dependencies = [ + "basic-toml", "dissimilar", "glob", + "once_cell", "serde", "serde_derive", "serde_json", - "target-triple", "termcolor", - "toml 0.8.19", ] [[package]] @@ -30473,13 +30256,13 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.12", + "http 0.2.9", "httparse", "log", "rand", - "rustls 0.21.12", + "rustls 0.21.7", "sha1", - "thiserror 1.0.69", + "thiserror", "url", "utf-8", ] @@ -30493,15 +30276,15 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.2.0", + "http 1.1.0", "httparse", "log", "rand", "rustls 0.22.4", - "rustls-native-certs 0.7.3", + "rustls-native-certs 0.7.0", "rustls-pki-types", "sha1", - "thiserror 1.0.69", + "thiserror", "url", "utf-8", ] @@ -30524,23 +30307,17 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "typeid" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" - [[package]] name = "typenum" -version = "1.17.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" @@ -30574,15 +30351,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.18" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -30601,21 +30378,15 @@ checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-segmentation" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.0" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -30625,9 +30396,15 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.6" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unicode_categories" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "universal-hash" @@ -30636,7 +30413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", - "subtle 2.6.1", + "subtle 2.5.0", ] [[package]] @@ -30693,30 +30470,30 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.12.1" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64 0.22.1", "flate2", "log", "once_cell", - "rustls 0.23.21", + "rustls 0.23.18", "rustls-pki-types", "serde", "serde_json", "url", - "webpki-roots 0.26.7", + "webpki-roots 0.26.3", ] [[package]] name = "url" -version = "2.5.4" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", "serde", ] @@ -30727,29 +30504,17 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.12.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ "getrandom", ] @@ -30762,9 +30527,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" +checksum = "8fec26a25bd6fca441cdd0f769fd7f891bae119f996de31f86a5eddccef54c1d" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -30772,9 +30537,9 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" +checksum = "ead5b693d906686203f19a49e88c477fb8c15798b68cf72f60b4b5521b4ad891" dependencies = [ "erased-serde", "serde", @@ -30783,9 +30548,9 @@ dependencies = [ [[package]] name = "value-bag-sval2" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" +checksum = "3b9d0f4a816370c3a0d7d82d603b62198af17675b12fe5e91de6b47ceb505882" dependencies = [ "sval", "sval_buffer", @@ -30810,9 +30575,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "void" @@ -30822,16 +30587,16 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "w3f-bls" -version = "0.1.8" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a3028804c8bbae2a97a15b71ffc0e308c4b01a520994aafa77d56e94e19024" +checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" dependencies = [ "ark-bls12-377", "ark-bls12-381", - "ark-ec 0.4.2", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", - "ark-serialize-derive 0.4.2", + "ark-serialize-derive", "arrayref", "constcat", "digest 0.10.7", @@ -30840,7 +30605,7 @@ dependencies = [ "rand_core 0.6.4", "sha2 0.10.8", "sha3 0.10.8", - "thiserror 1.0.69", + "thiserror", "zeroize", ] @@ -30855,9 +30620,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "walkdir" @@ -30890,24 +30655,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" -[[package]] -name = "wasix" -version = "0.12.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fbb4ef9bbca0c1170e0b00dd28abc9e3b68669821600cad1caaed606583c6d" -dependencies = [ - "wasi", -] - [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", - "rustversion", "serde", "serde_json", "wasm-bindgen-macro", @@ -30915,71 +30670,69 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "once_cell", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ - "quote 1.0.38", + "quote 1.0.37", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-bindgen-test" -version = "0.3.50" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3" +checksum = "6e6e302a7ea94f83a6d09e78e7dc7d9ca7b186bc2829c24a22d0753efd680671" dependencies = [ + "console_error_panic_hook", "js-sys", - "minicov", + "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", @@ -30987,23 +30740,21 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.50" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b" +checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", ] [[package]] name = "wasm-encoder" -version = "0.223.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e636076193fa68103e937ac951b5f2f587624097017d764b8984d9c0f149464" +checksum = "41763f20eafed1399fff1afb466496d3a959f58241436cfdc17e3f5ca954de16" dependencies = [ "leb128", - "wasmparser 0.223.0", ] [[package]] @@ -31023,12 +30774,12 @@ dependencies = [ "array-bytes", "log", "multibase 0.9.1", - "multihash 0.19.3", + "multihash 0.19.1", "serde", "serde_json", "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "subrpcer", - "thiserror 1.0.69", + "thiserror", "tungstenite 0.21.0", "ureq", "url", @@ -31036,16 +30787,16 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.116.1" +version = "0.116.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" +checksum = "fc942673e7684671f0c5708fc18993569d184265fd5223bb51fc8e5b9b6cfd52" dependencies = [ "anyhow", "libc", "strum 0.24.1", "strum_macros 0.24.3", "tempfile", - "thiserror 1.0.69", + "thiserror", "wasm-opt-cxx-sys", "wasm-opt-sys", ] @@ -31093,7 +30844,7 @@ dependencies = [ "sp-version 35.0.0", "sp-wasm-interface 21.0.1", "substrate-runtime-proposal-hash", - "thiserror 1.0.69", + "thiserror", "wasm-loader", ] @@ -31131,7 +30882,7 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50386c99b9c32bd2ed71a55b6dd4040af2580530fae8bdb9a6576571a80d0cca" dependencies = [ - "arrayvec 0.7.6", + "arrayvec 0.7.4", "multi-stash", "num-derive", "num-traits", @@ -31193,17 +30944,6 @@ dependencies = [ "url", ] -[[package]] -name = "wasmparser" -version = "0.223.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35" -dependencies = [ - "bitflags 2.8.0", - "indexmap 2.7.0", - "semver 1.0.24", -] - [[package]] name = "wasmparser-nostd" version = "0.100.2" @@ -31232,7 +30972,7 @@ dependencies = [ "rayon", "serde", "target-lexicon", - "wasmparser 0.102.0", + "wasmparser", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", @@ -31262,7 +31002,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.17", + "rustix 0.36.15", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -31286,8 +31026,8 @@ dependencies = [ "log", "object 0.30.4", "target-lexicon", - "thiserror 1.0.69", - "wasmparser 0.102.0", + "thiserror", + "wasmparser", "wasmtime-cranelift-shared", "wasmtime-environ", ] @@ -31321,8 +31061,8 @@ dependencies = [ "object 0.30.4", "serde", "target-lexicon", - "thiserror 1.0.69", - "wasmparser 0.102.0", + "thiserror", + "wasmparser", "wasmtime-types", ] @@ -31358,7 +31098,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.17", + "rustix 0.36.15", ] [[package]] @@ -31386,10 +31126,10 @@ dependencies = [ "log", "mach", "memfd", - "memoffset", + "memoffset 0.8.0", "paste", "rand", - "rustix 0.36.17", + "rustix 0.36.15", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -31404,37 +31144,36 @@ checksum = "a4f6fffd2a1011887d57f07654dd112791e872e3ff4a2e626aee8059ee17f06f" dependencies = [ "cranelift-entity", "serde", - "thiserror 1.0.69", - "wasmparser 0.102.0", + "thiserror", + "wasmparser", ] [[package]] name = "wast" -version = "223.0.0" +version = "63.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59b2ba8a2ff9f06194b7be9524f92e45e70149f4dacc0d0c7ad92b59ac875e4" +checksum = "2560471f60a48b77fccefaf40796fda61c97ce1e790b59dfcec9dc3995c9f63a" dependencies = [ - "bumpalo", "leb128", "memchr", - "unicode-width 0.2.0", + "unicode-width", "wasm-encoder", ] [[package]] name = "wat" -version = "1.223.0" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662786915c427e4918ff01eabb3c4756d4d947cd8f635761526b4cc9da2eaaad" +checksum = "3bdc306c2c4c2f2bf2ba69e083731d0d2a77437fc6a350a19db139636e7e416c" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -31462,15 +31201,15 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.4" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "webpki-roots" -version = "0.26.7" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" dependencies = [ "rustls-pki-types", ] @@ -31630,15 +31369,15 @@ version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06861bf945aadac59f4be23b44c85573029520ea9bd3d6c9ab21c8b306e81cdc" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "polkadot-primitives 16.0.0", "polkadot-runtime-common 17.0.0", "smallvec", "sp-core 34.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-weights 31.0.0", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", ] [[package]] @@ -31667,9 +31406,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.32" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" +checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" dependencies = [ "bytemuck", "safe_arch", @@ -31677,9 +31416,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.1.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "winapi" @@ -31699,11 +31438,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "windows-sys 0.59.0", + "winapi", ] [[package]] @@ -31714,60 +31453,59 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] name = "windows" -version = "0.53.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc5cf48f83140dcaab716eeaea345f9e93d0018fb81162753a3f76c3397b538" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-core 0.53.0", - "windows-targets 0.52.6", + "windows-core 0.51.1", + "windows-targets 0.48.5", ] [[package]] -name = "windows-core" +name = "windows" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ + "windows-core 0.52.0", "windows-targets 0.52.6", ] [[package]] name = "windows-core" -version = "0.53.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcc5b895a6377f1ab9fa55acedab1fd5ac0db66ad1e6c7f47e28a22e446a5dd" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] -name = "windows-registry" -version = "0.2.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-result 0.2.0", - "windows-strings", "windows-targets 0.52.6", ] [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-registry" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ + "windows-result", + "windows-strings", "windows-targets 0.52.6", ] @@ -31786,7 +31524,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result 0.2.0", + "windows-result", "windows-targets 0.52.6", ] @@ -32006,18 +31744,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.6.24" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -32032,18 +31770,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "wyz" version = "0.5.1" @@ -32055,9 +31781,9 @@ dependencies = [ [[package]] name = "x25519-dalek" -version = "2.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ "curve25519-dalek 4.1.3", "rand_core 0.6.4", @@ -32078,19 +31804,17 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "xattr" -version = "1.4.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" dependencies = [ "libc", - "linux-raw-sys 0.4.15", - "rustix 0.38.43", ] [[package]] @@ -32182,10 +31906,10 @@ version = "7.0.0" dependencies = [ "Inflector", "frame-support 28.0.0", - "proc-macro2 1.0.93", - "quote 1.0.38", + "proc-macro2 1.0.86", + "quote 1.0.37", "staging-xcm 7.0.0", - "syn 2.0.96", + "syn 2.0.87", "trybuild", ] @@ -32196,9 +31920,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87fb4f14094d65c500a59bcf540cf42b99ee82c706edd6226a92e769ad60563e" dependencies = [ "Inflector", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -32226,11 +31950,11 @@ dependencies = [ [[package]] name = "xcm-runtime-apis" -version = "0.4.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3d96bd7362d9e6884ef6762f08737d89205a358d059a0451353f3e91985ca5" +checksum = "69d4473a5d157e4d437d9ebcb1b99f9693a64983877ee57d97005f0167869935" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "parity-scale-codec", "scale-info", "sp-api 34.0.0", @@ -32266,7 +31990,7 @@ version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058e21bfc3e1180bbd83cad3690d0e63f34f43ab309e338afe988160aa776fcf" dependencies = [ - "frame-support 38.2.0", + "frame-support 38.0.0", "frame-system 38.0.0", "parity-scale-codec", "paste", @@ -32276,10 +32000,10 @@ dependencies = [ "polkadot-runtime-parachains 17.0.1", "scale-info", "sp-io 38.0.0", - "sp-runtime 39.0.5", + "sp-runtime 39.0.2", "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "staging-xcm 14.2.0", - "staging-xcm-builder 17.0.3", + "staging-xcm-builder 17.0.1", "staging-xcm-executor 17.0.0", ] @@ -32340,9 +32064,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.25" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" [[package]] name = "xmltree" @@ -32370,9 +32094,9 @@ dependencies = [ [[package]] name = "yamux" -version = "0.13.4" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17610762a1207ee816c6fadc29220904753648aba0a9ed61c7b8336e80a559c4" +checksum = "a31b5e376a8b012bee9c423acdbb835fc34d45001cfa3106236a624e4b738028" dependencies = [ "futures", "log", @@ -32386,9 +32110,9 @@ dependencies = [ [[package]] name = "yansi" -version = "1.0.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "yap" @@ -32405,70 +32129,24 @@ dependencies = [ "time", ] -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", - "synstructure 0.13.1", -] - [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - -[[package]] -name = "zerofrom" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.5" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", - "synstructure 0.13.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -32486,31 +32164,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.96", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.87", ] [[package]] @@ -32519,10 +32175,10 @@ version = "1.0.0" dependencies = [ "futures-util", "parity-scale-codec", - "reqwest 0.12.12", + "reqwest 0.12.9", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-tungstenite", "tracing-gum", @@ -32537,12 +32193,12 @@ checksum = "5ced2fca1322821431f03d06dcf2ea74d3a7369760b6c587b372de6eada3ce43" dependencies = [ "anyhow", "lazy_static", - "multiaddr 0.18.2", + "multiaddr 0.18.1", "regex", "reqwest 0.11.27", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tokio", "toml 0.8.19", "url", @@ -32562,7 +32218,7 @@ dependencies = [ "hex", "libp2p", "libsecp256k1", - "multiaddr 0.18.2", + "multiaddr 0.18.1", "rand", "regex", "reqwest 0.11.27", @@ -32572,7 +32228,7 @@ dependencies = [ "sp-core 34.0.0", "subxt", "subxt-signer", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", "uuid", @@ -32590,7 +32246,7 @@ checksum = "23702db0819a050c8a0130a769b105695137020a64207b4597aa021f06924552" dependencies = [ "pest", "pest_derive", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -32614,7 +32270,7 @@ dependencies = [ "serde_yaml", "sha2 0.10.8", "tar", - "thiserror 1.0.69", + "thiserror", "tokio", "tokio-util", "tracing", @@ -32655,7 +32311,7 @@ dependencies = [ "rand", "regex", "reqwest 0.11.27", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", "uuid", @@ -32701,10 +32357,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.8+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" dependencies = [ "cc", + "libc", "pkg-config", ] From de93ecdf4440b0a8474ef66ceefabf9908f649c1 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Jan 2025 15:39:53 +0000 Subject: [PATCH 77/95] onchain backup sorting, testing chain in kitchensink --- substrate/bin/node/cli/Cargo.toml | 3 + substrate/bin/node/cli/src/chain_spec.rs | 64 +++++++--- substrate/bin/node/runtime/Cargo.toml | 2 + substrate/bin/node/runtime/src/constants.rs | 4 + substrate/bin/node/runtime/src/lib.rs | 119 +++++++++++++++++- .../consensus/grandpa/src/aux_schema.rs | 4 +- .../election-provider-support/src/lib.rs | 50 ++++++++ .../election-provider-support/src/onchain.rs | 103 +++++++++++---- .../election-provider-support/src/tests.rs | 27 +++- 9 files changed, 330 insertions(+), 46 deletions(-) diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index 9e063ee3cde0f..6b4313d63ffd4 100644 --- a/substrate/bin/node/cli/Cargo.toml +++ b/substrate/bin/node/cli/Cargo.toml @@ -183,6 +183,9 @@ try-runtime = [ "polkadot-sdk/try-runtime", "substrate-cli-test-utils/try-runtime", ] +staking-playground = [ + "kitchensink-runtime/staking-playground", +] [[bench]] name = "transaction_pool" diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 038aa2f609285..e90312543433b 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -276,7 +276,6 @@ fn configure_accounts( )>, initial_nominators: Vec, endowed_accounts: Option>, - stash: Balance, ) -> ( Vec<( AccountId, @@ -305,21 +304,31 @@ fn configure_accounts( } }); - // stakers: all validators and nominators. + use rand::Rng; let mut rng = rand::thread_rng(); + let mut rng2 = rand::thread_rng(); + // stakers: all validators and nominators. let stakers = initial_authorities .iter() - .map(|x| (x.0.clone(), x.0.clone(), stash, StakerStatus::Validator)) + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + rng.gen_range(ENDOWMENT / 100..ENDOWMENT / 2), + StakerStatus::Validator, + ) + }) .chain(initial_nominators.iter().map(|x| { use rand::{seq::SliceRandom, Rng}; let limit = (MaxNominations::get() as usize).min(initial_authorities.len()); - let count = rng.gen::() % limit; + let count = (rng2.gen::() % limit).max(1); let nominations = initial_authorities .as_slice() - .choose_multiple(&mut rng, count) + .choose_multiple(&mut rng2, count) .into_iter() .map(|choice| choice.0.clone()) .collect::>(); + let stash = rng2.gen_range(ENDOWMENT / 100..ENDOWMENT / 2); (x.clone(), x.clone(), stash, StakerStatus::Nominator(nominations)) })) .collect::>(); @@ -346,7 +355,8 @@ pub fn testnet_genesis( endowed_accounts: Option>, ) -> serde_json::Value { let (initial_authorities, endowed_accounts, num_endowed_accounts, stakers) = - configure_accounts(initial_authorities, initial_nominators, endowed_accounts, STASH); + configure_accounts(initial_authorities, initial_nominators, endowed_accounts); + const MAX_COLLECTIVE_SIZE: usize = 50; serde_json::json!({ "balances": { @@ -372,8 +382,8 @@ pub fn testnet_genesis( .collect::>(), }, "staking": { - "validatorCount": initial_authorities.len() as u32, - "minimumValidatorCount": initial_authorities.len() as u32, + "validatorCount": (initial_authorities.len()/2usize) as u32, + "minimumValidatorCount": 4, "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), "slashRewardFraction": Perbill::from_percent(10), "stakers": stakers.clone(), @@ -381,7 +391,7 @@ pub fn testnet_genesis( "elections": { "members": endowed_accounts .iter() - .take((num_endowed_accounts + 1) / 2) + .take(((num_endowed_accounts + 1) / 2).min(MAX_COLLECTIVE_SIZE)) .cloned() .map(|member| (member, STASH)) .collect::>(), @@ -389,7 +399,7 @@ pub fn testnet_genesis( "technicalCommittee": { "members": endowed_accounts .iter() - .take((num_endowed_accounts + 1) / 2) + .take(((num_endowed_accounts + 1) / 2).min(MAX_COLLECTIVE_SIZE)) .cloned() .collect::>(), }, @@ -410,12 +420,34 @@ pub fn testnet_genesis( } fn development_config_genesis_json() -> serde_json::Value { - testnet_genesis( - vec![authority_keys_from_seed("Alice")], - vec![], - Sr25519Keyring::Alice.to_account_id(), - None, - ) + if cfg!(feature = "staking-playground") { + let random_authorities_count = 100; + let random_nominators_count = 3000; + let mut random_authorities = (0..random_authorities_count) + .map(|i| authority_keys_from_seed(&format!("Random{}", i))) + .collect::>(); + let random_nominators = (0..random_nominators_count) + .map(|i| { + get_public_from_string_or_panic::(&format!("Random{}", i)).into() + }) + .collect::>(); + // Alice should also always be an authority. + random_authorities.push(authority_keys_from_seed("Alice")); + + testnet_genesis( + random_authorities, + random_nominators, + Sr25519Keyring::Alice.to_account_id(), + None, + ) + } else { + testnet_genesis( + vec![authority_keys_from_seed("Alice")], + vec![], + Sr25519Keyring::Alice.to_account_id(), + None, + ) + } } fn props() -> Properties { diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 6d377cc92cce1..d532384aef5ff 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -74,3 +74,5 @@ experimental = [ "pallet-example-tasks/experimental", ] metadata-hash = ["substrate-wasm-builder/metadata-hash"] +# Test temp feature to allow this chain to be used for swift testing of staking elections. +staking-playground = [] diff --git a/substrate/bin/node/runtime/src/constants.rs b/substrate/bin/node/runtime/src/constants.rs index d13dca48d1f12..42629d53500ce 100644 --- a/substrate/bin/node/runtime/src/constants.rs +++ b/substrate/bin/node/runtime/src/constants.rs @@ -63,7 +63,11 @@ pub mod time { // NOTE: Currently it is not possible to change the epoch duration after the chain has started. // Attempting to do so will brick block production. + #[cfg(not(feature = "staking-playground"))] pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; + #[cfg(feature = "staking-playground")] + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; + pub const EPOCH_DURATION_IN_SLOTS: u64 = { const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index d052e3581ac44..a4bcaa31afd5b 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -127,6 +127,7 @@ pub use pallet_balances::Call as BalancesCall; pub use pallet_staking::StakerStatus; #[cfg(any(feature = "std", test))] pub use pallet_sudo::Call as SudoCall; +use sp_keyring; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -663,16 +664,119 @@ impl_opaque_keys! { } } +#[cfg(feature = "staking-playground")] +pub mod staking_playground { + use pallet_staking::Exposure; + + use super::*; + + /// An adapter to make the chain work with --dev only, even though it is running a large staking + /// election. + /// + /// It will ignore the staking election and just set the validator set to alice. + /// + /// Needs to be fed into `type SessionManager`. + pub struct AliceAsOnlyValidator; + impl pallet_session::SessionManager for AliceAsOnlyValidator { + fn end_session(end_index: sp_staking::SessionIndex) { + >::end_session(end_index) + } + + fn new_session(new_index: sp_staking::SessionIndex) -> Option> { + >::new_session(new_index).map( + |_ignored_validators| { + vec![sp_keyring::Sr25519Keyring::AliceStash.to_account_id().into()] + }, + ) + } + + fn new_session_genesis(new_index: sp_staking::SessionIndex) -> Option> { + >::new_session_genesis(new_index) + .map(|_ignored_validators| { + vec![sp_keyring::Sr25519Keyring::AliceStash.to_account_id().into()] + }) + } + + fn start_session(start_index: sp_staking::SessionIndex) { + >::start_session(start_index) + } + } + + impl pallet_session::historical::SessionManager> + for AliceAsOnlyValidator + { + fn end_session(end_index: sp_staking::SessionIndex) { + , + >>::end_session(end_index) + } + + fn new_session( + new_index: sp_staking::SessionIndex, + ) -> Option)>> { + , + >>::new_session(new_index) + .map(|_ignored| { + // construct a fake exposure for alice. + vec![( + sp_keyring::Sr25519Keyring::AliceStash.to_account_id().into(), + pallet_staking::Exposure { + total: 1_000_000_000, + own: 1_000_000_000, + others: vec![], + }, + )] + }) + } + + fn new_session_genesis( + new_index: sp_staking::SessionIndex, + ) -> Option)>> { + , + >>::new_session_genesis(new_index) + .map(|_ignored| { + // construct a fake exposure for alice. + vec![( + sp_keyring::Sr25519Keyring::AliceStash.to_account_id().into(), + pallet_staking::Exposure { + total: 1_000_000_000, + own: 1_000_000_000, + others: vec![], + }, + )] + }) + } + + fn start_session(start_index: sp_staking::SessionIndex) { + , + >>::start_session(start_index) + } + } +} + impl pallet_session::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; type NextSessionRotation = Babe; - type SessionManager = pallet_session::historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; type WeightInfo = pallet_session::weights::SubstrateWeight; + #[cfg(not(feature = "staking-playground"))] + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + #[cfg(feature = "staking-playground")] + type SessionManager = pallet_session::historical::NoteHistoricalRoot< + Self, + staking_playground::AliceAsOnlyValidator, + >; } impl pallet_session::historical::Config for Runtime { @@ -691,8 +795,16 @@ pallet_staking_reward_curve::build! { ); } +#[cfg(not(feature = "staking-playground"))] parameter_types! { pub const SessionsPerEra: sp_staking::SessionIndex = 6; +} +#[cfg(feature = "staking-playground")] +parameter_types! { + pub const SessionsPerEra: sp_staking::SessionIndex = 2; +} + +parameter_types! { pub const BondingDuration: sp_staking::EraIndex = 24 * 28; pub const SlashDeferDuration: sp_staking::EraIndex = 24 * 7; // 1/4 the bonding duration. pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; @@ -851,6 +963,7 @@ impl Get> for OffchainRandomBalancing { pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { + type Sort = ConstBool; type System = Runtime; type Solver = SequentialPhragmen< AccountId, @@ -1204,7 +1317,7 @@ parameter_types! { // additional data per vote is 32 bytes (account id). pub const VotingBondFactor: Balance = deposit(0, 32); pub const TermDuration: BlockNumber = 7 * DAYS; - pub const DesiredMembers: u32 = 13; + pub const DesiredMembers: u32 = CouncilMaxMembers::get(); pub const DesiredRunnersUp: u32 = 7; pub const MaxVotesPerVoter: u32 = 16; pub const MaxVoters: u32 = 512; @@ -1488,7 +1601,7 @@ parameter_types! { pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); /// We prioritize im-online heartbeats over election solution submission. pub const StakingUnsignedPriority: TransactionPriority = TransactionPriority::max_value() / 2; - pub const MaxAuthorities: u32 = 100; + pub const MaxAuthorities: u32 = 1000; pub const MaxKeys: u32 = 10_000; pub const MaxPeerInHeartbeats: u32 = 10_000; } diff --git a/substrate/client/consensus/grandpa/src/aux_schema.rs b/substrate/client/consensus/grandpa/src/aux_schema.rs index c42310dcd72cf..8ec882591be9a 100644 --- a/substrate/client/consensus/grandpa/src/aux_schema.rs +++ b/substrate/client/consensus/grandpa/src/aux_schema.rs @@ -743,9 +743,7 @@ mod test { substrate_test_runtime_client::runtime::Block, _, _, - >( - &client, H256::random(), 0, || unreachable!() - ) + >(&client, H256::random(), 0, || unreachable!()) .unwrap(); assert_eq!( diff --git a/substrate/frame/election-provider-support/src/lib.rs b/substrate/frame/election-provider-support/src/lib.rs index 8b2edf4452a87..f5043e0e32c41 100644 --- a/substrate/frame/election-provider-support/src/lib.rs +++ b/substrate/frame/election-provider-support/src/lib.rs @@ -769,6 +769,27 @@ impl> TryFrom> } } +impl> BoundedSupport { + pub fn sorted_truncate_from(mut support: sp_npos_elections::Support) -> Self { + // If bounds meet, then short circuit. + if let Ok(bounded) = support.clone().try_into() { + return bounded + } + + // sort support based on stake of each backer, low to high. + support.voters.sort_by(|a, b| a.1.cmp(&b.1)); + // then do the truncation. + let mut bounded = Self { voters: Default::default(), total: 0 }; + while let Some((voter, weight)) = support.voters.pop() { + if let Err(_) = bounded.voters.try_push((voter, weight)) { + break + } + bounded.total += weight; + } + bounded + } +} + /// A bounded vector of [`BoundedSupport`]. /// /// A [`BoundedSupports`] is a set of [`sp_npos_elections::Supports`] which are bounded in two @@ -877,6 +898,35 @@ impl, BInner: Get> TryFrom, BInner: Get> + BoundedSupports +{ + pub fn sorted_truncate_from(supports: Supports) -> Self { + // if bounds, meet, short circuit + if let Ok(bounded) = supports.clone().try_into() { + return bounded + } + + // first, convert all inner supports. + let mut inner_supports = supports + .into_iter() + .map(|(account, support)| { + (account, BoundedSupport::::sorted_truncate_from(support)) + }) + .collect::>(); + + // then sort outer supports based on total stake, high to low + inner_supports.sort_by(|a, b| b.1.total.cmp(&a.1.total)); + + // then take the first slice that can fit. + BoundedSupports( + BoundedVec::<(AccountId, BoundedSupport), BOuter>::truncate_from( + inner_supports, + ), + ) + } +} + /// Same as `BoundedSupports` but parameterized by an `ElectionProvider`. pub type BoundedSupportsOf = BoundedSupports< ::AccountId, diff --git a/substrate/frame/election-provider-support/src/onchain.rs b/substrate/frame/election-provider-support/src/onchain.rs index 379dccee2ce69..c18f8e1d54bda 100644 --- a/substrate/frame/election-provider-support/src/onchain.rs +++ b/substrate/frame/election-provider-support/src/onchain.rs @@ -39,9 +39,8 @@ pub enum Error { NposElections(sp_npos_elections::Error), /// Errors from the data provider. DataProvider(&'static str), - /// Configurational error caused by `desired_targets` requested by data provider exceeding - /// `MaxWinners`. - TooManyWinners, + /// Results failed to meet the bounds. + FailedToBound, /// Election page index not supported. UnsupportedPageIndex, } @@ -65,6 +64,12 @@ pub type BoundedExecution = OnChainExecution; /// Configuration trait for an onchain election execution. pub trait Config { + /// Whether to try and sort or not. + /// + /// If `true`, the supports will be sorted by descending total support to meet the bounds. If + /// `false`, `FailedToBound` error may be returned. + type Sort: Get; + /// Needed for weight registration. type System: frame_system::Config; @@ -113,9 +118,9 @@ impl OnChainExecution { let desired_targets = T::DataProvider::desired_targets().map_err(Error::DataProvider)?; - if desired_targets > T::MaxWinnersPerPage::get() { - // early exit - return Err(Error::TooManyWinners) + if (desired_targets > T::MaxWinnersPerPage::get()) && !T::Sort::get() { + // early exit what will fail in the last line anyways. + return Err(Error::FailedToBound) } let voters_len = voters.len() as u32; @@ -145,12 +150,13 @@ impl OnChainExecution { DispatchClass::Mandatory, ); - // defensive: Since npos solver returns a result always bounded by `desired_targets`, this - // is never expected to happen as long as npos solver does what is expected for it to do. - let supports: BoundedSupportsOf = - to_supports(&staked).try_into().map_err(|_| Error::TooManyWinners)?; - - Ok(supports) + let unbounded = to_supports(&staked); + let bounded = if T::Sort::get() { + BoundedSupportsOf::::sorted_truncate_from(unbounded) + } else { + unbounded.try_into().map_err(|_| Error::FailedToBound)? + }; + Ok(bounded) } } @@ -197,6 +203,7 @@ mod tests { use super::*; use crate::{ElectionProvider, PhragMMS, SequentialPhragmen}; use frame_support::{assert_noop, derive_impl, parameter_types}; + use sp_io::TestExternalities; use sp_npos_elections::Support; use sp_runtime::Perbill; type AccountId = u64; @@ -247,10 +254,12 @@ mod tests { pub static MaxWinnersPerPage: u32 = 10; pub static MaxBackersPerWinner: u32 = 20; pub static DesiredTargets: u32 = 2; + pub static Sort: bool = false; pub static Bounds: ElectionBounds = ElectionBoundsBuilder::default().voters_count(600.into()).targets_count(400.into()).build(); } impl Config for PhragmenParams { + type Sort = Sort; type System = Runtime; type Solver = SequentialPhragmen; type DataProvider = mock_data_provider::DataProvider; @@ -261,6 +270,7 @@ mod tests { } impl Config for PhragMMSParams { + type Sort = Sort; type System = Runtime; type Solver = PhragMMS; type DataProvider = mock_data_provider::DataProvider; @@ -312,8 +322,8 @@ mod tests { #[test] fn onchain_seq_phragmen_works() { - sp_io::TestExternalities::new_empty().execute_with(|| { - let expected_suports = vec![ + TestExternalities::new_empty().execute_with(|| { + let expected_supports = vec![ ( 10 as AccountId, Support { total: 25, voters: vec![(1 as AccountId, 10), (3, 15)] }, @@ -325,28 +335,77 @@ mod tests { assert_eq!( as ElectionProvider>::elect(0).unwrap(), - expected_suports, + expected_supports, ); }) } #[test] - fn too_many_winners_when_desired_targets_exceed_max_winners() { - sp_io::TestExternalities::new_empty().execute_with(|| { - // given desired targets larger than max winners - DesiredTargets::set(10); - MaxWinnersPerPage::set(9); + fn sorting_false_works() { + TestExternalities::new_empty().execute_with(|| { + // Default results would have 3 targets, but we allow for only 2. + DesiredTargets::set(3); + MaxWinnersPerPage::set(2); + + assert_noop!( + as ElectionProvider>::elect(0), + Error::FailedToBound, + ); + }); + + TestExternalities::new_empty().execute_with(|| { + // Default results would have 2 backers per winner + MaxBackersPerWinner::set(1); assert_noop!( as ElectionProvider>::elect(0), - Error::TooManyWinners, + Error::FailedToBound, + ); + }); + } + + #[test] + fn sorting_true_works_winners() { + Sort::set(true); + + TestExternalities::new_empty().execute_with(|| { + let expected_supports = + vec![(30, Support { total: 35, voters: vec![(2, 20), (3, 15)] })] + .try_into() + .unwrap(); + + // we want to allow 1 winner only, and allow sorting. + MaxWinnersPerPage::set(1); + + assert_eq!( + as ElectionProvider>::elect(0).unwrap(), + expected_supports, + ); + }); + + MaxWinnersPerPage::set(10); + + TestExternalities::new_empty().execute_with(|| { + let expected_supports = vec![ + (30, Support { total: 20, voters: vec![(2, 20)] }), + (10 as AccountId, Support { total: 15, voters: vec![(3 as AccountId, 15)] }), + ] + .try_into() + .unwrap(); + + // we want to allow 2 winners only but 1 backer each, and allow sorting. + MaxBackersPerWinner::set(1); + + assert_eq!( + as ElectionProvider>::elect(0).unwrap(), + expected_supports, ); }) } #[test] fn onchain_phragmms_works() { - sp_io::TestExternalities::new_empty().execute_with(|| { + TestExternalities::new_empty().execute_with(|| { assert_eq!( as ElectionProvider>::elect(0).unwrap(), vec![ diff --git a/substrate/frame/election-provider-support/src/tests.rs b/substrate/frame/election-provider-support/src/tests.rs index 6e3deb9e38346..b2bf223ed2fae 100644 --- a/substrate/frame/election-provider-support/src/tests.rs +++ b/substrate/frame/election-provider-support/src/tests.rs @@ -18,10 +18,10 @@ //! Tests for solution-type. #![cfg(test)] - -use crate::{mock::*, IndexAssignment, NposSolution}; +use crate::{mock::*, BoundedSupports, IndexAssignment, NposSolution}; use frame_support::traits::ConstU32; use rand::SeedableRng; +use sp_npos_elections::{Support, Supports}; mod solution_type { use super::*; @@ -452,3 +452,26 @@ fn index_assignments_generate_same_solution_as_plain_assignments() { assert_eq!(solution, index_compact); } + +#[test] +fn sorted_truncate_from_works() { + let supports: Supports = vec![ + (1, Support { total: 303, voters: vec![(100, 100), (101, 101), (102, 102)] }), + (2, Support { total: 201, voters: vec![(100, 100), (101, 101)] }), + (3, Support { total: 406, voters: vec![(100, 100), (101, 101), (102, 102), (103, 103)] }), + ]; + + let bounded = BoundedSupports::, ConstU32<2>>::sorted_truncate_from(supports); + // we trim 2 as it has least total support, and trim backers based on stake. + assert_eq!( + bounded + .clone() + .into_iter() + .map(|(k, v)| (k, Support { total: v.total, voters: v.voters.into_inner() })) + .collect::>(), + vec![ + (3, Support { total: 205, voters: vec![(103, 103), (102, 102)] }), + (1, Support { total: 203, voters: vec![(102, 102), (101, 101)] }) + ] + ); +} From 5d642936c027037652daa661082a8bae4194bba2 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 15 Jan 2025 15:41:15 +0000 Subject: [PATCH 78/95] fix migration --- substrate/frame/staking/src/migrations.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index b9219b4acb80e..36a94bfdfc912 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -100,12 +100,15 @@ pub mod v17 { migrated_stashes.into(), ) } - } - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { - frame_support::ensure!(Pallet::::on_chain_storage_version() >= 17, "v17 not applied"); - Ok(()) + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), TryRuntimeError> { + frame_support::ensure!( + Pallet::::on_chain_storage_version() >= 17, + "v17 not applied" + ); + Ok(()) + } } pub type MigrateV16ToV17 = VersionedMigration< From 01adfe63a1d72fe3cf883f7c831e3ecce9086439 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 09:16:53 +0000 Subject: [PATCH 79/95] greenish CI now --- polkadot/runtime/test-runtime/src/lib.rs | 7 +++++-- polkadot/runtime/westend/src/lib.rs | 6 +++--- substrate/frame/babe/src/mock.rs | 6 ++++-- substrate/frame/beefy/src/mock.rs | 6 ++++-- substrate/frame/delegated-staking/src/mock.rs | 3 ++- .../election-provider-multi-phase/src/mock.rs | 3 ++- .../test-staking-e2e/src/mock.rs | 19 +++++++++++++++---- substrate/frame/fast-unstake/src/mock.rs | 4 ++-- substrate/frame/grandpa/src/mock.rs | 6 ++++-- .../test-delegate-stake/src/mock.rs | 2 +- .../test-transfer-stake/src/mock.rs | 2 +- substrate/frame/root-offences/src/mock.rs | 5 ++++- substrate/frame/staking/src/mock.rs | 2 ++ 13 files changed, 49 insertions(+), 22 deletions(-) diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index 4f9ba8d8508cd..233ebb03034a1 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -77,7 +77,7 @@ use polkadot_runtime_common::{ use polkadot_runtime_parachains::reward_points::RewardValidatorsWithEraPoints; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_beefy::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; -use sp_core::{ConstU32, OpaqueMetadata}; +use sp_core::{ConstBool, ConstU32, OpaqueMetadata}; use sp_mmr_primitives as mmr; use sp_runtime::{ curve::PiecewiseLinear, @@ -359,7 +359,9 @@ impl onchain::Config for OnChainSeqPhragmen { type DataProvider = Staking; type WeightInfo = (); type Bounds = ElectionBoundsOnChain; - type MaxWinners = OnChainMaxWinners; + type MaxWinnersPerPage = OnChainMaxWinners; + type MaxBackersPerWinner = ConstU32<{ u32::MAX }>; + type Sort = ConstBool; } /// Upper limit on the number of NPOS nominations. @@ -396,6 +398,7 @@ impl pallet_staking::Config for Runtime { type EventListeners = (); type WeightInfo = (); type DisablingStrategy = pallet_staking::UpToLimitWithReEnablingDisablingStrategy; + type MaxValidatorSet = MaxAuthorities; } parameter_types! { diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 88f722e75a9a3..917f1689b1c03 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -94,7 +94,7 @@ use sp_consensus_beefy::{ ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}, mmr::{BeefyDataProvider, MmrLeafVersion}, }; -use sp_core::{ConstU8, OpaqueMetadata, RuntimeDebug, H256}; +use sp_core::{ConstBool, ConstU8, OpaqueMetadata, RuntimeDebug, H256}; use sp_runtime::{ generic, impl_opaque_keys, traits::{ @@ -600,6 +600,7 @@ frame_election_provider_support::generate_solution_type!( pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { + type Sort = ConstBool; type System = Runtime; type Solver = SequentialPhragmen; type DataProvider = Staking; @@ -1150,8 +1151,7 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | - RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) diff --git a/substrate/frame/babe/src/mock.rs b/substrate/frame/babe/src/mock.rs index 23857470adc4a..12a9fc0ae179c 100644 --- a/substrate/frame/babe/src/mock.rs +++ b/substrate/frame/babe/src/mock.rs @@ -31,7 +31,7 @@ use pallet_session::historical as pallet_session_historical; use sp_consensus_babe::{AuthorityId, AuthorityPair, Randomness, Slot, VrfSignature}; use sp_core::{ crypto::{Pair, VrfSecret}, - U256, + ConstBool, U256, }; use sp_io; use sp_runtime::{ @@ -151,7 +151,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = ConstBool; type Bounds = ElectionsBounds; } diff --git a/substrate/frame/beefy/src/mock.rs b/substrate/frame/beefy/src/mock.rs index 7ae41c609180e..369e171f81cc2 100644 --- a/substrate/frame/beefy/src/mock.rs +++ b/substrate/frame/beefy/src/mock.rs @@ -29,7 +29,7 @@ use frame_support::{ }; use frame_system::pallet_prelude::HeaderFor; use pallet_session::historical as pallet_session_historical; -use sp_core::{crypto::KeyTypeId, ConstU128}; +use sp_core::{crypto::KeyTypeId, ConstBool, ConstU128}; use sp_runtime::{ app_crypto::ecdsa::Public, curve::PiecewiseLinear, @@ -228,7 +228,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = ConstBool; type Bounds = ElectionsBoundsOnChain; } diff --git a/substrate/frame/delegated-staking/src/mock.rs b/substrate/frame/delegated-staking/src/mock.rs index a7363698e0747..95e6833432928 100644 --- a/substrate/frame/delegated-staking/src/mock.rs +++ b/substrate/frame/delegated-staking/src/mock.rs @@ -32,7 +32,7 @@ use frame_election_provider_support::{ }; use frame_support::dispatch::RawOrigin; use pallet_staking::{ActiveEra, ActiveEraInfo, CurrentEra}; -use sp_core::U256; +use sp_core::{ConstBool, U256}; use sp_runtime::traits::Convert; use sp_staking::{Agent, Stake, StakingInterface}; @@ -98,6 +98,7 @@ impl onchain::Config for OnChainSeqPhragmen { type WeightInfo = (); type MaxWinnersPerPage = ConstU32<100>; type MaxBackersPerWinner = ConstU32<100>; + type Sort = ConstBool; type Bounds = ElectionsBoundsOnChain; } diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 20fe4016375c8..c408296e48346 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -35,7 +35,7 @@ use sp_core::{ testing::{PoolState, TestOffchainExt, TestTransactionPoolExt}, OffchainDbExt, OffchainWorkerExt, TransactionPoolExt, }, - H256, + ConstBool, H256, }; use sp_npos_elections::{ assignment_ratio_to_staked_normalized, seq_phragmen, to_supports, BalancingConfig, @@ -313,6 +313,7 @@ impl onchain::Config for OnChainSeqPhragmen { type WeightInfo = (); type MaxWinnersPerPage = MaxWinners; type MaxBackersPerWinner = MaxBackersPerWinner; + type Sort = ConstBool; type Bounds = OnChainElectionsBounds; } diff --git a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs index eaab848c16944..9d354f4cf6dab 100644 --- a/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/test-staking-e2e/src/mock.rs @@ -23,7 +23,7 @@ use frame_support::{ weights::constants, }; use frame_system::EnsureRoot; -use sp_core::{ConstU32, Get}; +use sp_core::{ConstBool, ConstU32, Get}; use sp_npos_elections::{ElectionScore, VoteWeight}; use sp_runtime::{ offchain::{ @@ -168,6 +168,8 @@ parameter_types! { pub static TransactionPriority: transaction_validity::TransactionPriority = 1; #[derive(Debug)] pub static MaxWinners: u32 = 100; + #[derive(Debug)] + pub static MaxBackersPerWinner: u32 = 100; pub static MaxVotesPerVoter: u32 = 16; pub static SignedFixedDeposit: Balance = 1; pub static SignedDepositIncreaseFactor: Percent = Percent::from_percent(10); @@ -196,12 +198,18 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SlashHandler = (); type RewardHandler = (); type DataProvider = Staking; - type Fallback = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, MaxWinners)>; + type Fallback = frame_election_provider_support::NoElection<( + AccountId, + BlockNumber, + Staking, + MaxWinners, + MaxBackersPerWinner, + )>; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen, ()>; type ForceOrigin = EnsureRoot; type MaxWinners = MaxWinners; + type MaxBackersPerWinner = MaxBackersPerWinner; type ElectionBounds = ElectionBounds; type BenchmarkingConfig = NoopElectionProviderBenchmarkConfig; type WeightInfo = (); @@ -215,6 +223,7 @@ impl MinerConfig for Runtime { type MaxLength = MinerMaxLength; type MaxWeight = MinerMaxWeight; type MaxWinners = MaxWinners; + type MaxBackersPerWinner = MaxBackersPerWinner; fn solution_weight(_v: u32, _t: u32, _a: u32, _d: u32) -> Weight { Weight::zero() @@ -334,6 +343,9 @@ parameter_types! { } impl onchain::Config for OnChainSeqPhragmen { + type MaxWinnersPerPage = MaxWinners; + type MaxBackersPerWinner = MaxBackersPerWinner; + type Sort = ConstBool; type System = Runtime; type Solver = SequentialPhragmen< AccountId, @@ -341,7 +353,6 @@ impl onchain::Config for OnChainSeqPhragmen { >; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = MaxWinners; type Bounds = ElectionBounds; } diff --git a/substrate/frame/fast-unstake/src/mock.rs b/substrate/frame/fast-unstake/src/mock.rs index 2104cfb46bed7..0b711bf4aa31d 100644 --- a/substrate/frame/fast-unstake/src/mock.rs +++ b/substrate/frame/fast-unstake/src/mock.rs @@ -203,7 +203,7 @@ impl ExtBuilder { (v, Exposure { total: 0, own: 0, others }) }) .for_each(|(validator, exposure)| { - pallet_staking::EraInfo::::set_exposure(era, &validator, exposure); + pallet_staking::EraInfo::::upsert_exposure(era, &validator, exposure); }); } @@ -301,7 +301,7 @@ pub fn create_exposed_nominator(exposed: AccountId, era: u32) { // create an exposed nominator in passed era let mut exposure = pallet_staking::EraInfo::::get_full_exposure(era, &VALIDATORS_PER_ERA); exposure.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); - pallet_staking::EraInfo::::set_exposure(era, &VALIDATORS_PER_ERA, exposure); + pallet_staking::EraInfo::::upsert_exposure(era, &VALIDATORS_PER_ERA, exposure); Balances::make_free_balance_be(&exposed, 100); assert_ok!(Staking::bond( diff --git a/substrate/frame/grandpa/src/mock.rs b/substrate/frame/grandpa/src/mock.rs index 87369c23948ca..309383d475dcc 100644 --- a/substrate/frame/grandpa/src/mock.rs +++ b/substrate/frame/grandpa/src/mock.rs @@ -32,7 +32,7 @@ use frame_support::{ }; use pallet_session::historical as pallet_session_historical; use sp_consensus_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID}; -use sp_core::H256; +use sp_core::{ConstBool, H256}; use sp_keyring::Ed25519Keyring; use sp_runtime::{ curve::PiecewiseLinear, @@ -155,7 +155,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = ConstBool; type Bounds = ElectionsBoundsOnChain; } diff --git a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs index d1bc4ef8ff281..370e1aa1b84b3 100644 --- a/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-delegate-stake/src/mock.rs @@ -98,7 +98,7 @@ impl pallet_staking::Config for Runtime { type BondingDuration = BondingDuration; type EraPayout = pallet_staking::ConvertCurve; type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, (), ())>; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs index d913c5fe6948c..8e545f7dffa93 100644 --- a/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs +++ b/substrate/frame/nomination-pools/test-transfer-stake/src/mock.rs @@ -90,7 +90,7 @@ impl pallet_staking::Config for Runtime { type BondingDuration = BondingDuration; type EraPayout = pallet_staking::ConvertCurve; type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, (), ())>; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/substrate/frame/root-offences/src/mock.rs b/substrate/frame/root-offences/src/mock.rs index 7a96b8eade4e1..e64adc8fcc3bf 100644 --- a/substrate/frame/root-offences/src/mock.rs +++ b/substrate/frame/root-offences/src/mock.rs @@ -28,6 +28,7 @@ use frame_support::{ traits::{ConstU32, ConstU64, OneSessionHandler}, }; use pallet_staking::StakerStatus; +use sp_core::ConstBool; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{EraIndex, SessionIndex}; @@ -110,7 +111,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = ConstBool; type Bounds = ElectionsBounds; } diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 4750f7e1438ad..90c35413b66b1 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -32,6 +32,7 @@ use frame_support::{ weights::constants::RocksDbWeight, }; use frame_system::{EnsureRoot, EnsureSignedBy}; +use sp_core::ConstBool; use sp_io; use sp_runtime::{curve::PiecewiseLinear, testing::UintAuthorityId, traits::Zero, BuildStorage}; use sp_staking::{ @@ -290,6 +291,7 @@ impl onchain::Config for OnChainSeqPhragmen { type DataProvider = Staking; type WeightInfo = (); type Bounds = ElectionsBounds; + type Sort = ConstBool; type MaxBackersPerWinner = ConstU32<{ u32::MAX }>; type MaxWinnersPerPage = MaxWinnersPerPage; } From eedd03a31d2409c4f1375b6d624633f48f8038d4 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 09:17:25 +0000 Subject: [PATCH 80/95] fmt --- polkadot/runtime/westend/src/lib.rs | 3 ++- substrate/client/consensus/grandpa/src/aux_schema.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 917f1689b1c03..5256799f12365 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1151,7 +1151,8 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | + RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) diff --git a/substrate/client/consensus/grandpa/src/aux_schema.rs b/substrate/client/consensus/grandpa/src/aux_schema.rs index 8ec882591be9a..c42310dcd72cf 100644 --- a/substrate/client/consensus/grandpa/src/aux_schema.rs +++ b/substrate/client/consensus/grandpa/src/aux_schema.rs @@ -743,7 +743,9 @@ mod test { substrate_test_runtime_client::runtime::Block, _, _, - >(&client, H256::random(), 0, || unreachable!()) + >( + &client, H256::random(), 0, || unreachable!() + ) .unwrap(); assert_eq!( From 33a37e69872e61a7bb485779ee97ae6f0ba20c9a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 09:18:25 +0000 Subject: [PATCH 81/95] fix unused import --- substrate/bin/node/runtime/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index a4bcaa31afd5b..b11dcd0448c1f 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -127,7 +127,6 @@ pub use pallet_balances::Call as BalancesCall; pub use pallet_staking::StakerStatus; #[cfg(any(feature = "std", test))] pub use pallet_sudo::Call as SudoCall; -use sp_keyring; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; From 7df54f14caf65ccd2f3c43f03b8325073b100a34 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 09:25:11 +0000 Subject: [PATCH 82/95] fix some benchmarks too --- substrate/frame/nomination-pools/benchmarking/src/mock.rs | 2 +- substrate/frame/offences/benchmarking/src/mock.rs | 5 ++++- substrate/frame/session/benchmarking/src/mock.rs | 5 ++++- substrate/frame/staking/src/benchmarking.rs | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/substrate/frame/nomination-pools/benchmarking/src/mock.rs b/substrate/frame/nomination-pools/benchmarking/src/mock.rs index 15d9e2c56031f..da7ce57d977c9 100644 --- a/substrate/frame/nomination-pools/benchmarking/src/mock.rs +++ b/substrate/frame/nomination-pools/benchmarking/src/mock.rs @@ -84,7 +84,7 @@ impl pallet_staking::Config for Runtime { type AdminOrigin = frame_system::EnsureRoot; type EraPayout = pallet_staking::ConvertCurve; type ElectionProvider = - frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, ())>; + frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking, (), ())>; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = VoterList; type TargetList = pallet_staking::UseValidatorsMap; diff --git a/substrate/frame/offences/benchmarking/src/mock.rs b/substrate/frame/offences/benchmarking/src/mock.rs index c5c178aa4443d..0fde556671b81 100644 --- a/substrate/frame/offences/benchmarking/src/mock.rs +++ b/substrate/frame/offences/benchmarking/src/mock.rs @@ -111,6 +111,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); + pub const Sort: bool = true; } pub struct OnChainSeqPhragmen; @@ -119,7 +120,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = Sort; type Bounds = ElectionsBounds; } diff --git a/substrate/frame/session/benchmarking/src/mock.rs b/substrate/frame/session/benchmarking/src/mock.rs index 346cd04c0fa9e..253fff1623a6b 100644 --- a/substrate/frame/session/benchmarking/src/mock.rs +++ b/substrate/frame/session/benchmarking/src/mock.rs @@ -119,6 +119,7 @@ pallet_staking_reward_curve::build! { parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); + pub const Sort: bool = true; } pub struct OnChainSeqPhragmen; @@ -127,7 +128,9 @@ impl onchain::Config for OnChainSeqPhragmen { type Solver = SequentialPhragmen; type DataProvider = Staking; type WeightInfo = (); - type MaxWinners = ConstU32<100>; + type MaxWinnersPerPage = ConstU32<100>; + type MaxBackersPerWinner = ConstU32<100>; + type Sort = Sort; type Bounds = ElectionsBounds; } diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 606c93e3fc00b..7dd7addeb7363 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -1251,7 +1251,7 @@ mod tests { false, false, RewardDestination::Staked, - CurrentEra::::get().unwrap(), + CurrentEra::::get().unwrap(), ) .unwrap(); @@ -1284,7 +1284,7 @@ mod tests { false, false, RewardDestination::Staked, - CurrentEra::::get().unwrap(), + CurrentEra::::get().unwrap(), ) .unwrap(); From 1b5ddc6de2124213c0a056b61010648d3c849c39 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 09:27:35 +0000 Subject: [PATCH 83/95] better doc --- substrate/bin/node/runtime/Cargo.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index d532384aef5ff..07c97f8c271e7 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -74,5 +74,9 @@ experimental = [ "pallet-example-tasks/experimental", ] metadata-hash = ["substrate-wasm-builder/metadata-hash"] -# Test temp feature to allow this chain to be used for swift testing of staking elections. +# Test temp feature to allow this chain to be used for swift testing of staking elections. should +# only be run by --dev chain. It will create a large staking election process as per the constants +# in `chain_spec.rs`, but `Alice` will be the only authority that is communicated to the node and +# ergo block production works fine with --dev and is independent of staking election. See ` pub +# struct AliceAsOnlyValidator`. staking-playground = [] From c5efc26411ebe1ee55000643d3d5fac519d3dfdf Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 16 Jan 2025 14:47:31 +0000 Subject: [PATCH 84/95] fix tests and a bug --- substrate/bin/node/runtime/src/lib.rs | 8 +- .../election-provider-multi-phase/src/lib.rs | 19 ++-- substrate/frame/staking/src/benchmarking.rs | 13 ++- substrate/frame/staking/src/pallet/impls.rs | 90 +++---------------- substrate/frame/staking/src/pallet/mod.rs | 35 +++++--- substrate/frame/staking/src/tests.rs | 9 +- .../frame/staking/src/tests_paged_election.rs | 79 +++------------- 7 files changed, 76 insertions(+), 177 deletions(-) diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b11dcd0448c1f..b12c488584c40 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1018,7 +1018,13 @@ impl pallet_election_provider_multi_phase::Config for Runtime { type SlashHandler = (); // burn slashes type RewardHandler = (); // rewards are minted from the void type DataProvider = Staking; - type Fallback = onchain::OnChainExecution; + type Fallback = frame_election_provider_support::NoElection<( + AccountId, + BlockNumber, + Staking, + MaxActiveValidators, + MaxBackersPerWinner, + )>; type GovernanceFallback = onchain::OnChainExecution; type Solver = SequentialPhragmen, OffchainRandomBalancing>; type ForceOrigin = EnsureRootOrHalfCouncil; diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index ae1d3edb794b2..e2351252efa3a 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -778,9 +778,10 @@ pub mod pallet { log!( trace, - "current phase {:?}, next election {:?}, metadata: {:?}", + "current phase {:?}, next election {:?}, queued? {:?}, metadata: {:?}", current_phase, next_election, + QueuedSolution::::get().map(|rs| (rs.supports.len(), rs.compute, rs.score)), SnapshotMetadata::::get() ); match current_phase { @@ -1652,6 +1653,7 @@ impl Pallet { QueuedSolution::::take() .ok_or(ElectionError::::NothingQueued) .or_else(|_| { + log!(warn, "No solution queued, falling back to instant fallback.",); // default data provider bounds are unbounded. calling `instant_elect` with // unbounded data provider bounds means that the on-chain `T:Bounds` configs will // *not* be overwritten. @@ -1670,16 +1672,12 @@ impl Pallet { }) .map(|ReadySolution { compute, score, supports }| { Self::deposit_event(Event::ElectionFinalized { compute, score }); - if Round::::get() != 1 { - log!(info, "Finalized election round with compute {:?}.", compute); - } + log!(info, "Finalized election round with compute {:?}.", compute); supports }) .map_err(|err| { Self::deposit_event(Event::ElectionFailed); - if Round::::get() != 1 { - log!(warn, "Failed to finalize election round. reason {:?}", err); - } + log!(warn, "Failed to finalize election round. reason {:?}", err); err }) } @@ -1790,7 +1788,7 @@ impl ElectionProvider for Pallet { // Note: this pallet **MUST** only by used in the single-page mode. ensure!(page == SINGLE_PAGE, ElectionError::::MultiPageNotSupported); - match Self::do_elect() { + let res = match Self::do_elect() { Ok(bounded_supports) => { // All went okay, record the weight, put sign to be Off, clean snapshot, etc. Self::weigh_supports(&bounded_supports); @@ -1802,7 +1800,10 @@ impl ElectionProvider for Pallet { Self::phase_transition(Phase::Emergency); Err(why) }, - } + }; + + log!(info, "ElectionProvider::elect({}) => {:?}", page, res.as_ref().map(|s| s.len())); + res } fn ongoing() -> bool { diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 7dd7addeb7363..7e7e5b59d5614 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -227,7 +227,7 @@ mod benchmarks { #[benchmark] fn on_initialize_noop() { assert!(ElectableStashes::::get().is_empty()); - assert_eq!(ElectingStartedAt::::get(), None); + assert_eq!(NextElectionPage::::get(), None); #[block] { @@ -235,7 +235,7 @@ mod benchmarks { } assert!(ElectableStashes::::get().is_empty()); - assert_eq!(ElectingStartedAt::::get(), None); + assert_eq!(NextElectionPage::::get(), None); } #[benchmark] @@ -272,14 +272,14 @@ mod benchmarks { } ElectableStashes::::set(stashes); - ElectingStartedAt::::set(Some(10u32.into())); + NextElectionPage::::set(Some(10u32.into())); #[block] { Pallet::::clear_election_metadata() } - assert!(ElectingStartedAt::::get().is_none()); + assert!(NextElectionPage::::get().is_none()); assert!(ElectableStashes::::get().is_empty()); Ok(()) @@ -1245,20 +1245,19 @@ mod tests { ExtBuilder::default().build_and_execute(|| { let n = 10; + let current_era = CurrentEra::::get().unwrap(); let (validator_stash, nominators) = create_validator_with_nominators::( n, <::MaxExposurePageSize as Get<_>>::get(), false, false, RewardDestination::Staked, - CurrentEra::::get().unwrap(), + current_era, ) .unwrap(); assert_eq!(nominators.len() as u32, n); - let current_era = CurrentEra::::get().unwrap(); - let original_stakeable_balance = asset::stakeable_balance::(&validator_stash); assert_ok!(Staking::payout_stakers_by_page( RuntimeOrigin::signed(1337), diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 62ded203fdb92..96fb59abbf7d4 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -81,7 +81,8 @@ impl Pallet { /// Clears up all election preparation metadata in storage. pub(crate) fn clear_election_metadata() { - ElectingStartedAt::::kill(); + // TODO: voter snapshot status should also be killed? + NextElectionPage::::kill(); ElectableStashes::::kill(); } @@ -640,10 +641,9 @@ impl Pallet { // Clean old era information. if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { + log!(trace, "Removing era information for {:?}", old_era); Self::clear_era_information(old_era); } - // Including election prep metadata. - Self::clear_election_metadata(); } /// Potentially plan a new era. @@ -713,12 +713,13 @@ impl Pallet { _ => {}, } // election failed, clear election prep metadata. - Self::clear_election_metadata(); Self::deposit_event(Event::StakingElectionFailed); + Self::clear_election_metadata(); None } else { Self::deposit_event(Event::StakersElected); + Self::clear_election_metadata(); Self::trigger_new_era(start_session_index); Some(validators) @@ -737,7 +738,7 @@ impl Pallet { /// result of the election. We ensure that only the winners that are part of the electable /// stashes have exposures collected for the next era. pub(crate) fn do_elect_paged(page: PageIndex) -> Weight { - let paged_result = match ::elect(page) { + let paged_result = match T::ElectionProvider::elect(page) { Ok(result) => result, Err(e) => { log!(warn, "election provider page failed due to {:?} (page: {})", e, page); @@ -2166,77 +2167,14 @@ impl Pallet { } /// Invariants: - /// * If the election preparation has started (i.e. `now` >= `expected_election - n_pages`): - /// * The election preparation metadata should be set (`ElectingStartedAt`); - /// * The electable stashes should not be empty; - /// * The exposures for the current electable stashes should have been collected; - /// * If the election preparation has not started yet: - /// * The election preparation metadata is empty; - /// * The electable stashes for this era is empty; - pub fn ensure_snapshot_metadata_state(now: BlockNumberFor) -> Result<(), TryRuntimeError> { - let pages: BlockNumberFor = Self::election_pages().into(); - let next_election = ::next_election_prediction(now); - let expect_election_start_at = next_election.saturating_sub(pages); - - let election_prep_started = now >= expect_election_start_at; - - if !election_prep_started { - // election prep should have not been started yet, no metadata in storage. - ensure!( - ElectableStashes::::get().is_empty(), - "unexpected electable stashes in storage while election prep hasn't started." - ); - ensure!( - ElectingStartedAt::::get().is_none(), - "unexpected election metadata while election prep hasn't started.", - ); - ensure!( - VoterSnapshotStatus::::get() == SnapshotStatus::Waiting, - "unexpected voter snapshot status in storage." - ); - - return Ok(()) - } - - // from now on, we expect the election to have started. check election metadata, electable - // targets and era exposures. - let maybe_electing_started = ElectingStartedAt::::get(); - - if maybe_electing_started.is_none() { - return Err( - "election prep should have started already, but no election metadata in storage." - .into(), - ); - } - - let started_at = maybe_electing_started.unwrap(); - - ensure!( - started_at == expect_election_start_at, - "unexpected electing_started_at block number in storage." - ); - ensure!( - !ElectableStashes::::get().is_empty(), - "election should have been started and the electable stashes non empty." - ); - - // all the current electable stashes exposures should have been collected and - // stored for the next era, and their total exposure should be > 0. - for s in ElectableStashes::::get().iter() { - ensure!( - EraInfo::::get_paged_exposure( - Self::current_era().unwrap_or_default().saturating_add(1), - s, - 0 - ) - .defensive_proof("electable stash exposure does not exist, unexpected.") - .unwrap() - .exposure_metadata - .total != Zero::zero(), - "no exposures collected for an electable stash." - ); - } - + /// + /// Test invariants of: + /// + /// - `NextElectionPage` + /// - `ElectableStashes` + /// - `VoterSnapshotStatus` + pub fn ensure_snapshot_metadata_state(_now: BlockNumberFor) -> Result<(), TryRuntimeError> { + // TODO: Ok(()) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 62de4a0d3d45e..3e053ac64120e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -31,7 +31,7 @@ use frame_support::{ }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ - traits::{One, SaturatedConversion, StaticLookup, Zero}, + traits::{SaturatedConversion, StaticLookup, Zero}, ArithmeticError, Perbill, Percent, Saturating, }; @@ -739,10 +739,12 @@ pub mod pallet { /// Keeps track of an ongoing multi-page election solution request. /// - /// Stores the block number of when the first election page was requested. `None` indicates - /// that the election results haven't started to be fetched. + /// If `Some(_)``, it is the next page that we intend to elect. If `None`, we are not in the + /// election process. + /// + /// This is only set in multi-block elections. Should always be `None` otherwise. #[pallet::storage] - pub(crate) type ElectingStartedAt = StorageValue<_, BlockNumberFor, OptionQuery>; + pub(crate) type NextElectionPage = StorageValue<_, PageIndex, OptionQuery>; /// A bounded list of the "electable" stashes that resulted from a successful election. #[pallet::storage] @@ -1016,27 +1018,34 @@ pub mod pallet { /// that the `ElectableStashes` has been populated with all validators from all pages at /// the time of the election. fn on_initialize(now: BlockNumberFor) -> Weight { - let pages: BlockNumberFor = Self::election_pages().into(); + let pages = Self::election_pages(); + crate::log!( + trace, + "now: {:?}, NextElectionPage: {:?}", + now, + NextElectionPage::::get() + ); // election ongoing, fetch the next page. - let inner_weight = if let Some(started_at) = ElectingStartedAt::::get() { - let next_page = - pages.saturating_sub(One::one()).saturating_sub(now.saturating_sub(started_at)); - - Self::do_elect_paged(next_page.saturated_into::()) + let inner_weight = if let Some(next_page) = NextElectionPage::::get() { + let next_next_page = next_page.checked_sub(1); + NextElectionPage::::set(next_next_page); + Self::do_elect_paged(next_page) } else { // election isn't ongoing yet, check if it should start. let next_election = ::next_election_prediction(now); - if now == (next_election.saturating_sub(pages)) { + if now == (next_election.saturating_sub(pages.into())) { crate::log!( trace, "elect(): start fetching solution pages. expected pages: {:?}", pages ); - ElectingStartedAt::::set(Some(now)); - Self::do_elect_paged(pages.saturated_into::().saturating_sub(1)) + let current_page = pages.saturating_sub(1); + let next_page = current_page.checked_sub(1); + NextElectionPage::::set(next_page); + Self::do_elect_paged(current_page) } else { Weight::default() } diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 00b618b9b0837..690d8983dd315 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -3080,6 +3080,7 @@ fn deferred_slashes_are_deferred() { staking_events_since_last_call().as_slice(), &[ Event::SlashReported { validator: 11, slash_era: 1, .. }, + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, .., Event::Slashed { staker: 11, amount: 100 }, @@ -3416,6 +3417,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert_eq!( staking_events_since_last_call(), vec![ + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::SlashReported { @@ -3489,6 +3491,7 @@ fn non_slashable_offence_disables_validator() { assert_eq!( staking_events_since_last_call(), vec![ + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::SlashReported { @@ -3569,6 +3572,7 @@ fn slashing_independent_of_disabling_validator() { assert_eq!( staking_events_since_last_call(), vec![ + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::SlashReported { @@ -5560,7 +5564,6 @@ mod election_data_provider { // election run_to_block(20); assert_eq!(Staking::next_election_prediction(System::block_number()), 45); - assert_eq!(staking_events().len(), 1); assert_eq!(*staking_events().last().unwrap(), Event::StakersElected); for b in 21..45 { @@ -5571,7 +5574,6 @@ mod election_data_provider { // election run_to_block(45); assert_eq!(Staking::next_election_prediction(System::block_number()), 70); - assert_eq!(staking_events().len(), 3); assert_eq!(*staking_events().last().unwrap(), Event::StakersElected); Staking::force_no_eras(RuntimeOrigin::root()).unwrap(); @@ -5594,7 +5596,6 @@ mod election_data_provider { MinimumValidatorCount::::put(2); run_to_block(55); assert_eq!(Staking::next_election_prediction(System::block_number()), 55 + 25); - assert_eq!(staking_events().len(), 10); assert_eq!( *staking_events().last().unwrap(), Event::ForceEra { mode: Forcing::NotForcing } @@ -8630,6 +8631,7 @@ fn reenable_lower_offenders_mock() { assert_eq!( staking_events_since_last_call(), vec![ + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::SlashReported { @@ -8706,6 +8708,7 @@ fn do_not_reenable_higher_offenders_mock() { assert_eq!( staking_events_since_last_call(), vec![ + Event::PagedElectionProceeded { page: 0, result: Ok(()) }, Event::StakersElected, Event::EraPaid { era_index: 0, validator_payout: 11075, remainder: 33225 }, Event::SlashReported { diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 12dcfcfe6751d..0477cb20e2d7d 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -16,7 +16,7 @@ // limitations under the License. use crate::{mock::*, *}; -use frame_support::{assert_ok, testing_prelude::*, BoundedBTreeSet}; +use frame_support::{assert_ok, testing_prelude::*}; use substrate_test_utils::assert_eq_uvec; use frame_election_provider_support::{ @@ -145,7 +145,7 @@ mod paged_on_initialize { // 1. election prep hasn't started yet, election cursor and electable stashes are // not set yet. run_to_block(8); - assert_eq!(ElectingStartedAt::::get(), None); + assert_eq!(NextElectionPage::::get(), None); assert!(ElectableStashes::::get().is_empty()); assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); @@ -156,8 +156,8 @@ mod paged_on_initialize { run_to_block(9); assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); - // electing started at cursor is set once the election starts to be prepared. - assert_eq!(ElectingStartedAt::::get(), Some(9)); + // electing started, but since single-page, we don't set `NextElectionPage` at all. + assert_eq!(NextElectionPage::::get(), None); // now the electable stashes have been fetched and stored. assert_eq_uvec!( ElectableStashes::::get().into_iter().collect::>(), @@ -173,7 +173,7 @@ mod paged_on_initialize { assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 1); // clears out election metadata for era. - assert!(ElectingStartedAt::::get().is_none()); + assert!(NextElectionPage::::get().is_none()); assert!(ElectableStashes::::get().into_iter().collect::>().is_empty()); assert_eq!(VoterSnapshotStatus::::get(), SnapshotStatus::Waiting); @@ -231,7 +231,7 @@ mod paged_on_initialize { assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); assert_eq!(current_era(), 0); // election haven't started yet. - assert_eq!(ElectingStartedAt::::get(), None); + assert_eq!(NextElectionPage::::get(), None); assert!(ElectableStashes::::get().is_empty()); // progress to era rotation session. @@ -347,7 +347,7 @@ mod paged_on_initialize { // not set yet. run_to_block(6); assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); - assert_eq!(ElectingStartedAt::::get(), None); + assert_eq!(NextElectionPage::::get(), None); assert!(ElectableStashes::::get().is_empty()); // 2. starts preparing election at the (election_prediction - n_pages) block. @@ -356,7 +356,7 @@ mod paged_on_initialize { assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // electing started at cursor is set once the election starts to be prepared. - assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + assert_eq!(NextElectionPage::::get(), Some(1)); // now the electable stashes started to be fetched and stored. assert_eq_uvec!( ElectableStashes::::get().into_iter().collect::>(), @@ -379,7 +379,7 @@ mod paged_on_initialize { expected_elected ); // election cursor reamins unchanged during intermediate pages. - assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + assert_eq!(NextElectionPage::::get(), Some(0)); // exposures have been collected for all validators in the page. for s in expected_elected.iter() { // 2 pages fetched, 2 `other` exposures collected per electable stash. @@ -399,7 +399,7 @@ mod paged_on_initialize { // 3 pages fetched, 3 `other` exposures collected per electable stash. assert_eq!(Staking::eras_stakers(current_era() + 1, s).others.len(), 3); } - assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); + assert_eq!(NextElectionPage::::get(), None); assert_eq!(staking_events_since_last_call(), vec![ Event::PagedElectionProceeded { page: 2, result: Ok(()) }, Event::PagedElectionProceeded { page: 1, result: Ok(()) }, @@ -409,13 +409,12 @@ mod paged_on_initialize { // upon fetching page 0, the electing started will remain in storage until the // era rotates. assert_eq!(current_era(), 0); - assert_eq!(ElectingStartedAt::::get(), Some(next_election - pages)); // Next block the era will rotate. run_to_block(10); assert_ok!(Staking::ensure_snapshot_metadata_state(System::block_number())); // and all the metadata has been cleared up and ready for the next election. - assert!(ElectingStartedAt::::get().is_none()); + assert!(NextElectionPage::::get().is_none()); assert!(ElectableStashes::::get().is_empty()); // events assert_eq!(staking_events_since_last_call(), vec![ @@ -501,62 +500,6 @@ mod paged_on_initialize { ); }) } - - #[test] - fn try_state_failure_works() { - ExtBuilder::default().build_and_execute(|| { - let pages: BlockNumber = - <::ElectionProvider as ElectionProvider>::Pages::get().into(); - let next_election = - ::next_election_prediction(System::block_number()); - - let mut invalid_stashes = BoundedBTreeSet::new(); - - run_to_block(next_election - pages - 1); - - // election hasn't started yet, no electable stashes expected in storage. - assert_ok!(invalid_stashes.try_insert(42)); - ElectableStashes::::set(invalid_stashes); - assert_err!( - Staking::ensure_snapshot_metadata_state(System::block_number()), - "unexpected electable stashes in storage while election prep hasn't started." - ); - Staking::clear_election_metadata(); - - // election hasn't started yet, no electable stashes expected in storage. - ElectingStartedAt::::set(Some(42)); - assert_err!( - Staking::ensure_snapshot_metadata_state(System::block_number()), - "unexpected election metadata while election prep hasn't started." - ); - Staking::clear_election_metadata(); - - run_to_block(next_election - pages); - - // election prep started, metadata, electable stashes and exposures are expected to - // exist. - let _ = ErasStakersOverview::::clear(u32::MAX, None); - let _ = ErasStakersPaged::::clear(u32::MAX, None); - assert_err!( - Staking::ensure_snapshot_metadata_state(System::block_number()), - "no exposures collected for an electable stash." - ); - - ElectingStartedAt::::kill(); - assert_err!( - Staking::ensure_snapshot_metadata_state(System::block_number()), - "election prep should have started already, but no election metadata in storage." - ); - ElectingStartedAt::::set(Some(424242)); - assert_err!( - Staking::ensure_snapshot_metadata_state(System::block_number()), - "unexpected electing_started_at block number in storage." - ); - - // skip final try state checks. - SkipTryStateCheck::set(true); - }) - } } mod paged_snapshot { From 4d690b764c72b7873228f17decc5773744c81df3 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 17 Jan 2025 09:18:56 +0000 Subject: [PATCH 85/95] more testing --- substrate/bin/node/cli/src/chain_spec.rs | 8 ++- substrate/bin/node/runtime/src/constants.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 30 ++++++----- .../src/unsigned.rs | 53 ++++++++----------- substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/pallet/impls.rs | 15 ++++-- .../primitives/npos-elections/src/lib.rs | 3 +- 7 files changed, 58 insertions(+), 55 deletions(-) diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index e90312543433b..5641b70aa9be2 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -421,8 +421,12 @@ pub fn testnet_genesis( fn development_config_genesis_json() -> serde_json::Value { if cfg!(feature = "staking-playground") { - let random_authorities_count = 100; - let random_nominators_count = 3000; + let random_authorities_count = std::option_env!("AUTHORITIES") + .map(|s| s.parse::().unwrap()) + .unwrap_or(100); + let random_nominators_count = std::option_env!("NOMINATORS") + .map(|s| s.parse::().unwrap()) + .unwrap_or(3000); let mut random_authorities = (0..random_authorities_count) .map(|i| authority_keys_from_seed(&format!("Random{}", i))) .collect::>(); diff --git a/substrate/bin/node/runtime/src/constants.rs b/substrate/bin/node/runtime/src/constants.rs index 42629d53500ce..3a892e2f2b358 100644 --- a/substrate/bin/node/runtime/src/constants.rs +++ b/substrate/bin/node/runtime/src/constants.rs @@ -66,7 +66,7 @@ pub mod time { #[cfg(not(feature = "staking-playground"))] pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; #[cfg(feature = "staking-playground")] - pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 2 * MINUTES; pub const EPOCH_DURATION_IN_SLOTS: u64 = { const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 46570a72a47aa..8e30eac5e05a5 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -849,7 +849,7 @@ impl pallet_staking::Config for Runtime { type SessionInterface = Self; type EraPayout = pallet_staking::ConvertCurve; type NextNewSession = Session; - type MaxExposurePageSize = ConstU32<256>; + type MaxExposurePageSize = MaxExposurePageSize; type MaxValidatorSet = MaxActiveValidators; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::OnChainExecution; @@ -878,9 +878,9 @@ impl pallet_fast_unstake::Config for Runtime { } parameter_types! { - // phase durations. 1/4 of the last session for each. - pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; - pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; + // phase durations. 1/2 of the last session for each. + pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 2; + pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 2; // signed config pub const SignedRewardBase: Balance = 1 * DOLLARS; @@ -907,25 +907,27 @@ frame_election_provider_support::generate_solution_type!( VoterIndex = u32, TargetIndex = u16, Accuracy = sp_runtime::PerU16, - MaxVoters = MaxElectingVotersSolution, + MaxVoters = ConstU32<22500>, >(16) ); parameter_types! { - // Note: the EPM in this runtime runs the election on-chain. The election bounds must be - // carefully set so that an election round fits in one block. + /// Note: the EPM in this runtime runs the election on-chain. The election bounds must be + /// carefully set so that an election round fits in one block. pub ElectionBoundsMultiPhase: ElectionBounds = ElectionBoundsBuilder::default() - .voters_count(10_000.into()).targets_count(1_500.into()).build(); + .voters_count(22500.into()).targets_count(1000.into()).build(); pub ElectionBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default() - .voters_count(5_000.into()).targets_count(1_250.into()).build(); + .voters_count(1000.into()).targets_count(100.into()).build(); pub MaxNominations: u32 = ::LIMIT as u32; - pub MaxElectingVotersSolution: u32 = 40_000; - // The maximum winners that can be elected by the Election pallet which is equivalent to the - // maximum active validators the staking pallet can have. + /// The maximum winners that can be elected by the Election pallet which is equivalent to the + /// maximum active validators the staking pallet can have. pub MaxActiveValidators: u32 = 1000; - // Unbounded number of backers per winner in the election solution. - pub MaxBackersPerWinner: u32 = u32::MAX; + /// 512 backers per winner in the election solution. + pub MaxBackersPerWinner: u32 = 512; + /// 64 backers per exposure page. + pub MaxExposurePageSize: u32 = 64; + } /// The numbers configured here could always be more than the the maximum limits of staking pallet diff --git a/substrate/frame/election-provider-multi-phase/src/unsigned.rs b/substrate/frame/election-provider-multi-phase/src/unsigned.rs index 1a1245dbfd435..5aabc3454d4df 100644 --- a/substrate/frame/election-provider-multi-phase/src/unsigned.rs +++ b/substrate/frame/election-provider-multi-phase/src/unsigned.rs @@ -98,6 +98,8 @@ pub enum MinerError { NoMoreVoters, /// An error from the solver. Solver, + /// Desired targets are mire than the maximum allowed winners. + TooManyDesiredTargets, } impl From for MinerError { @@ -202,6 +204,7 @@ impl>> Pallet { let RoundSnapshot { voters, targets } = Snapshot::::get().ok_or(MinerError::SnapshotUnAvailable)?; let desired_targets = DesiredTargets::::get().ok_or(MinerError::SnapshotUnAvailable)?; + ensure!(desired_targets <= T::MaxWinners::get(), MinerError::TooManyDesiredTargets); let (solution, score, size, is_trimmed) = Miner::::mine_solution_with_snapshot::( voters, @@ -270,16 +273,17 @@ impl>> Pallet { /// Mine a new solution as a call. Performs all checks. pub fn mine_checked_call() -> Result, MinerError> { // get the solution, with a load of checks to ensure if submitted, IT IS ABSOLUTELY VALID. - let (raw_solution, witness, _) = Self::mine_and_check()?; + let (raw_solution, witness, _trimming) = Self::mine_and_check()?; let score = raw_solution.score; let call: Call = Call::submit_unsigned { raw_solution: Box::new(raw_solution), witness }; log!( debug, - "mined a solution with score {:?} and size {}", + "mined a solution with score {:?} and size {} and trimming {:?}", score, - call.using_encoded(|b| b.len()) + call.using_encoded(|b| b.len()), + _trimming ); Ok(call) @@ -556,11 +560,7 @@ impl Miner { .voters .split_off(max_backers_per_winner) .into_iter() - .map(|(who, stake)| { - // update total support of the target where the edge will be removed. - support.total -= stake; - who - }) + .map(|(who, _stake)| who) .collect(); // remove lowest stake edges calculated above from assignments. @@ -685,7 +685,7 @@ impl Miner { let remove = assignments.len().saturating_sub(maximum_allowed_voters); log_no_system!( - debug, + trace, "from {} assignments, truncating to {} for length, removing {}", assignments.len(), maximum_allowed_voters, @@ -1939,29 +1939,20 @@ mod tests { let targets = vec![10, 20, 30, 40]; let voters = vec![ - (1, 10, bounded_vec![10, 20, 30]), - (2, 10, bounded_vec![10, 20, 30]), - (3, 10, bounded_vec![10, 20, 30]), - (4, 10, bounded_vec![10, 20, 30]), - (5, 10, bounded_vec![10, 20, 40]), + (1, 11, bounded_vec![10, 20, 30]), + (2, 12, bounded_vec![10, 20, 30]), + (3, 13, bounded_vec![10, 20, 30]), + (4, 14, bounded_vec![10, 20, 30]), + (5, 15, bounded_vec![10, 20, 40]), ]; let snapshot = RoundSnapshot { voters: voters.clone(), targets: targets.clone() }; let (round, desired_targets) = (1, 3); - let expected_score_unbounded = - ElectionScore { minimal_stake: 12, sum_stake: 50, sum_stake_squared: 874 }; - let expected_score_bounded = - ElectionScore { minimal_stake: 10, sum_stake: 30, sum_stake_squared: 300 }; - - // solution without max_backers_per_winner set will be higher than the score when bounds - // are set, confirming the trimming when using the same snapshot state. - assert!(expected_score_unbounded > expected_score_bounded); - // election with unbounded max backers per winnner. ExtBuilder::default().max_backers_per_winner(u32::MAX).build_and_execute(|| { assert_eq!(MaxBackersPerWinner::get(), u32::MAX); - let (solution, _, _, trimming_status) = + let (solution, expected_score_unbounded, _, trimming_status) = Miner::::mine_solution_with_snapshot::<::Solver>( voters.clone(), targets.clone(), @@ -1984,10 +1975,10 @@ mod tests { vec![ ( 10, - BoundedSupport { total: 21, voters: bounded_vec![(1, 10), (4, 8), (5, 3)] } + BoundedSupport { total: 25, voters: bounded_vec![(1, 11), (5, 5), (4, 9)] } ), - (20, BoundedSupport { total: 17, voters: bounded_vec![(2, 10), (5, 7)] }), - (30, BoundedSupport { total: 12, voters: bounded_vec![(3, 10), (4, 2)] }), + (20, BoundedSupport { total: 22, voters: bounded_vec![(2, 12), (5, 10)] }), + (30, BoundedSupport { total: 18, voters: bounded_vec![(3, 13), (4, 5)] }) ] ); @@ -1999,7 +1990,7 @@ mod tests { ExtBuilder::default().max_backers_per_winner(1).build_and_execute(|| { assert_eq!(MaxBackersPerWinner::get(), 1); - let (solution, _, _, trimming_status) = + let (solution, expected_score_bounded, _, trimming_status) = Miner::::mine_solution_with_snapshot::<::Solver>( voters, targets, @@ -2024,9 +2015,9 @@ mod tests { assert_eq!( ready_solution.supports.into_iter().collect::>(), vec![ - (10, BoundedSupport { total: 10, voters: bounded_vec![(1, 10)] }), - (20, BoundedSupport { total: 10, voters: bounded_vec![(2, 10)] }), - (30, BoundedSupport { total: 10, voters: bounded_vec![(3, 10)] }), + (10, BoundedSupport { total: 11, voters: bounded_vec![(1, 11)] }), + (20, BoundedSupport { total: 12, voters: bounded_vec![(2, 12)] }), + (30, BoundedSupport { total: 13, voters: bounded_vec![(3, 13)] }) ] ); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 5b2829c3556af..ec961e15a3ec5 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -1313,7 +1313,7 @@ impl EraInfo { let last_page_empty_slots = T::MaxExposurePageSize::get().saturating_sub(last_page.others.len() as u32); - // splits the exposure so that `exposures_append` will fit witin the last exposure + // splits the exposure so that `exposures_append` will fit within the last exposure // page, up to the max exposure page size. The remaining individual exposures in // `exposure` will be added to new pages. let exposures_append = exposure.split_others(last_page_empty_slots); diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index 96fb59abbf7d4..fb7a2f6a0b7e1 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -675,7 +675,7 @@ impl Pallet { .unwrap_or_default(); // set stakers info for genesis era (0). - Self::store_stakers_info(exposures, Zero::zero()); + let _ = Self::store_stakers_info(exposures, Zero::zero()); validators } else { @@ -689,7 +689,12 @@ impl Pallet { .expect("same bounds, will fit; qed.") }; - log!(info, "electable validators for session {:?}: {:?}", start_session_index, validators); + log!( + info, + "electable validators count for session {:?}: {:?}", + start_session_index, + validators.len() + ); if (validators.len() as u32) < MinimumValidatorCount::::get().max(1) { // Session will panic if we ever return an empty validator set, thus max(1) ^^. @@ -814,6 +819,7 @@ impl Pallet { // populate elected stash, stakers, exposures, and the snapshot of validator prefs. let mut total_stake_page: BalanceOf = Zero::zero(); let mut elected_stashes_page = Vec::with_capacity(exposures.len()); + let mut total_backers = 0u32; exposures.into_iter().for_each(|(stash, exposure)| { // build elected stash. @@ -821,7 +827,7 @@ impl Pallet { // accumulate total stake. total_stake_page = total_stake_page.saturating_add(exposure.total); // set or update staker exposure for this era. - + total_backers += exposure.others.len() as u32; EraInfo::::upsert_exposure(new_planned_era, &stash, exposure); }); @@ -842,8 +848,9 @@ impl Pallet { if new_planned_era > 0 { log!( info, - "updated validator set with {:?} validators for era {:?}", + "stored a page of stakers with {:?} validators and {:?} total backers for era {:?}", elected_stashes.len(), + total_backers, new_planned_era, ); } diff --git a/substrate/primitives/npos-elections/src/lib.rs b/substrate/primitives/npos-elections/src/lib.rs index 96af46e30f63f..8134c3ceeac02 100644 --- a/substrate/primitives/npos-elections/src/lib.rs +++ b/substrate/primitives/npos-elections/src/lib.rs @@ -482,8 +482,7 @@ pub fn to_support_map( supports } -/// Same as [`to_support_map`] except it returns a -/// flat vector. +/// Same as [`to_support_map`] except it returns a flat vector. pub fn to_supports( assignments: &[StakedAssignment], ) -> Supports { From d348cb019f21b1dc786326818b5338d46360efed Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:22:02 +0000 Subject: [PATCH 86/95] Update substrate/primitives/staking/src/lib.rs Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- substrate/primitives/staking/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 5f0b86c4050fe..8b58ea94347c5 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -522,7 +522,10 @@ where ) -> Self { let new_nominator_count = self.nominator_count.saturating_add(others_num); let new_page_count = - new_nominator_count.saturating_add(Max::get()).saturating_div(Max::get()); + new_nominator_count + .defensive_saturating_add(Max::get()) + .defensive_saturating_sub(1) + .saturating_div(Max::get()); Self { total: self.total.saturating_add(others_balance), From 7ce460cbb3f798e88518a9b59bc814d8ebc66138 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 17 Jan 2025 12:27:31 +0000 Subject: [PATCH 87/95] rename and fix --- cumulus/bin/pov-validator/Cargo.toml | 2 +- polkadot/runtime/westend/src/lib.rs | 4 +- substrate/frame/staking/src/benchmarking.rs | 6 +- substrate/frame/staking/src/lib.rs | 2 +- substrate/frame/staking/src/migrations.rs | 12 +-- substrate/frame/staking/src/pallet/impls.rs | 92 ++++++++++++------- substrate/frame/staking/src/pallet/mod.rs | 6 -- substrate/frame/staking/src/tests.rs | 2 +- .../frame/staking/src/tests_paged_election.rs | 2 +- substrate/primitives/staking/src/lib.rs | 37 +++++++- 10 files changed, 111 insertions(+), 54 deletions(-) diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml index d7af29a6bcb25..a919e3f68eace 100644 --- a/cumulus/bin/pov-validator/Cargo.toml +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -19,8 +19,8 @@ sc-executor.workspace = true sp-core.workspace = true sp-io.workspace = true sp-maybe-compressed-blob.workspace = true -tracing-subscriber.workspace = true tracing.workspace = true +tracing-subscriber.workspace = true [lints] workspace = true diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index e8df5f4083cc9..3c36453115c79 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1153,8 +1153,7 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | - RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) @@ -1855,6 +1854,7 @@ pub mod migrations { parachains_shared::migration::MigrateToV1, parachains_scheduler::migration::MigrateV2ToV3, pallet_staking::migrations::v16::MigrateV15ToV16, + pallet_staking::migrations::v17::MigrateV16ToV17, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); diff --git a/substrate/frame/staking/src/benchmarking.rs b/substrate/frame/staking/src/benchmarking.rs index 6ffdf09208a9b..984c4aadcd7d2 100644 --- a/substrate/frame/staking/src/benchmarking.rs +++ b/substrate/frame/staking/src/benchmarking.rs @@ -117,7 +117,7 @@ pub fn create_validator_with_nominators( ValidatorCount::::put(1); // Start a new Era - let new_validators = Staking::::try_trigger_new_era(SessionIndex::one(), true).unwrap(); + let new_validators = Staking::::try_plan_new_era(SessionIndex::one(), true).unwrap(); assert_eq!(new_validators.len(), 1); assert_eq!(new_validators[0], v_stash, "Our validator was not selected!"); @@ -904,7 +904,7 @@ mod benchmarks { #[block] { validators = - Staking::::try_trigger_new_era(session_index, true).ok_or("`new_era` failed")?; + Staking::::try_plan_new_era(session_index, true).ok_or("`new_era` failed")?; } assert!(validators.len() == v as usize); @@ -922,7 +922,7 @@ mod benchmarks { None, )?; // Start a new Era - let new_validators = Staking::::try_trigger_new_era(SessionIndex::one(), true).unwrap(); + let new_validators = Staking::::try_plan_new_era(SessionIndex::one(), true).unwrap(); assert!(new_validators.len() == v as usize); let current_era = CurrentEra::::get().unwrap(); diff --git a/substrate/frame/staking/src/lib.rs b/substrate/frame/staking/src/lib.rs index 44052a35f3cd5..07d38a139504d 100644 --- a/substrate/frame/staking/src/lib.rs +++ b/substrate/frame/staking/src/lib.rs @@ -161,7 +161,7 @@ //! //! Note: [`frame_election_provider_support::ElectionDataProvider`] trait supports mulit-paged //! target snaphsot. However, this pallet only supports and implements a single-page snapshot. -//! Calling [`ElectionDataProvider::electable_targets`] with a different index than 0 is redundant +//! Calling `ElectionDataProvider::electable_targets` with a different index than 0 is redundant //! and the single page idx 0 of targets be returned. //! //! ### Prepare an election ahead of time with `on_initialize` diff --git a/substrate/frame/staking/src/migrations.rs b/substrate/frame/staking/src/migrations.rs index 36a94bfdfc912..c616ce5ee330a 100644 --- a/substrate/frame/staking/src/migrations.rs +++ b/substrate/frame/staking/src/migrations.rs @@ -62,19 +62,19 @@ type StorageVersion = StorageValue, ObsoleteReleases, Value /// Migrates to multi-page election support. /// -/// See: https://github.com/paritytech/polkadot-sdk/pull/6034 +/// See: /// /// Important note: this migration should be released with the election provider configured by this /// pallet supporting up to 1 page. Thus, /// * `VoterSnapshotStatus` does not need migration, as it will always be `Status::Waiting` when /// the number of election pages is 1. /// * `ElectableStashes` must be populated iif there are collected exposures for a future era (i.e. -/// exposures have been collected but `fn try_trigger_new_era` was not called). +/// exposures have been collected but `fn try_plan_new_era` was not called). pub mod v17 { use super::*; pub struct VersionedMigrateV16ToV17(core::marker::PhantomData); - impl OnRuntimeUpgrade for VersionedMigrateV16ToV17 { + impl UncheckedOnRuntimeUpgrade for VersionedMigrateV16ToV17 { fn on_runtime_upgrade() -> Weight { // Populates the `ElectableStashes` with the exposures of the next planning era if it // is initialized (i.e. if the there are exposures collected for the next planning @@ -84,15 +84,15 @@ pub mod v17 { debug_assert!(Pallet::::election_pages() == 1); let next_era = CurrentEra::::get().defensive_unwrap_or_default().saturating_add(1); - let prepared_exposures = ErasStakersOverview::::iter() - .filter(|(era_idx, _, _)| *era_idx == next_era) - .map(|(_, v, _)| v) + let prepared_exposures = ErasStakersOverview::::iter_prefix(next_era) + .map(|(v, _)| v) .collect::>(); let migrated_stashes = prepared_exposures.len() as u32; let result = Pallet::::add_electables(prepared_exposures.into_iter()); debug_assert!(result.is_ok()); + log!(info, "v17 applied successfully, migrated {:?}.", migrated_stashes); T::DbWeight::get().reads_writes( // 1x read per history depth and current era read. (T::HistoryDepth::get() + 1u32).into(), diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b2f720d1c3caf..b116286000be1 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -80,7 +80,7 @@ impl Pallet { /// Clears up all election preparation metadata in storage. pub(crate) fn clear_election_metadata() { - // TODO: voter snapshot status should also be killed? + VoterSnapshotStatus::::kill(); NextElectionPage::::kill(); ElectableStashes::::kill(); } @@ -459,8 +459,8 @@ impl Pallet { /// Plan a new session potentially trigger a new era. /// /// Subsequent function calls in the happy path are as follows: - /// 1. `try_trigger_new_era` - /// 2. `trigger_new_era` + /// 1. `try_plan_new_era` + /// 2. `plan_new_era` fn new_session( session_index: SessionIndex, is_genesis: bool, @@ -478,9 +478,9 @@ impl Pallet { match ForceEra::::get() { // Will be set to `NotForcing` again if a new era has been triggered. Forcing::ForceNew => (), - // Short circuit to `try_trigger_new_era`. + // Short circuit to `try_plan_new_era`. Forcing::ForceAlways => (), - // Only go to `try_trigger_new_era` if deadline reached. + // Only go to `try_plan_new_era` if deadline reached. Forcing::NotForcing if era_length >= T::SessionsPerEra::get() => (), _ => { // Either `Forcing::ForceNone`, @@ -490,7 +490,7 @@ impl Pallet { } // New era. - let maybe_new_era_validators = Self::try_trigger_new_era(session_index, is_genesis); + let maybe_new_era_validators = Self::try_plan_new_era(session_index, is_genesis); if maybe_new_era_validators.is_some() && matches!(ForceEra::::get(), Forcing::ForceNew) { @@ -501,7 +501,7 @@ impl Pallet { } else { // Set initial era. log!(debug, "Starting the first era."); - Self::try_trigger_new_era(session_index, is_genesis) + Self::try_plan_new_era(session_index, is_genesis) } } @@ -550,6 +550,7 @@ impl Pallet { fn start_era(start_session: SessionIndex) { let active_era = ActiveEra::::mutate(|active_era| { let new_index = active_era.as_ref().map(|info| info.index + 1).unwrap_or(0); + log!(debug, "starting active era {:?}", new_index); *active_era = Some(ActiveEraInfo { index: new_index, // Set new active era start in next `on_finalize`. To guarantee usage of `Time` @@ -621,28 +622,6 @@ impl Pallet { } } - /// Plan a new era. - /// - /// * Bump the current era storage (which holds the latest planned era). - /// * Store start session index for the new planned era. - /// * Clean old era information. - /// - /// The new validator set for this era is stored under [`ElectableStashes`]. - pub fn trigger_new_era(start_session_index: SessionIndex) { - // Increment or set current era. - let new_planned_era = CurrentEra::::mutate(|s| { - *s = Some(s.map(|s| s + 1).unwrap_or(0)); - s.unwrap() - }); - ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); - - // Clean old era information. - if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { - log!(trace, "Removing era information for {:?}", old_era); - Self::clear_era_information(old_era); - } - } - /// Potentially plan a new era. /// /// The election results are either fetched directly from an election provider if it is the @@ -651,7 +630,7 @@ impl Pallet { /// In case election result has more than [`MinimumValidatorCount`] validator trigger a new era. /// /// In case a new era is planned, the new validator set is returned. - pub(crate) fn try_trigger_new_era( + pub(crate) fn try_plan_new_era( start_session_index: SessionIndex, is_genesis: bool, ) -> Option>> { @@ -722,12 +701,34 @@ impl Pallet { } else { Self::deposit_event(Event::StakersElected); Self::clear_election_metadata(); - Self::trigger_new_era(start_session_index); + Self::plan_new_era(start_session_index); Some(validators) } } + /// Plan a new era. + /// + /// * Bump the current era storage (which holds the latest planned era). + /// * Store start session index for the new planned era. + /// * Clean old era information. + /// + /// The new validator set for this era is stored under `ElectableStashes`. + pub fn plan_new_era(start_session_index: SessionIndex) { + // Increment or set current era. + let new_planned_era = CurrentEra::::mutate(|s| { + *s = Some(s.map(|s| s + 1).unwrap_or(0)); + s.unwrap() + }); + ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); + + // Clean old era information. + if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { + log!(trace, "Removing era information for {:?}", old_era); + Self::clear_era_information(old_era); + } + } + /// Paginated elect. /// /// Fetches the election page with index `page` from the election provider. @@ -1594,6 +1595,15 @@ impl ElectionDataProvider for Pallet { /// Once the first new_session is planned, all session must start and then end in order, though /// some session can lag in between the newest session planned and the latest session started. impl pallet_session::SessionManager for Pallet { + // └── Self::new_session(new_index, false) + // └── Self::try_plan_new_era(session_index, is_genesis) + // └── T::GenesisElectionProvider::elect() OR ElectableStashes::::take() + // └── Self::collect_exposures() + // └── Self::store_stakers_info() + // └── Self::plan_new_era() + // └── CurrentEra increment + // └── ErasStartSessionIndex update + // └── Self::clear_era_information() fn new_session(new_index: SessionIndex) -> Option> { log!(trace, "planning new session {}", new_index); CurrentPlannedSession::::put(new_index); @@ -1604,6 +1614,19 @@ impl pallet_session::SessionManager for Pallet { CurrentPlannedSession::::put(new_index); Self::new_session(new_index, true).map(|v| v.into_inner()) } + // start_session(start_session: SessionIndex) + // └── Check if this is the start of next active era + // └── Self::start_era(start_session) + // └── Update active era index + // └── Set active era start timestamp + // └── Update BondedEras + // └── Self::apply_unapplied_slashes() + // └── Get slashes for era from UnappliedSlashes + // └── Apply each slash + // └── Clear slashes metadata + // └── Process disabled validators + // └── Get all disabled validators + // └── Call T::SessionInterface::disable_validator() for each fn start_session(start_index: SessionIndex) { log!(trace, "starting session {}", start_index); Self::start_session(start_index) @@ -2346,6 +2369,13 @@ impl Pallet { ::TargetList::count() == Validators::::count(), "wrong external count" ); + let max_validators_bound = MaxWinnersOf::::get(); + let max_winners_per_page_bound = MaxWinnersPerPageOf::::get(); + ensure!( + max_validators_bound >= max_winners_per_page_bound, + "max validators should be higher than per page bounds" + ); + ensure!(ValidatorCount::::get() <= max_validators_bound, Error::::TooManyValidators); Ok(()) } diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 917ca1ce36fa6..70c3cd54215c7 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -1059,12 +1059,6 @@ pub mod pallet { /// the time of the election. fn on_initialize(now: BlockNumberFor) -> Weight { let pages = Self::election_pages(); - crate::log!( - trace, - "now: {:?}, NextElectionPage: {:?}", - now, - NextElectionPage::::get() - ); // election ongoing, fetch the next page. let inner_weight = if let Some(next_page) = NextElectionPage::::get() { diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index 6ff42022d7b18..c57df4dec9a36 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -3670,7 +3670,7 @@ fn slashing_independent_of_disabling_validator() { } #[test] -fn offence_threshold_doesnt_trigger_new_era() { +fn offence_threshold_doesnt_plan_new_era() { ExtBuilder::default() .validator_count(4) .set_status(41, StakerStatus::Validator) diff --git a/substrate/frame/staking/src/tests_paged_election.rs b/substrate/frame/staking/src/tests_paged_election.rs index 0477cb20e2d7d..72e17bf53c090 100644 --- a/substrate/frame/staking/src/tests_paged_election.rs +++ b/substrate/frame/staking/src/tests_paged_election.rs @@ -643,7 +643,7 @@ mod paged_exposures { let genesis_result = <::GenesisElectionProvider>::elect(0u32).unwrap(); let expected_exposures = Staking::collect_exposures(genesis_result.clone()); - Staking::try_trigger_new_era(0u32, true); + Staking::try_plan_new_era(0u32, true); // expected exposures are stored for the expected genesis validators. for exposure in expected_exposures { diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 5f0b86c4050fe..1e6b116e79db7 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -511,7 +511,7 @@ where + Copy + sp_runtime::traits::Debug, { - /// Consomes self and returns the result of the metadata updated with `other_balances` and + /// Consumes self and returns the result of the metadata updated with `other_balances` and /// of adding `other_num` nominators to the metadata. /// /// `Max` is a getter of the maximum number of nominators per page. @@ -520,9 +520,10 @@ where others_balance: Balance, others_num: u32, ) -> Self { + let page_limit = Max::get().max(1); let new_nominator_count = self.nominator_count.saturating_add(others_num); let new_page_count = - new_nominator_count.saturating_add(Max::get()).saturating_div(Max::get()); + new_nominator_count.saturating_add(page_limit).saturating_div(page_limit); Self { total: self.total.saturating_add(others_balance), @@ -696,8 +697,40 @@ sp_core::generate_feature_enabled_macro!(runtime_benchmarks_enabled, feature = " #[cfg(test)] mod tests { + use sp_core::ConstU32; + use super::*; + #[test] + fn update_with_works() { + let metadata = PagedExposureMetadata:: { + total: 1000, + own: 0, // don't care + nominator_count: 10, + page_count: 1, + }; + + assert_eq!( + metadata.clone().update_with::>(1, 1), + PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 2 }, + ); + + assert_eq!( + metadata.clone().update_with::>(1, 1), + PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 3 }, + ); + + assert_eq!( + metadata.clone().update_with::>(1, 1), + PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 3 }, + ); + + assert_eq!( + metadata.clone().update_with::>(1, 1), + PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 12 }, + ); + } + #[test] fn individual_exposures_to_exposure_works() { let exposure_1 = IndividualExposure { who: 1, value: 10u32 }; From 7f438db36fc2f3fed114fc96696d3c4effb60429 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 17 Jan 2025 12:41:06 +0000 Subject: [PATCH 88/95] fix --- substrate/frame/staking/src/mock.rs | 2 +- substrate/frame/staking/src/tests.rs | 3 +++ substrate/primitives/staking/src/lib.rs | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/substrate/frame/staking/src/mock.rs b/substrate/frame/staking/src/mock.rs index 1f6ce09182b5d..1ca018fcbcce4 100644 --- a/substrate/frame/staking/src/mock.rs +++ b/substrate/frame/staking/src/mock.rs @@ -209,7 +209,7 @@ parameter_types! { pub static MaxValidatorSet: u32 = 100; pub static ElectionsBounds: ElectionBounds = ElectionBoundsBuilder::default().build(); pub static AbsoluteMaxNominations: u32 = 16; - pub static MaxWinnersPerPage: u32 = 100; + pub static MaxWinnersPerPage: u32 = MaxValidatorSet::get(); } type VoterBagsListInstance = pallet_bags_list::Instance1; diff --git a/substrate/frame/staking/src/tests.rs b/substrate/frame/staking/src/tests.rs index c57df4dec9a36..7ae0a8607d67a 100644 --- a/substrate/frame/staking/src/tests.rs +++ b/substrate/frame/staking/src/tests.rs @@ -6594,6 +6594,7 @@ fn reducing_max_unlocking_chunks_abrupt() { fn cannot_set_unsupported_validator_count() { ExtBuilder::default().build_and_execute(|| { MaxValidatorSet::set(50); + MaxWinnersPerPage::set(50); // set validator count works assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 30)); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 50)); @@ -6609,6 +6610,7 @@ fn cannot_set_unsupported_validator_count() { fn increase_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { MaxValidatorSet::set(50); + MaxWinnersPerPage::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 40)); // increase works @@ -6627,6 +6629,7 @@ fn increase_validator_count_errors() { fn scale_validator_count_errors() { ExtBuilder::default().build_and_execute(|| { MaxValidatorSet::set(50); + MaxWinnersPerPage::set(50); assert_ok!(Staking::set_validator_count(RuntimeOrigin::root(), 20)); // scale value works diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 8b5265dcc2156..262181987d167 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -523,8 +523,8 @@ where let page_limit = Max::get().max(1); let new_nominator_count = self.nominator_count.saturating_add(others_num); let new_page_count = new_nominator_count - .defensive_saturating_add(page_limit) - .defensive_saturating_sub(1) + .saturating_add(page_limit) + .saturating_sub(1) .saturating_div(page_limit); Self { @@ -729,7 +729,7 @@ mod tests { assert_eq!( metadata.clone().update_with::>(1, 1), - PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 12 }, + PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 11 }, ); } From 90807e22fc74d8a7637c8bf7a438effeaafd0c08 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Fri, 17 Jan 2025 13:35:39 +0000 Subject: [PATCH 89/95] add tests --- substrate/bin/node/cli/src/chain_spec.rs | 2 +- substrate/bin/node/runtime/src/constants.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 10 ++- substrate/frame/staking/src/pallet/impls.rs | 68 +++++++++++++++------ 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/substrate/bin/node/cli/src/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index 5641b70aa9be2..400c6e1fdd6fc 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -382,7 +382,7 @@ pub fn testnet_genesis( .collect::>(), }, "staking": { - "validatorCount": (initial_authorities.len()/2usize) as u32, + "validatorCount": std::option_env!("VAL_COUNT").map(|v| v.parse::().unwrap()).unwrap_or((initial_authorities.len()/2usize) as u32), "minimumValidatorCount": 4, "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), "slashRewardFraction": Perbill::from_percent(10), diff --git a/substrate/bin/node/runtime/src/constants.rs b/substrate/bin/node/runtime/src/constants.rs index 3a892e2f2b358..42629d53500ce 100644 --- a/substrate/bin/node/runtime/src/constants.rs +++ b/substrate/bin/node/runtime/src/constants.rs @@ -66,7 +66,7 @@ pub mod time { #[cfg(not(feature = "staking-playground"))] pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 10 * MINUTES; #[cfg(feature = "staking-playground")] - pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 2 * MINUTES; + pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * MINUTES; pub const EPOCH_DURATION_IN_SLOTS: u64 = { const SLOT_FILL_RATE: f64 = MILLISECS_PER_BLOCK as f64 / SLOT_DURATION as f64; diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 32d7342ab1c80..b0748935dc1e4 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -919,18 +919,16 @@ parameter_types! { /// Note: the EPM in this runtime runs the election on-chain. The election bounds must be /// carefully set so that an election round fits in one block. pub ElectionBoundsMultiPhase: ElectionBounds = ElectionBoundsBuilder::default() - .voters_count(22500.into()).targets_count(1000.into()).build(); + .voters_count(5000.into()).targets_count(10.into()).build(); pub ElectionBoundsOnChain: ElectionBounds = ElectionBoundsBuilder::default() - .voters_count(1000.into()).targets_count(100.into()).build(); + .voters_count(1000.into()).targets_count(10.into()).build(); pub MaxNominations: u32 = ::LIMIT as u32; /// The maximum winners that can be elected by the Election pallet which is equivalent to the /// maximum active validators the staking pallet can have. pub MaxActiveValidators: u32 = 1000; - /// 512 backers per winner in the election solution. - pub MaxBackersPerWinner: u32 = 512; - /// 64 backers per exposure page. - pub MaxExposurePageSize: u32 = 64; + pub MaxBackersPerWinner: u32 = 32; + pub MaxExposurePageSize: u32 = 4; } diff --git a/substrate/frame/staking/src/pallet/impls.rs b/substrate/frame/staking/src/pallet/impls.rs index b116286000be1..8db6feda4710d 100644 --- a/substrate/frame/staking/src/pallet/impls.rs +++ b/substrate/frame/staking/src/pallet/impls.rs @@ -667,8 +667,8 @@ impl Pallet { log!( info, - "electable validators count for session {:?}: {:?}", - start_session_index, + "electable validators count for era {:?}: {:?}", + CurrentEra::::get().unwrap_or_default() + 1, validators.len() ); @@ -820,6 +820,12 @@ impl Pallet { let mut total_backers = 0u32; exposures.into_iter().for_each(|(stash, exposure)| { + log!( + trace, + "stored exposure for stash {:?} and {:?} backers", + stash, + exposure.others.len() + ); // build elected stash. elected_stashes_page.push(stash.clone()); // accumulate total stake. @@ -843,15 +849,13 @@ impl Pallet { >::insert(&new_planned_era, stash, pref); } - if new_planned_era > 0 { - log!( - info, - "stored a page of stakers with {:?} validators and {:?} total backers for era {:?}", - elected_stashes.len(), - total_backers, - new_planned_era, - ); - } + log!( + info, + "stored a page of stakers with {:?} validators and {:?} total backers for era {:?}", + elected_stashes.len(), + total_backers, + new_planned_era, + ); elected_stashes } @@ -2266,15 +2270,43 @@ impl Pallet { Self::ensure_disabled_validators_sorted() } - /// Invariants: - /// /// Test invariants of: /// - /// - `NextElectionPage` - /// - `ElectableStashes` - /// - `VoterSnapshotStatus` - pub fn ensure_snapshot_metadata_state(_now: BlockNumberFor) -> Result<(), TryRuntimeError> { - // TODO: + /// - `NextElectionPage`: should only be set if pages > 1 and if we are within `pages-election + /// -> election` + /// - `ElectableStashes`: should only be set in `pages-election -> election block` + /// - `VoterSnapshotStatus`: cannot be argued about as we don't know when we get a call to data + /// provider, but we know it should never be set if we have 1 page. + /// + /// -- SHOULD ONLY BE CALLED AT THE END OF A GIVEN BLOCK. + pub fn ensure_snapshot_metadata_state(now: BlockNumberFor) -> Result<(), TryRuntimeError> { + let next_election = Self::next_election_prediction(now); + let pages = Self::election_pages().saturated_into::>(); + let election_prep_start = next_election - pages; + + if now >= election_prep_start && now < next_election { + ensure!( + !ElectableStashes::::get().is_empty(), + "ElectableStashes should not be empty mid election" + ); + } + + if pages > One::one() && now >= election_prep_start { + ensure!( + NextElectionPage::::get().is_some() || next_election == now + One::one(), + "NextElectionPage should be set mid election, except for last block" + ); + } else if pages == One::one() { + ensure!( + NextElectionPage::::get().is_none(), + "NextElectionPage should not be set mid election" + ); + ensure!( + VoterSnapshotStatus::::get() == SnapshotStatus::Waiting, + "VoterSnapshotStatus should not be set mid election" + ); + } + Ok(()) } From ebaeaf57dd6eb91fc08b02fda2e188168e7107c8 Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Mon, 20 Jan 2025 18:36:52 +0000 Subject: [PATCH 90/95] Update from kianenigma running command 'fmt' --- cumulus/bin/pov-validator/Cargo.toml | 2 +- polkadot/runtime/westend/src/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml index a919e3f68eace..d7af29a6bcb25 100644 --- a/cumulus/bin/pov-validator/Cargo.toml +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -19,8 +19,8 @@ sc-executor.workspace = true sp-core.workspace = true sp-io.workspace = true sp-maybe-compressed-blob.workspace = true -tracing.workspace = true tracing-subscriber.workspace = true +tracing.workspace = true [lints] workspace = true diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 2d597797f1b26..f7c80367c3c09 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -1154,7 +1154,8 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | + RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) From 336642dd00a512264958e1e3ece58ddbd2b25e8e Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 23 Jan 2025 09:51:08 +0000 Subject: [PATCH 91/95] bump storage version --- substrate/frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 70c3cd54215c7..2fea66f0f6e5e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -71,7 +71,7 @@ pub mod pallet { use frame_election_provider_support::{ElectionDataProvider, PageIndex}; /// The in-code storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(16); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(17); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] From c40f986e22607f8790609c385bfb866c85d2338d Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:11:12 +0000 Subject: [PATCH 92/95] Update substrate/frame/staking/src/pallet/mod.rs Co-authored-by: Oliver Tale-Yazdi --- substrate/frame/staking/src/pallet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2fea66f0f6e5e..63d1ded95be0e 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -778,7 +778,7 @@ pub mod pallet { /// A bounded list of the "electable" stashes that resulted from a successful election. #[pallet::storage] - pub(crate) type ElectableStashes = + pub type ElectableStashes = StorageValue<_, BoundedBTreeSet, ValueQuery>; #[pallet::genesis_config] From aa4d903e6c531b031cf265ed2e8a04d87df974fa Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 23 Jan 2025 14:11:55 +0000 Subject: [PATCH 93/95] pub all storage types --- substrate/frame/staking/src/pallet/mod.rs | 17 ++++++++--------- substrate/primitives/staking/src/lib.rs | 8 ++++---- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/substrate/frame/staking/src/pallet/mod.rs b/substrate/frame/staking/src/pallet/mod.rs index 2fea66f0f6e5e..7380c691b964f 100644 --- a/substrate/frame/staking/src/pallet/mod.rs +++ b/substrate/frame/staking/src/pallet/mod.rs @@ -695,13 +695,12 @@ pub mod pallet { /// `[active_era - bounding_duration; active_era]` #[pallet::storage] #[pallet::unbounded] - pub(crate) type BondedEras = - StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; + pub type BondedEras = StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; /// All slashing events on validators, mapped by era to the highest slash proportion /// and slash value of the era. #[pallet::storage] - pub(crate) type ValidatorSlashInEra = StorageDoubleMap< + pub type ValidatorSlashInEra = StorageDoubleMap< _, Twox64Concat, EraIndex, @@ -712,7 +711,7 @@ pub mod pallet { /// All slashing events on nominators, mapped by era to the highest slash value of the era. #[pallet::storage] - pub(crate) type NominatorSlashInEra = + pub type NominatorSlashInEra = StorageDoubleMap<_, Twox64Concat, EraIndex, Twox64Concat, T::AccountId, BalanceOf>; /// Slashing spans for stash accounts. @@ -724,7 +723,7 @@ pub mod pallet { /// Records information about the maximum slash of a stash within a slashing span, /// as well as how much reward has been paid out. #[pallet::storage] - pub(crate) type SpanSlash = StorageMap< + pub type SpanSlash = StorageMap< _, Twox64Concat, (T::AccountId, slashing::SpanIndex), @@ -757,14 +756,14 @@ pub mod pallet { /// nominators. The threshold is compared to the actual number of validators / nominators /// (`CountFor*`) in the system compared to the configured max (`Max*Count`). #[pallet::storage] - pub(crate) type ChillThreshold = StorageValue<_, Percent, OptionQuery>; + pub type ChillThreshold = StorageValue<_, Percent, OptionQuery>; /// Voter snapshot progress status. /// /// If the status is `Ongoing`, it keeps a cursor of the last voter retrieved to proceed when /// creating the next snapshot page. #[pallet::storage] - pub(crate) type VoterSnapshotStatus = + pub type VoterSnapshotStatus = StorageValue<_, SnapshotStatus, ValueQuery>; /// Keeps track of an ongoing multi-page election solution request. @@ -774,11 +773,11 @@ pub mod pallet { /// /// This is only set in multi-block elections. Should always be `None` otherwise. #[pallet::storage] - pub(crate) type NextElectionPage = StorageValue<_, PageIndex, OptionQuery>; + pub type NextElectionPage = StorageValue<_, PageIndex, OptionQuery>; /// A bounded list of the "electable" stashes that resulted from a successful election. #[pallet::storage] - pub(crate) type ElectableStashes = + pub type ElectableStashes = StorageValue<_, BoundedBTreeSet, ValueQuery>; #[pallet::genesis_config] diff --git a/substrate/primitives/staking/src/lib.rs b/substrate/primitives/staking/src/lib.rs index 262181987d167..538cef00e268d 100644 --- a/substrate/primitives/staking/src/lib.rs +++ b/substrate/primitives/staking/src/lib.rs @@ -713,22 +713,22 @@ mod tests { }; assert_eq!( - metadata.clone().update_with::>(1, 1), + metadata.update_with::>(1, 1), PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 2 }, ); assert_eq!( - metadata.clone().update_with::>(1, 1), + metadata.update_with::>(1, 1), PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 3 }, ); assert_eq!( - metadata.clone().update_with::>(1, 1), + metadata.update_with::>(1, 1), PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 3 }, ); assert_eq!( - metadata.clone().update_with::>(1, 1), + metadata.update_with::>(1, 1), PagedExposureMetadata { total: 1001, own: 0, nominator_count: 11, page_count: 11 }, ); } From 039f2f77bf3a31befcb0b0b0aa43be3ea879f5af Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 23 Jan 2025 14:32:46 +0000 Subject: [PATCH 94/95] more clippy fixes --- cumulus/bin/pov-validator/Cargo.toml | 2 +- substrate/frame/staking/src/slashing.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml index d7af29a6bcb25..a919e3f68eace 100644 --- a/cumulus/bin/pov-validator/Cargo.toml +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -19,8 +19,8 @@ sc-executor.workspace = true sp-core.workspace = true sp-io.workspace = true sp-maybe-compressed-blob.workspace = true -tracing-subscriber.workspace = true tracing.workspace = true +tracing-subscriber.workspace = true [lints] workspace = true diff --git a/substrate/frame/staking/src/slashing.rs b/substrate/frame/staking/src/slashing.rs index ae76b0707dcb7..6739f31291d08 100644 --- a/substrate/frame/staking/src/slashing.rs +++ b/substrate/frame/staking/src/slashing.rs @@ -189,7 +189,7 @@ impl SlashingSpans { /// A slashing-span record for a particular stash. #[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)] -pub(crate) struct SpanRecord { +pub struct SpanRecord { slashed: Balance, paid_out: Balance, } From f24232fbe91168e0dbfc37094872888e0faf45dd Mon Sep 17 00:00:00 2001 From: kianenigma Date: Thu, 23 Jan 2025 14:41:40 +0000 Subject: [PATCH 95/95] undo toml file update --- cumulus/bin/pov-validator/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml index a919e3f68eace..d7af29a6bcb25 100644 --- a/cumulus/bin/pov-validator/Cargo.toml +++ b/cumulus/bin/pov-validator/Cargo.toml @@ -19,8 +19,8 @@ sc-executor.workspace = true sp-core.workspace = true sp-io.workspace = true sp-maybe-compressed-blob.workspace = true -tracing.workspace = true tracing-subscriber.workspace = true +tracing.workspace = true [lints] workspace = true