diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py index 3a950bd47c..088f3ee2ed 100755 --- a/.github/scripts/cmd/cmd.py +++ b/.github/scripts/cmd/cmd.py @@ -29,27 +29,27 @@ subparsers = parser.add_subparsers(help='a command to run', dest='command') """ -BENCH +BENCH """ bench_example = '''**Examples**: > runs all benchmarks - + %(prog)s - + > runs benchmarks for pallet_balances and pallet_multisig for all runtimes which have these pallets > --quiet makes it to output nothing to PR but reactions - + %(prog)s --pallet pallet_balances pallet_xcm_benchmarks::generic --quiet - + > runs bench for all pallets for polkadot runtime and continues even if some benchmarks fail - - %(prog)s --runtime polkadot --continue-on-fail - - > does not output anything and cleans up the previous bot's & author command triggering comments in PR - - %(prog)s --runtime polkadot kusama --pallet pallet_balances pallet_multisig --quiet --clean + + %(prog)s --runtime polkadot --continue-on-fail + + > does not output anything and cleans up the previous bot's & author command triggering comments in PR + + %(prog)s --runtime polkadot kusama --pallet pallet_balances pallet_multisig --quiet --clean ''' @@ -62,7 +62,7 @@ parser_bench.add_argument('--pallet', help='Pallet(s) space separated', nargs='*', default=[]) """ -FMT +FMT """ parser_fmt = subparsers.add_parser('fmt', help='Formats code') for arg, config in common_args.items(): diff --git a/Cargo.lock b/Cargo.lock index 9108f2dc66..932d66dc85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -966,6 +966,7 @@ dependencies = [ "sp-session", "sp-staking", "sp-storage", + "sp-tracing 18.0.0", "sp-transaction-pool", "sp-version", "sp-weights", diff --git a/relay/kusama/src/lib.rs b/relay/kusama/src/lib.rs index 325b0c800e..1ed761e4d6 100644 --- a/relay/kusama/src/lib.rs +++ b/relay/kusama/src/lib.rs @@ -121,8 +121,8 @@ pub use sp_runtime::BuildStorage; use sp_runtime::{ generic, impl_opaque_keys, traits::{ - AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Get, - IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Saturating, Verify, + AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Convert, ConvertInto, + Get, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, Saturating, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, OpaqueValue, Perbill, Percent, Permill, @@ -485,6 +485,7 @@ impl pallet_timestamp::Config for Runtime { impl pallet_authorship::Config for Runtime { type FindAuthor = pallet_session::FindAccountFromAuthorIndex; + // Era points are now reported to ah-client, to be sent to AH on next session. type EventHandler = StakingAhClient; } @@ -510,6 +511,8 @@ impl pallet_session::Config for Runtime { type ValidatorIdOf = ConvertInto; type ShouldEndSession = Babe; type NextSessionRotation = Babe; + // Sessions are now managed by the staking-ah client, giving us validator sets, and sending + // session report. type SessionManager = session_historical::NoteHistoricalRoot; type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; @@ -522,6 +525,10 @@ impl pallet_session::Config for Runtime { impl pallet_session::historical::Config for Runtime { type RuntimeEvent = RuntimeEvent; + // Note: while the identification of each validators for historical reasons is still an + // exposure, we actually don't need this data, and `DefaultExposureOf` always uses + // `Default::default`. Retaining this type + keeping a default value is only for historical + // reasons and backwards compatibility. type FullIdentification = pallet_staking::Exposure; type FullIdentificationOf = pallet_staking::DefaultExposureOf; } @@ -806,7 +813,7 @@ impl pallet_staking::EraPayout for EraPayout { let params = relay_common::EraPayoutParams { total_staked, - total_stakable: 0, // TODO: double check + total_stakable: Balances::total_issuance(), ideal_stake: dynamic_params::inflation::IdealStake::get(), max_annual_inflation: dynamic_params::inflation::MaxInflation::get(), min_annual_inflation: dynamic_params::inflation::MinInflation::get(), @@ -1036,6 +1043,8 @@ impl pallet_child_bounties::Config for Runtime { impl pallet_offences::Config for Runtime { type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; + // Offences are now reported to ah-client, to be forwarded to AH, after potentially disabling + // validators. type OnOffenceHandler = StakingAhClient; } @@ -1432,6 +1441,7 @@ impl parachains_session_info::Config for Runtime { impl parachains_inclusion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type DisputesHandler = ParasDisputes; + // parachain consensus points are now reported to ah-client, to be sent to AH on next session. type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; type MessageQueue = MessageQueue; @@ -1721,6 +1731,8 @@ impl pallet_nomination_pools::Config for Runtime { parameter_types! { pub const DelegatedStakingPalletId: PalletId = PalletId(*b"py/dlstk"); pub const SlashRewardFraction: Perbill = Perbill::from_percent(1); + // Kusama always wants 1000 validators, we reject anything smaller than that. + pub storage MinimumValidatorSetSize: u32 = 1000; } impl pallet_delegated_staking::Config for Runtime { @@ -1741,10 +1753,10 @@ impl pallet_staking_async_ah_client::Config for Runtime { type AdminOrigin = EnsureRoot; type SessionInterface = Self; type SendToAssetHub = StakingXcmToAssetHub; - type MinimumValidatorSetSize = ConstU32<400>; + type MinimumValidatorSetSize = MinimumValidatorSetSize; type UnixTime = Timestamp; type PointsPerBlock = ConstU32<20>; - type MaxOffenceBatchSize = ConstU32<50>; + type MaxOffenceBatchSize = ConstU32<32>; type Fallback = Staking; type WeightInfo = pallet_staking_async_ah_client::weights::SubstrateWeight; } @@ -1771,6 +1783,7 @@ impl frame_support::traits::EnsureOrigin for EnsureAssetHub { #[derive(Encode, Decode)] enum AssetHubRuntimePallets { + // index of the rc-client pallet in ksm-ah. #[codec(index = 84)] RcClient(RcClientCalls), } @@ -1811,12 +1824,12 @@ impl pallet_staking_async_ah_client::SendToAssetHub for StakingXcmToAssetHub { fn relay_session_report( session_report: pallet_staking_async_rc_client::SessionReport, ) { - pallet_staking_async_rc_client::XCMSender::< - xcm_config::XcmRouter, - AssetHubLocation, - pallet_staking_async_rc_client::SessionReport, - SessionReportToXcm, - >::split_then_send(session_report, Some(8)); + // TODO: after https://github.com/paritytech/polkadot-sdk/pull/9619, use `XCMSender::send` and handle error + let message = SessionReportToXcm::convert(session_report); + let dest = AssetHubLocation::get(); + let _ = xcm::prelude::send_xcm::(dest, message).inspect_err(|err| { + log::error!(target: "runtime::ah-client", "Failed to send relay session report: {:?}", err); + }); } fn relay_new_offence( @@ -1839,9 +1852,12 @@ impl pallet_staking_async_ah_client::SendToAssetHub for StakingXcmToAssetHub { .into(), }, ]); - if let Err(err) = send_xcm::(AssetHubLocation::get(), message) { - log::error!(target: "runtime::ah-client", "Failed to send relay offence message: {:?}", err); - } + // TODO: after https://github.com/paritytech/polkadot-sdk/pull/9619, use `XCMSender::send` and handle error + let _ = send_xcm::(AssetHubLocation::get(), message).inspect_err( + |err| { + log::error!(target: "runtime::ah-client", "Failed to send relay offence message: {:?}", err); + }, + ); } } @@ -2022,6 +2038,7 @@ construct_runtime! { // Staking extension for delegation DelegatedStaking: pallet_delegated_staking = 47, + // staking client to communicate with AH. StakingAhClient: pallet_staking_async_ah_client = 48, // Parachains pallets. Start indices at 50 to leave room. diff --git a/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml b/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml index 41f4ef2b3c..70a507ef53 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml +++ b/system-parachains/asset-hubs/asset-hub-kusama/Cargo.toml @@ -138,6 +138,7 @@ snowbridge-inbound-queue-primitives = { workspace = true } asset-test-utils = { workspace = true } parachains-runtimes-test-utils = { workspace = true } sp-io = { workspace = true, default-features = true } +sp-tracing = { workspace = true, default-features = true } [build-dependencies] substrate-wasm-builder = { optional = true, workspace = true } diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/genesis_config_presets.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/genesis_config_presets.rs index dfa791b9af..7e8db858a2 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/genesis_config_presets.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/genesis_config_presets.rs @@ -69,7 +69,7 @@ fn asset_hub_kusama_genesis( }, "staking": { "validatorCount": 1000, - "devStakers": Some((2_000, 25_000)), + "devStakers": Some((4_000, 15_000)), }, "foreignAssets": ForeignAssetsConfig { assets: foreign_assets diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs index 28e191701e..f03ae66a03 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/lib.rs @@ -92,10 +92,10 @@ use sp_runtime::{ generic, impl_opaque_keys, traits::{ AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Convert, ConvertInto, - Verify, + Get, Verify, }, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Perbill, Permill, RuntimeDebug, + ApplyExtrinsicResult, Perbill, Permill, Perquintill, RuntimeDebug, }; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -1345,6 +1345,8 @@ impl EnsureOriginWithArg for DynamicParamet use crate::RuntimeParametersKey::*; match key { + Inflation(_) => + EitherOf::, StakingAdmin>::ensure_origin(origin.clone()), Treasury(_) => EitherOf::, GeneralAdmin>::ensure_origin(origin.clone()), } @@ -1370,6 +1372,27 @@ impl pallet_parameters::Config for Runtime { pub mod dynamic_params { use super::*; + /// Parameters used to calculate staking era payouts. + #[dynamic_pallet_params] + #[codec(index = 0)] + pub mod inflation { + /// Minimum inflation rate used to calculate era payouts. + #[codec(index = 0)] + pub static MinInflation: Perquintill = Perquintill::from_rational(25u64, 1000); + + /// Maximum inflation rate used to calculate era payouts. + #[codec(index = 1)] + pub static MaxInflation: Perquintill = Perquintill::from_percent(10); + + /// Ideal stake ratio used to calculate era payouts. + #[codec(index = 2)] + pub static IdealStake: Perquintill = Perquintill::from_percent(75); + + /// Falloff used to calculate era payouts. + #[codec(index = 3)] + pub static Falloff: Perquintill = Perquintill::from_percent(5); + } + /// Parameters used by `pallet-treasury` to handle the burn process. #[dynamic_pallet_params] #[codec(index = 1)] @@ -1385,9 +1408,10 @@ pub mod dynamic_params { #[cfg(feature = "runtime-benchmarks")] impl Default for RuntimeParameters { fn default() -> Self { - RuntimeParameters::Treasury(dynamic_params::treasury::Parameters::BurnPortion( - dynamic_params::treasury::BurnPortion, - Some(Permill::from_percent(0)), + // TODO: @kianenigma/!bkontur - is this ok? + RuntimeParameters::Inflation(dynamic_params::inflation::Parameters::MinInflation( + dynamic_params::inflation::MinInflation, + Some(Perquintill::from_rational(25u64, 1000u64)), )) } } @@ -1570,6 +1594,8 @@ pub type Migrations = ( pallet_session::migrations::v1::InitOffenceSeverity, >, cumulus_pallet_aura_ext::migration::MigrateV0ToV1, + // TODO: TRIPLE CHECK the spec version prior to final merge, and remove the TODO. + staking::InitiateStakingAsync<1_008_000>, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/staking/mod.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/staking/mod.rs index 79a4bcf2fc..fd8f32911d 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/staking/mod.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/staking/mod.rs @@ -28,51 +28,60 @@ use pallet_election_provider_multi_block::{self as multi_block, SolutionAccuracy use pallet_staking_async::UseValidatorsMap; use pallet_staking_async_rc_client as rc_client; use scale_info::TypeInfo; -use sp_arithmetic::FixedU128; -use sp_runtime::{ - transaction_validity::TransactionPriority, FixedPointNumber, SaturatedConversion, -}; +use sp_runtime::{transaction_validity::TransactionPriority, Perquintill}; use sp_staking::SessionIndex; use system_parachains_constants::async_backing::MINUTES; use xcm::v5::prelude::*; +// NOTES: +// * a lot of the parameters are defined as `storage` such that they can be upgraded with a smaller +// overhead by the root origin, as opposed to a code upgrade. We expect to remove them. If all +// goes well in Kusama AHM, we can stop using `storage` in Polkadot. +// * The EPMB pallets only use local block times. They can one day be moved to use the relay-chain +// block, based on how the core-count and fast-blocks evolve, they might benefit from moving to +// relay-chain blocks. As of now, the duration of all phases are more about "POV" than "time", so +// AH deciding to use 2 or 3 cores is not an issue, as its PoV capacity also increases. The signed +// and unsigned phase are more about "time", yet the values used here are generous and should +// leave plenty of time for solution mining and submission. parameter_types! { - /// Number of election pages that we operate upon. 32 * 6s block = 192s = 3.2min snapshots - pub Pages: u32 = 32; + /// Kusama election pages, 1.6m snapshot. + pub Pages: u32 = 16; - /// Verify 8 solutions at most. - pub storage SignedValidationPhase: u32 = Pages::get() * 8; - - // TODO: local or RC minutes? - // TODO: 15 minutes like in RC? - /// 20 mins for signed phase. + /// 20 mins worth of local 6s blocks for signed phase. pub storage SignedPhase: u32 = 20 * MINUTES; - // TODO: local or RC minutes? - /// Offchain miner shall mine at most 4 pages. - pub storage MinerPages: u32 = 4; + /// Allow up to 16 signed solutions to be submitted. + /// + /// Safety note: Larger signed submission increases the weight of the `OnRoundRotation` data cleanup. + pub storage MaxSignedSubmissions: u32 = 16; + + /// Verify all of them. + pub storage SignedValidationPhase: u32 = Pages::get() * MaxSignedSubmissions::get(); - // TODO: local or RC minutes? - // TODO: 15 minutes like in RC? /// 30m for unsigned phase. pub storage UnsignedPhase: u32 = 30 * MINUTES; - // TODO: devide by 8 like in RC? + /// In which we try and mine a 4-page solution. + pub storage MinerPages: u32 = 4; + /// Allow OCW miner to at most run 4 times in the entirety of the 10m Unsigned Phase. pub OffchainRepeat: u32 = UnsignedPhase::get() / 4; - // TODO: 12_500 like in RC? + /// Kusama allows up to 12_500 active nominators (aka. electing voters). pub storage MaxElectingVoters: u32 = 12_500; - /// Always equal to `staking.maxValidatorCount`. - pub storage TargetSnapshotPerBlock: u32 = 2000; - - /// Number of nominators per page of the snapshot, and consequently number of backers in the solution. + /// Which leads to ~782 nominators in each snapshot page (and consequently solution page, at most). pub VoterSnapshotPerBlock: u32 = MaxElectingVoters::get().div_ceil(Pages::get()); - // TODO: 2000 like in RC? - /// Maximum number of validators that we may want to elect. 1000 is the end target. - pub const MaxValidatorSet: u32 = 2000; + /// An upper bound on the number of anticipated kusama "validator candidates". + /// + /// At the time of writing, Kusama has 1000 active validators, and ~2k validator candidates. + /// + /// Safety note: This increases the weight of `on_initialize_into_snapshot_msp` weight. Double check TODO @kianenigma. + pub storage TargetSnapshotPerBlock: u32 = 2500; + + /// Kusama will at most have 1000 validators. + pub const MaxValidatorSet: u32 = 1000; /// In each page, we may observe up to all of the validators. pub MaxWinnersPerPage: u32 = MaxValidatorSet::get(); @@ -88,23 +97,55 @@ parameter_types! { pub MaxBackersPerWinnerFinal: u32 = MaxElectingVoters::get(); /// Size of the exposures. This should be small enough to make the reward payouts feasible. - pub MaxExposurePageSize: u32 = 512; + /// + /// Safety note: during AHM, this value must be the same as it was on the RC + pub const MaxExposurePageSize: u32 = 512; } +// Solution type. +// +// * Voter index: u32 will scale to a near-infinite number of validators/nominators as npos-voters. +// While u16 is also enough, it might very well lead to issues if we wish to increase +// `MaxElectingVoters`. Numbers show that the byte-size of the solution is far from being a +// bottleneck, ergo using u32. +// * Target index: 65k is well enough for a network with 1000 validators +// max. +// * 24: Note that kusama allows for 24 nominations per nominator. frame_election_provider_support::generate_solution_type!( #[compact] pub struct NposCompactSolution24::< VoterIndex = u32, TargetIndex = u16, Accuracy = sp_runtime::PerU16, - MaxVoters = MaxElectingVoters, + MaxVoters = VoterSnapshotPerBlock, >(24) ); parameter_types! { + /// AHM Audit: should be the same as RC. pub const BagThresholds: &'static [u64] = &bags_thresholds::THRESHOLDS; } +/// We don't want to do any auto-rebags in pallet-bags while the migration is not started or +/// ongoing. +pub struct RebagIffMigrationDone; +impl sp_runtime::traits::Get for RebagIffMigrationDone { + fn get() -> u32 { + if cfg!(feature = "runtime-benchmarks") { + 5 + } else { + if matches!( + pallet_ah_migrator::AhMigrationStage::::get(), + pallet_ah_migrator::MigrationStage::MigrationDone + ) { + 5 + } else { + 0 + } + } + } +} + type VoterBagsListInstance = pallet_bags_list::Instance1; impl pallet_bags_list::Config for Runtime { type RuntimeEvent = RuntimeEvent; @@ -112,11 +153,7 @@ impl pallet_bags_list::Config for Runtime { type WeightInfo = weights::pallet_bags_list::WeightInfo; type BagThresholds = BagThresholds; type Score = sp_npos_elections::VoteWeight; - // We have to enable it for benchmarks since the benchmark otherwise panics. - #[cfg(feature = "runtime-benchmarks")] - type MaxAutoRebagPerBlock = ConstU32<5>; - #[cfg(not(any(feature = "runtime-benchmarks")))] - type MaxAutoRebagPerBlock = ConstU32<0>; + type MaxAutoRebagPerBlock = RebagIffMigrationDone; } parameter_types! { @@ -177,10 +214,10 @@ impl multi_block::Config for Runtime { type Fallback = frame_election_provider_support::onchain::OnChainExecution; // Revert back to signed phase if nothing is submitted and queued, so we prolong the election. type AreWeDone = multi_block::RevertToSignedIfNotQueuedOf; + // Clean all data on round rotation. Later on, we can move to lazy deletion. + // TODO @kianenigma lazy deletion already? type OnRoundRotation = multi_block::CleanRound; - // Note: these pallets are currently not "easily" benchmark-able in CIs. They provide a set of - // weights for polkadot/kusama/westend. Using the polkadot-variant is good enough for now. - type WeightInfo = multi_block::weights::kusama::MultiBlockWeightInfo; + type WeightInfo = weights::pallet_election_provider_multi_block::WeightInfo; } impl multi_block::verifier::Config for Runtime { @@ -188,17 +225,56 @@ impl multi_block::verifier::Config for Runtime { type MaxBackersPerWinner = MaxBackersPerWinner; type MaxBackersPerWinnerFinal = MaxBackersPerWinnerFinal; type SolutionDataProvider = MultiBlockElectionSigned; + // Deliberate choice: we want any solution, even an epsilon better, to be considered superior. type SolutionImprovementThreshold = (); - type WeightInfo = multi_block::weights::polkadot::MultiBlockVerifierWeightInfo; + type WeightInfo = weights::pallet_election_provider_multi_block_verifier::WeightInfo; +} + +parameter_types! { + pub const GeometricDepositStart: Balance = UNITS / 10; + pub const GeometricDepositCommon: Balance = 4; } +/// ## Example +/// ``` +/// fn main() { +/// use asset_hub_kusama_runtime::staking::GeometricDeposit; +/// use pallet_election_provider_multi_block::signed::CalculateBaseDeposit; +/// use kusama_runtime_constants::currency::UNITS; +/// +/// // Base deposit +/// assert_eq!(GeometricDeposit::calculate_base_deposit(0), UNITS / 10); // 0.1 KSM +/// assert_eq!(GeometricDeposit::calculate_base_deposit(1), 4 * UNITS / 10); // 0.4 KSM +/// assert_eq!(GeometricDeposit::calculate_base_deposit(2), 16 * UNITS / 10); // 1.6 KSM +/// // and so on +/// +/// // Full 16 page deposit, to be paid on top of the above base +/// sp_io::TestExternalities::default().execute_with(|| { +/// let deposit = asset_hub_kusama_runtime::staking::DepositPerPage::get() * 16; +/// assert_eq!(deposit, 515_519_591_040); // 0.5 KSM +/// }) +/// } +/// ``` +pub struct GeometricDeposit; +impl multi_block::signed::CalculateBaseDeposit for GeometricDeposit { + fn calculate_base_deposit(existing_submitters: usize) -> Balance { + let start: Balance = UNITS / 10; + let common: Balance = 4; + start.saturating_mul(common.saturating_pow(existing_submitters as u32)) + } +} + +// Parameters only regarding signed submission deposits/rewards. parameter_types! { - pub MaxSubmissions: u32 = 16; // TODO: 16 like in RC? - pub DepositBase: Balance = 5 * UNITS; // TODO: new deposit base? - pub DepositPerPage: Balance = 1 * UNITS; // TODO: new deposit per page? - pub BailoutGraceRatio: Perbill = Perbill::from_percent(50); - pub EjectGraceRatio: Perbill = Perbill::from_percent(50); - pub RewardBase: Balance = 10 * UNITS; // TODO: new reward base? + pub DepositPerPage: Balance = system_para_deposit(1, NposCompactSolution24::max_encoded_len() as u32); + /// Bailing is rather disincentivized, as it can allow attackers to submit bad solutions, but get away with it last minute. We only return 25% of the deposit in case someone bails. In Polkadot, this value will be lower or simply zero. + pub BailoutGraceRatio: Perbill = Perbill::from_percent(25); + /// Invulnerable miners will pay this deposit only. + pub InvulnerableFixedDeposit: Balance = UNITS; + /// Being ejected is already paid for by the new submitter replacing you; no need to charge deposit. + pub EjectGraceRatio: Perbill = Perbill::from_percent(0); + /// .2 KSM as the reward for the best signed submission. + pub RewardBase: Balance = UNITS / 5; } impl multi_block::signed::Config for Runtime { @@ -207,33 +283,36 @@ impl multi_block::signed::Config for Runtime { type EjectGraceRatio = EjectGraceRatio; type DepositBase = DepositBase; type DepositPerPage = DepositPerPage; - type InvulnerableDeposit = (); + type InvulnerableDeposit = InvulnerableFixedDeposit; type RewardBase = RewardBase; - type MaxSubmissions = MaxSubmissions; + type MaxSubmissions = MaxSignedSubmissions; type EstimateCallFee = TransactionPayment; - type WeightInfo = multi_block::weights::polkadot::MultiBlockSignedWeightInfo; + type WeightInfo = weights::pallet_election_provider_multi_block_signed::WeightInfo; } parameter_types! { - /// Priority of the offchain miner transactions. + /// Priority of the "offchain" miner transactions. pub MinerTxPriority: TransactionPriority = TransactionPriority::max_value() / 2; + + /// Offchain miner transaction can fill up to 75% of the block size. + pub MinerMaxLength: u32 = Perbill::from_percent(75) * + *RuntimeBlockLength::get() + .max + .get(DispatchClass::Normal); + + /// Whether the offchain worker should use its offchain cache or not. Set as a storage, so it can be tweaked slightly easier than with a code-upgrade. + pub storage OffchainStorage: bool = true; } impl multi_block::unsigned::Config for Runtime { type MinerPages = MinerPages; - type OffchainStorage = ConstBool; - type OffchainSolver = SequentialPhragmen>; + type OffchainStorage = OffchainStorage; + // Note: we don't want the offchain miner to run balancing, as it might be too expensive to run + // in WASM, ergo the last `()`. + type OffchainSolver = SequentialPhragmen, ()>; type MinerTxPriority = MinerTxPriority; type OffchainRepeat = OffchainRepeat; - type WeightInfo = multi_block::weights::polkadot::MultiBlockUnsignedWeightInfo; -} - -parameter_types! { - /// Miner transaction can fill up to 75% of the block size. - pub MinerMaxLength: u32 = Perbill::from_rational(75u32, 100) * - *RuntimeBlockLength::get() - .max - .get(DispatchClass::Normal); + type WeightInfo = weights::pallet_election_provider_multi_block_unsigned::WeightInfo; } impl multi_block::unsigned::miner::MinerConfig for Runtime { @@ -253,47 +332,68 @@ impl multi_block::unsigned::miner::MinerConfig for Runtime { type TargetSnapshotPerBlock = ::TargetSnapshotPerBlock; } -// We cannot re-use the one from the relay since that is for pallet-staking and will be removed soon -// anyway. +// AUDIT: This is the inflation formula of Kusama prior to AHM. Source: +// https://github.com/polkadot-fellows/runtimes/blob/18cbc8b3004f3cff44f6de053bb4220a9f85a7b1/relay/kusama/src/lib.rs#L793-L823 pub struct EraPayout; impl pallet_staking_async::EraPayout for EraPayout { fn era_payout( - _total_staked: Balance, + total_staked: Balance, _total_issuance: Balance, era_duration_millis: u64, ) -> (Balance, Balance) { - // TODO: review, copied from Polkadot. - const MILLISECONDS_PER_YEAR: u64 = (1000 * 3600 * 24 * 36525) / 100; - // A normal-sized era will have 1 / 365.25 here: - let relative_era_len = - FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into()); - - // Fixed total TI that we use as baseline for the issuance. - let fixed_total_issuance: i128 = 5_216_342_402_773_185_773; - let fixed_inflation_rate = FixedU128::from_rational(8, 100); - let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance); - - let era_emission = relative_era_len.saturating_mul_int(yearly_emission); - // 15% to treasury, as per Polkadot ref 1139. - let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission); - let to_stakers = era_emission.saturating_sub(to_treasury); - - (to_stakers.saturated_into(), to_treasury.saturated_into()) + const MILLISECONDS_PER_YEAR: u64 = 1000 * 3600 * 24 * 36525 / 100; + use crate::dynamic_params; + + // TODO @kianenigma one sanity check test for this as we had in the RC + let params = polkadot_runtime_common::impls::EraPayoutParams { + total_staked, + total_stakable: Balances::total_issuance(), + ideal_stake: dynamic_params::inflation::IdealStake::get(), + max_annual_inflation: dynamic_params::inflation::MaxInflation::get(), + min_annual_inflation: dynamic_params::inflation::MinInflation::get(), + falloff: dynamic_params::inflation::Falloff::get(), + period_fraction: Perquintill::from_rational(era_duration_millis, MILLISECONDS_PER_YEAR), + // Note: Kusama RC had the code for reserving a subset of its "ideal-staked-ratio" to be + // allocated to parachain auctions. Yet, this code was buggy in the RC, and was actually + // not doing this. Even if otherwise, in the absence of auctions, this code made no + // sense, and Kusama governance can alter the `ideal_stake` parameter if need be. + // Finally, this information about the parachain count is not even available in AHM + // state. + legacy_auction_proportion: None, + }; + polkadot_runtime_common::impls::relay_era_payout(params) } } -// See: TODO @kianenigma -// https://github.com/paseo-network/runtimes/blob/7904882933075551e23d32d86dbb97b971e84bca/relay/paseo/src/lib.rs#L662 -// https://github.com/paseo-network/runtimes/blob/7904882933075551e23d32d86dbb97b971e84bca/relay/paseo/constants/src/lib.rs#L49 parameter_types! { pub const SessionsPerEra: SessionIndex = 6; - pub const RelaySessionDuration: BlockNumber = 1 * HOURS; // TODO: RC hours/minutes? + /// Note: This is measured in RC block time. Our calculation of when to plan a new era might get + /// confused in case AH block times change. Ideally, this value should be updated alongside AH's + /// block time. If AH blocks progress faster, our eras will become shorter, which is not a + /// critical issue. + pub const RelaySessionDuration: BlockNumber = 1 * HOURS; pub const BondingDuration: sp_staking::EraIndex = 28; pub const SlashDeferDuration: sp_staking::EraIndex = 27; - pub const MaxControllersInDeprecationBatch: u32 = 5169; // TODO: 5169 like in RC? - // alias for 16, which is the max nominations per nominator in the runtime. - pub const MaxNominations: u32 = ::LIMIT as u32; - pub const MaxEraDuration: u64 = RelaySessionDuration::get() as u64 * RELAY_CHAIN_SLOT_DURATION_MILLIS as u64 * SessionsPerEra::get() as u64; + /// Note: smaller value than in RC as parachain PVF is more sensitive to over-weight execution. + pub const MaxControllersInDeprecationBatch: u32 = 512; + /// alias for 24, which is the max nominations per nominator in the runtime. + pub const MaxNominations: u32 = < + NposCompactSolution24 + as + frame_election_provider_support::NposSolution + >::LIMIT as u32; + + /// This is the upper bound on how much we are willing to inflate per era. We also emit a + /// warning event in case an era is longer than this amount. + /// + /// Under normal conditions, this upper bound is never needed. Yet, since this is the first + /// deployment of pallet-staking-async, eras might become longer due to misconfiguration, and we + /// don't want to reduce the validator payouts by too much because of this. Therefore, we allow + /// each era to be at most 2x the expected value + pub const MaxEraDuration: u64 = 2 * ( + // the expected era duration in milliseconds. + RelaySessionDuration::get() as u64 * RELAY_CHAIN_SLOT_DURATION_MILLIS as u64 * SessionsPerEra::get() as u64 + ); } impl pallet_staking_async::Config for Runtime { @@ -302,6 +402,12 @@ impl pallet_staking_async::Config for Runtime { type Currency = Balances; type CurrencyBalance = Balance; type RuntimeHoldReason = RuntimeHoldReason; + // Note: Previously, we used `U128CurrencyToVote`, which donwscaled as the TI moved closer to + // u64::MAX. Both chains are rather close to this value, so we move to saturating. This is a + // good option, as it means some whales, if in any crazy scenario, have more than u64::MAX in + // their balance, the excess will be ignored in staking election voting. Contrary, if we use + // `U128CurrencyToVote`, the presence of one whale with more than u64::MAX will cause everyone's + // staking election vote to be downscaled by two. type CurrencyToVote = sp_staking::currency_to_vote::SaturatingCurrencyToVote; type RewardRemainder = ResolveTo; type Slash = ResolveTo; @@ -321,12 +427,13 @@ impl pallet_staking_async::Config for Runtime { type HistoryDepth = frame_support::traits::ConstU32<84>; type MaxControllersInDeprecationBatch = MaxControllersInDeprecationBatch; type EventListeners = (NominationPools, DelegatedStaking); - type WeightInfo = weights::pallet_staking_async::WeightInfo; + // Note used; don't care. type MaxInvulnerables = frame_support::traits::ConstU32<20>; type PlanningEraOffset = pallet_staking_async::PlanningEraOffsetOf>; type RcClientInterface = StakingRcClient; type MaxEraDuration = MaxEraDuration; + type WeightInfo = weights::pallet_staking_async::WeightInfo; } impl pallet_staking_async_rc_client::Config for Runtime { @@ -380,12 +487,12 @@ pub struct StakingXcmToRelayChain; impl rc_client::SendToRelayChain for StakingXcmToRelayChain { type AccountId = AccountId; fn validator_set(report: rc_client::ValidatorSetReport) { - rc_client::XCMSender::< - xcm_config::XcmRouter, - RelayLocation, - rc_client::ValidatorSetReport, - ValidatorSetToXcm, - >::split_then_send(report, Some(8)); + // TODO: after https://github.com/paritytech/polkadot-sdk/pull/9619, use `XCMSender::send` + let message = ValidatorSetToXcm::convert(report); + let dest = RelayLocation::get(); + let _ = crate::send_xcm::(dest, message).inspect_err(|err| { + log::error!(target: "runtime::ah-client", "Failed to send validator set report: {:?}", err); + }); } } @@ -404,9 +511,6 @@ where type Extension = TxExtension; fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic { - // TODO: double check. the only way I found to access the `new_transaction` method. - // `UncheckedExtrinsic` is not generic::UncheckedExtrinsic, its wrapped by pallet revive's - // type `UncheckedExtrinsic`. ::Identity::new_transaction(call, extension).into() } } @@ -416,9 +520,278 @@ where RuntimeCall: From, { fn create_bare(call: RuntimeCall) -> UncheckedExtrinsic { - // TODO: double check. the only way I found to access the `new_bare` method. - // `UncheckedExtrinsic` is not generic::UncheckedExtrinsic, its wrapped by pallet revive's - // type `UncheckedExtrinsic`. ::Identity::new_bare(call).into() } } + +pub struct InitiateStakingAsync; +impl frame_support::traits::OnRuntimeUpgrade + for InitiateStakingAsync +{ + fn on_runtime_upgrade() -> Weight { + if crate::VERSION.spec_version == EXPECTED_SPEC { + use pallet_election_provider_multi_block::verifier::Verifier; + // set parity staking miner as the invulnerable submitter in `multi-block`. + // https://kusama.subscan.io/account/GtGGqmjQeRt7Q5ggrjmSHsEEfeXUMvPuF8mLun2ApaiotVr + let acc = hex_literal::hex!( + "bea06e6ad606b2a80822a72aaae84a9a80bec27f1beef1880ad4970b72227601" + ); + if let Ok(bounded) = BoundedVec::::try_from(vec![acc.into()]) { + multi_block::signed::Invulnerables::::put(bounded); + } + + // set the minimum score for the election, as per the kusama RC state. + // + // This value is set from block [29,940,247](https://dev.papi.how/explorer/0xf8e2599cd04321369810cd6b4c520f4bc3a8f08f76089d0e467d4a0967179a94#networkId=kusama&endpoint=wss%3A%2F%2Frpc.ibp.network%2Fkusama) of Kusama RC. + // Recent election scores in Kusama can be found on: + // https://kusama.subscan.io/event?page=1&time_dimension=date&module=electionprovidermultiphase&event_id=electionfinalized + // + // The last example, at block [29939392](https://kusama.subscan.io/event/29939392-0) being: + // + // * minimal_stake: 6543_701_618_936_726 (2.12x the minimum -- 6.5k KSM) + // * sum_stake: 8_062_560_594_210_938_663 (2.3x the minimum -- 8M KSM) + // * sum_stake_squared: 67_504_538_161_651_736_253_970_267_717_229_279 (0.8 the minimum, + // the lower the better) + let minimum_score = sp_npos_elections::ElectionScore { + minimal_stake: 2957640724907066, + sum_stake: 3471819933857856584, + sum_stake_squared: 78133097080615021100202963085417458, + }; + ::Verifier::set_minimum_score(minimum_score); + + // The maximum number of validators should be equal to `TargetSnapshotPerBlock`, 2500. + // + // Note that previously this value was 4000, allowing for possibly more validator + // candidates to exists. In a parachain, we cannot afford this high limit anymore, as + // it would increase the chances of the chain stalling due to over-weight + // on-initialize code. + // + // Future iterations of staking-async will either: + // + // * Remove this bottleneck + // * Move to using `on_poll` + // + // After which this limit can be increased again. + pallet_staking_async::ValidatorCount::::put(2500); + + ::DbWeight::get().writes(3) + } else { + Default::default() + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use sp_runtime::Percent; + use sp_weights::constants::{WEIGHT_PROOF_SIZE_PER_KB, WEIGHT_REF_TIME_PER_MILLIS}; + + fn analyze_weight( + op_name: &str, + op_weight: Weight, + limit_weight: Weight, + maybe_max_ratio: Option, + ) { + sp_tracing::try_init_simple(); + let ref_time_ms = op_weight.ref_time() / WEIGHT_REF_TIME_PER_MILLIS; + let ref_time_ratio = Percent::from_rational(op_weight.ref_time(), limit_weight.ref_time()); + let proof_size_kb = op_weight.proof_size() / WEIGHT_PROOF_SIZE_PER_KB; + let proof_size_ratio = + Percent::from_rational(op_weight.proof_size(), limit_weight.proof_size()); + let limit_ms = limit_weight.ref_time() / WEIGHT_REF_TIME_PER_MILLIS; + let limit_kb = limit_weight.proof_size() / WEIGHT_PROOF_SIZE_PER_KB; + log::info!(target: "runtime::asset-hub-kusama", "weight of {:?} is: ref-time: {}ms, {:?} of total, proof-size: {}KiB, {:?} of total (total: {}ms, {}KiB)", + op_name, + ref_time_ms, + ref_time_ratio, + proof_size_kb, + proof_size_ratio, + limit_ms, + limit_kb + ); + + if let Some(max_ratio) = maybe_max_ratio { + assert!(ref_time_ratio <= max_ratio && proof_size_ratio <= max_ratio,) + } + } + + mod incoming_xcm_weights { + use sp_runtime::{Perbill, Percent}; + + use crate::staking::tests::analyze_weight; + + #[test] + fn offence_report() { + use crate::{AccountId, Runtime}; + use frame_support::dispatch::GetDispatchInfo; + use pallet_staking_async_rc_client as rc_client; + + // up to a 1/3 of the validators are reported in a single batch of offences + let hefty_offences = (0..333) + .map(|i| { + rc_client::Offence { + offender: ::from([i as u8; 32]), /* overflows, but whatever, + * don't matter */ + reporters: vec![::from([1u8; 32])], + slash_fraction: Perbill::from_percent(10), + } + }) + .collect(); + let di = rc_client::Call::::relay_new_offence { + slash_session: 42, + offences: hefty_offences, + } + .get_dispatch_info(); + + let offence_report = di.call_weight + di.extension_weight; + let mq_service_weight = crate::MessageQueueServiceWeight::get(); + + analyze_weight( + "offence_report", + offence_report, + mq_service_weight, + Some(Percent::from_percent(95)), + ); + } + + #[test] + fn session_report() { + use crate::{AccountId, Runtime}; + use frame_support::dispatch::GetDispatchInfo; + use pallet_staking_async_rc_client as rc_client; + + sp_io::TestExternalities::new_empty().execute_with(|| { + // this benchmark is a function of current active validator count + pallet_staking_async::ValidatorCount::::put(1000); + let hefty_report = rc_client::SessionReport { + activation_timestamp: Some((42, 42)), + end_index: 42, + leftover: false, + validator_points: (0..1000u32) + .map(|i| { + let unique = i.to_le_bytes(); + let mut acc = [0u8; 32]; + // first 4 bytes should be `unique`, rest 0 + acc[..4].copy_from_slice(&unique); + (AccountId::from(acc), i) + }) + .collect(), + }; + let di = rc_client::Call::::relay_session_report { report: hefty_report } + .get_dispatch_info(); + let session_report_weight = di.call_weight + di.extension_weight; + let mq_service_weight = crate::MessageQueueServiceWeight::get(); + analyze_weight( + "session_report", + session_report_weight, + mq_service_weight, + Some(Percent::from_percent(95)), + ); + }) + } + } + + /// The staking/election weights to check. + /// + /// * Snapshot-MSP weight (when we take validator snapshot, function of + /// `TargetSnapshotPerBlock`) + /// * Snapshot-rest weight (when we take nominator snapshot, function of + /// `VoterSnapshotPerBlock`) + /// * Verification of the last page (the most expensive) + /// * The time it takes to mine a solution via OCW (function of `MinerPages`) + /// * The weight of the on-the-spot-verification of an OCW-mined solution (function of + /// `MinerPages`) + /// * Election export terminal (which is the most expensive, and has round cleanup in it) + mod weights { + use super::*; + #[test] + fn snapshot_msp_weight() { + use multi_block::WeightInfo; + analyze_weight( + "snapshot_msp", + ::WeightInfo::on_initialize_into_snapshot_msp(), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + } + + #[test] + fn snapshot_rest_weight() { + use multi_block::WeightInfo; + analyze_weight( + "snapshot_rest", + ::WeightInfo::on_initialize_into_snapshot_rest(), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + } + + #[test] + fn verifier_weight() { + use multi_block::verifier::WeightInfo; + analyze_weight( + "verifier valid terminal", + ::WeightInfo::on_initialize_valid_terminal(), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + + analyze_weight( + "verifier invalid terminal", + ::WeightInfo::on_initialize_invalid_terminal(), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + } + + #[test] + fn round_cleanup() { + use multi_block::signed::WeightInfo; + analyze_weight( + "single solution cleanup", + ::WeightInfo::clear_old_round_data( + Pages::get(), + ), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + analyze_weight( + "full solution cleanup", + ::WeightInfo::clear_old_round_data( + Pages::get(), + ) + .mul(16 as u64), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + } + + #[test] + fn export_weight() { + use multi_block::WeightInfo; + analyze_weight( + "export terminal", + ::WeightInfo::export_terminal(), + ::BlockWeights::get().max_block, + Some(Percent::from_percent(75)), + ); + } + + #[test] + fn verify_unsigned_solution() { + use multi_block::unsigned::WeightInfo; + analyze_weight( + "unsigned solution verify", + ::WeightInfo::submit_unsigned(), + ::BlockWeights::get() + .per_class + .get(DispatchClass::Operational) + .max_extrinsic + .unwrap(), + Some(Percent::from_percent(50)), + ); + } + } +} diff --git a/system-parachains/asset-hubs/asset-hub-kusama/src/weights/pallet_election_provider_multi_block.rs b/system-parachains/asset-hubs/asset-hub-kusama/src/weights/pallet_election_provider_multi_block.rs index 2a33672edc..3b4bb63631 100644 --- a/system-parachains/asset-hubs/asset-hub-kusama/src/weights/pallet_election_provider_multi_block.rs +++ b/system-parachains/asset-hubs/asset-hub-kusama/src/weights/pallet_election_provider_multi_block.rs @@ -14,10 +14,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO: I generated this file on a refhw VPS. Should be replaced by a final run of the CI bench bot. + + //! Autogenerated weights for `pallet_election_provider_multi_block` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 48.0.0 -//! DATE: 2025-07-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2025-09-05, STEPS: `10`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `ggwpez-ref-hw`, CPU: `AMD EPYC 7232P 8-Core Processor` //! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: 1024 @@ -28,21 +31,22 @@ // benchmark // pallet // --runtime -// target/production/wbuild/asset-hub-polkadot-runtime/asset_hub_polkadot_runtime.compact.compressed.wasm +// ./target/release/wbuild/asset-hub-kusama-runtime/asset_hub_kusama_runtime.wasm +// --pallets +// pallet_election_provider_multi_block // --extrinsic -// -// --header -// .github/scripts/cmd/file_header.txt +// * +// --steps +// 10 +// --repeat +// 10 // --output -// system-parachains/asset-hubs/asset-hub-polkadot/src/weights/ -// --heap-pages=4096 -// --pallet=pallet_staking_async,pallet_fast_unstake,pallet_bags_list,pallet_election_provider_multi_block,pallet_election_provider_multi_block_verifier,pallet_election_provider_multi_block_unsigned,pallet_election_provider_multi_block_signed +// . #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -#![allow(dead_code)] use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; @@ -56,14 +60,16 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) fn on_initialize_nothing() -> Weight { // Proof Size summary in bytes: - // Measured: `223` - // Estimated: `3688` - // Minimum execution time: 11_180_000 picoseconds. - Weight::from_parts(11_530_000, 0) - .saturating_add(Weight::from_parts(0, 3688)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `400` + // Estimated: `3865` + // Minimum execution time: 17_280_000 picoseconds. + Weight::from_parts(17_780_000, 0) + .saturating_add(Weight::from_parts(0, 3865)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) @@ -76,26 +82,28 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: UNKNOWN KEY `0x5640fd84ada5e16d1b6739279282536c` (r:1 w:0) /// Storage: `Staking::CounterForValidators` (r:1 w:0) /// Proof: `Staking::CounterForValidators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) - /// Storage: `Staking::Validators` (r:2001 w:0) + /// Storage: `Staking::Validators` (r:2501 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `Measured`) /// Storage: `MultiBlockElectionVerifier::StatusStorage` (r:1 w:0) /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) /// Storage: `MultiBlockElection::DesiredTargets` (r:0 w:1) /// Proof: `MultiBlockElection::DesiredTargets` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `Measured`) /// Storage: `MultiBlockElection::PagedTargetSnapshotHash` (r:0 w:1) /// Proof: `MultiBlockElection::PagedTargetSnapshotHash` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `Measured`) /// Storage: `MultiBlockElection::PagedTargetSnapshot` (r:0 w:1) - /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(64026), added: 66501, mode: `Measured`) + /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(80026), added: 82501, mode: `Measured`) fn on_initialize_into_snapshot_msp() -> Weight { // Proof Size summary in bytes: - // Measured: `95221` - // Estimated: `5048686` - // Minimum execution time: 13_515_581_000 picoseconds. - Weight::from_parts(13_558_480_000, 0) - .saturating_add(Weight::from_parts(0, 5048686)) - .saturating_add(T::DbWeight::get().reads(2008)) + // Measured: `119145` + // Estimated: `6310110` + // Minimum execution time: 17_587_116_000 picoseconds. + Weight::from_parts(17_844_999_000, 0) + .saturating_add(Weight::from_parts(0, 6310110)) + .saturating_add(T::DbWeight::get().reads(2509)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) @@ -108,15 +116,15 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) /// Storage: `VoterList::ListBags` (r:1 w:0) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `Measured`) - /// Storage: `VoterList::ListNodes` (r:706 w:0) + /// Storage: `VoterList::ListNodes` (r:784 w:0) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:704 w:0) + /// Storage: `Staking::Bonded` (r:782 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `Measured`) - /// Storage: `Staking::Ledger` (r:704 w:0) + /// Storage: `Staking::Ledger` (r:782 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(753), added: 3228, mode: `Measured`) - /// Storage: `Staking::Nominators` (r:704 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `Measured`) - /// Storage: `Staking::Validators` (r:216 w:0) + /// Storage: `Staking::Nominators` (r:782 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(814), added: 3289, mode: `Measured`) + /// Storage: `Staking::Validators` (r:490 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `Measured`) /// Storage: `MultiBlockElection::Round` (r:1 w:0) /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) @@ -124,22 +132,24 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) /// Storage: `Staking::MinimumActiveStake` (r:0 w:1) /// Proof: `Staking::MinimumActiveStake` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) /// Storage: `VoterList::Lock` (r:0 w:1) /// Proof: `VoterList::Lock` (`max_values`: Some(1), `max_size`: Some(0), added: 495, mode: `Measured`) /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:0 w:1) - /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(389338), added: 391813, mode: `Measured`) + /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(632664), added: 635139, mode: `Measured`) /// Storage: `MultiBlockElection::PagedVoterSnapshotHash` (r:0 w:1) /// Proof: `MultiBlockElection::PagedVoterSnapshotHash` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `Measured`) fn on_initialize_into_snapshot_rest() -> Weight { // Proof Size summary in bytes: - // Measured: `1466883` - // Estimated: `3215223` - // Minimum execution time: 38_139_334_000 picoseconds. - Weight::from_parts(42_870_088_000, 0) - .saturating_add(Weight::from_parts(0, 3215223)) - .saturating_add(T::DbWeight::get().reads(3042)) + // Measured: `1398540` + // Estimated: `3339930` + // Minimum execution time: 46_425_559_000 picoseconds. + Weight::from_parts(46_926_093_000, 0) + .saturating_add(Weight::from_parts(0, 3339930)) + .saturating_add(T::DbWeight::get().reads(3629)) .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) @@ -150,17 +160,17 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `Staking::VoterSnapshotStatus` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `Measured`) /// Storage: `VoterList::CounterForListNodes` (r:1 w:0) /// Proof: `VoterList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) - /// Storage: `VoterList::ListNodes` (r:706 w:0) + /// Storage: `VoterList::ListNodes` (r:784 w:0) /// Proof: `VoterList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `Measured`) - /// Storage: `Staking::Bonded` (r:704 w:0) + /// Storage: `Staking::Bonded` (r:782 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `Measured`) - /// Storage: `Staking::Ledger` (r:704 w:0) + /// Storage: `Staking::Ledger` (r:782 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(753), added: 3228, mode: `Measured`) - /// Storage: `Staking::Nominators` (r:704 w:0) - /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `Measured`) + /// Storage: `Staking::Nominators` (r:782 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(814), added: 3289, mode: `Measured`) /// Storage: `VoterList::ListBags` (r:1 w:0) /// Proof: `VoterList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `Measured`) - /// Storage: `Staking::Validators` (r:38 w:0) + /// Storage: `Staking::Validators` (r:196 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `Measured`) /// Storage: `MultiBlockElection::Round` (r:1 w:0) /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) @@ -170,38 +180,42 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) /// Storage: `Staking::MinimumActiveStake` (r:0 w:1) /// Proof: `Staking::MinimumActiveStake` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) /// Storage: `VoterList::Lock` (r:0 w:1) /// Proof: `VoterList::Lock` (`max_values`: Some(1), `max_size`: Some(0), added: 495, mode: `Measured`) /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:0 w:1) - /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(389338), added: 391813, mode: `Measured`) + /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(632664), added: 635139, mode: `Measured`) /// Storage: `MultiBlockElection::PagedVoterSnapshotHash` (r:0 w:1) /// Proof: `MultiBlockElection::PagedVoterSnapshotHash` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `Measured`) fn on_initialize_into_signed() -> Weight { // Proof Size summary in bytes: - // Measured: `1536828` - // Estimated: `3285168` - // Minimum execution time: 40_918_833_000 picoseconds. - Weight::from_parts(41_169_753_000, 0) - .saturating_add(Weight::from_parts(0, 3285168)) - .saturating_add(T::DbWeight::get().reads(2865)) + // Measured: `1602506` + // Estimated: `3543896` + // Minimum execution time: 43_225_429_000 picoseconds. + Weight::from_parts(43_298_861_000, 0) + .saturating_add(Weight::from_parts(0, 3543896)) + .saturating_add(T::DbWeight::get().reads(3336)) .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) /// Storage: `MultiBlockElectionVerifier::StatusStorage` (r:1 w:0) /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) fn on_initialize_into_signed_validation() -> Weight { // Proof Size summary in bytes: - // Measured: `417` - // Estimated: `3882` - // Minimum execution time: 45_840_000 picoseconds. - Weight::from_parts(56_110_000, 0) - .saturating_add(Weight::from_parts(0, 3882)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `594` + // Estimated: `4059` + // Minimum execution time: 59_370_000 picoseconds. + Weight::from_parts(62_231_000, 0) + .saturating_add(Weight::from_parts(0, 4059)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) @@ -212,14 +226,16 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: UNKNOWN KEY `0xc209f5d8eb920681b56c64b8694ea78c` (r:1 w:0) /// Storage: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) /// Proof: UNKNOWN KEY `0x48384a816e4f71a936cb76dc9e303f2a` (r:1 w:0) + /// Storage: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x5fa6b11cf49311969aa152d95989a962` (r:1 w:0) fn on_initialize_into_unsigned() -> Weight { // Proof Size summary in bytes: - // Measured: `417` - // Estimated: `3882` - // Minimum execution time: 53_260_000 picoseconds. - Weight::from_parts(56_970_000, 0) - .saturating_add(Weight::from_parts(0, 3882)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `594` + // Estimated: `4059` + // Minimum execution time: 61_550_000 picoseconds. + Weight::from_parts(62_480_000, 0) + .saturating_add(Weight::from_parts(0, 4059)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) @@ -229,32 +245,32 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:0) /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) /// Storage: `MultiBlockElectionVerifier::QueuedSolutionX` (r:1 w:0) - /// Proof: `MultiBlockElectionVerifier::QueuedSolutionX` (`max_values`: None, `max_size`: Some(33842026), added: 33844501, mode: `Measured`) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionX` (`max_values`: None, `max_size`: Some(37586026), added: 37588501, mode: `Measured`) /// Storage: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) /// Storage: `Staking::ElectableStashes` (r:1 w:1) /// Proof: `Staking::ElectableStashes` (`max_values`: Some(1), `max_size`: Some(32002), added: 32497, mode: `Measured`) - /// Storage: `Staking::ErasStakersOverview` (r:981 w:981) + /// Storage: `Staking::ErasStakersOverview` (r:916 w:916) /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `Measured`) /// Storage: `Staking::ErasTotalStake` (r:1 w:1) /// Proof: `Staking::ErasTotalStake` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `Measured`) - /// Storage: `Staking::Validators` (r:981 w:0) + /// Storage: `Staking::Validators` (r:916 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `Measured`) - /// Storage: `Staking::ErasValidatorPrefs` (r:0 w:981) + /// Storage: `Staking::ErasValidatorPrefs` (r:0 w:916) /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:0 w:980) + /// Storage: `Staking::ErasStakersPaged` (r:0 w:896) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: Some(24656), added: 27131, mode: `Measured`) fn export_non_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `336781` - // Estimated: `2765746` - // Minimum execution time: 18_476_588_000 picoseconds. - Weight::from_parts(18_649_428_000, 0) - .saturating_add(Weight::from_parts(0, 2765746)) - .saturating_add(T::DbWeight::get().reads(1970)) - .saturating_add(T::DbWeight::get().writes(2945)) + // Measured: `240793` + // Estimated: `2508883` + // Minimum execution time: 18_196_918_000 picoseconds. + Weight::from_parts(19_652_445_000, 0) + .saturating_add(Weight::from_parts(0, 2508883)) + .saturating_add(T::DbWeight::get().reads(1840)) + .saturating_add(T::DbWeight::get().writes(2731)) } /// Storage: `MultiBlockElection::CurrentPhase` (r:1 w:1) /// Proof: `MultiBlockElection::CurrentPhase` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) @@ -262,54 +278,54 @@ impl pallet_election_provider_multi_block::WeightInfo f /// Proof: `MultiBlockElection::Round` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) /// Storage: `MultiBlockElectionVerifier::QueuedValidVariant` (r:1 w:1) /// Proof: `MultiBlockElectionVerifier::QueuedValidVariant` (`max_values`: None, `max_size`: Some(13), added: 2488, mode: `Measured`) - /// Storage: `MultiBlockElectionVerifier::QueuedSolutionX` (r:32 w:32) - /// Proof: `MultiBlockElectionVerifier::QueuedSolutionX` (`max_values`: None, `max_size`: Some(33842026), added: 33844501, mode: `Measured`) + /// Storage: `MultiBlockElectionVerifier::QueuedSolutionX` (r:16 w:16) + /// Proof: `MultiBlockElectionVerifier::QueuedSolutionX` (`max_values`: None, `max_size`: Some(37586026), added: 37588501, mode: `Measured`) /// Storage: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6f320d44e42312c78638e6c92dff65af` (r:1 w:0) - /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:32 w:32) - /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(389338), added: 391813, mode: `Measured`) - /// Storage: `MultiBlockElection::PagedVoterSnapshotHash` (r:32 w:32) + /// Storage: `MultiBlockElection::PagedVoterSnapshot` (r:16 w:16) + /// Proof: `MultiBlockElection::PagedVoterSnapshot` (`max_values`: None, `max_size`: Some(632664), added: 635139, mode: `Measured`) + /// Storage: `MultiBlockElection::PagedVoterSnapshotHash` (r:16 w:16) /// Proof: `MultiBlockElection::PagedVoterSnapshotHash` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `Measured`) /// Storage: `MultiBlockElection::PagedTargetSnapshot` (r:1 w:1) - /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(64026), added: 66501, mode: `Measured`) + /// Proof: `MultiBlockElection::PagedTargetSnapshot` (`max_values`: None, `max_size`: Some(80026), added: 82501, mode: `Measured`) /// Storage: `MultiBlockElection::PagedTargetSnapshotHash` (r:1 w:1) /// Proof: `MultiBlockElection::PagedTargetSnapshotHash` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `Measured`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `Measured`) /// Storage: `Staking::ElectableStashes` (r:1 w:1) /// Proof: `Staking::ElectableStashes` (`max_values`: Some(1), `max_size`: Some(32002), added: 32497, mode: `Measured`) - /// Storage: `Staking::ErasStakersOverview` (r:995 w:995) + /// Storage: `Staking::ErasStakersOverview` (r:972 w:972) /// Proof: `Staking::ErasStakersOverview` (`max_values`: None, `max_size`: Some(92), added: 2567, mode: `Measured`) - /// Storage: `Staking::ErasStakersPaged` (r:995 w:995) + /// Storage: `Staking::ErasStakersPaged` (r:972 w:972) /// Proof: `Staking::ErasStakersPaged` (`max_values`: None, `max_size`: Some(24656), added: 27131, mode: `Measured`) /// Storage: `Staking::ErasTotalStake` (r:1 w:1) /// Proof: `Staking::ErasTotalStake` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `Measured`) - /// Storage: `Staking::Validators` (r:995 w:0) + /// Storage: `Staking::Validators` (r:972 w:0) /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `Measured`) /// Storage: `MultiBlockElectionVerifier::StatusStorage` (r:0 w:1) /// Proof: `MultiBlockElectionVerifier::StatusStorage` (`max_values`: Some(1), `max_size`: Some(5), added: 500, mode: `Measured`) /// Storage: `MultiBlockElectionVerifier::QueuedSolutionScore` (r:0 w:1) /// Proof: `MultiBlockElectionVerifier::QueuedSolutionScore` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `Measured`) - /// Storage: `Staking::ErasValidatorPrefs` (r:0 w:995) + /// Storage: `Staking::ErasValidatorPrefs` (r:0 w:972) /// Proof: `Staking::ErasValidatorPrefs` (`max_values`: None, `max_size`: Some(57), added: 2532, mode: `Measured`) /// Storage: `MultiBlockElection::DesiredTargets` (r:0 w:1) /// Proof: `MultiBlockElection::DesiredTargets` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `Measured`) fn export_terminal() -> Weight { // Proof Size summary in bytes: - // Measured: `7461067` - // Estimated: `9924682` - // Minimum execution time: 48_080_914_000 picoseconds. - Weight::from_parts(48_305_537_000, 0) - .saturating_add(Weight::from_parts(0, 9924682)) - .saturating_add(T::DbWeight::get().reads(3090)) - .saturating_add(T::DbWeight::get().writes(3091)) + // Measured: `2929834` + // Estimated: `5336524` + // Minimum execution time: 39_360_560_000 picoseconds. + Weight::from_parts(39_715_782_000, 0) + .saturating_add(Weight::from_parts(0, 5336524)) + .saturating_add(T::DbWeight::get().reads(2973)) + .saturating_add(T::DbWeight::get().writes(2974)) } fn manage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 180_000 picoseconds. - Weight::from_parts(230_000, 0) + // Minimum execution time: 190_000 picoseconds. + Weight::from_parts(220_000, 0) .saturating_add(Weight::from_parts(0, 0)) } }