mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 17:07:56 +00:00
move paras inherent filtering to runtime (#4028)
* move things around, add filter methods * validator keys, modify availability bitfields according to disputes * simplify, keep the filter -> sanitize generic for both usecases * minor * assure tests still work, reduce changeset * integration * start entropy passing * fixins * compile, 1 failing test * filter with coverage * fixins * Update runtime/parachains/src/paras_inherent.rs Co-authored-by: Robert Habermeier <rphmeier@gmail.com> * slip of the pen * improve test cases * misc * fix * fixins * test avoid extra into() calls in assert_noop! * chores * ff * test fixup superfluous into call * chore: pfmt * improve apply_block_weight_limit to try to maximize the number of sufficiently backed blocks and add extra bitfields in a round-robin fashion * new code treats the lack of backed candidates as ok * Use vrf based entropy * fixup vrf random * add warn * slip of the pen * fixup * assure ordering * rethink apply_weights * mock * use a closure as predicate check * extract and use DisputedBitfield * chore: simplify * remove stray dbg * chore: fmt * address feedback * fix test, halfway there * stage1 * dbg stuff * make group selection align * fix session index * fix wrongly returned candidates * cleanup * chore fmt * fix ensure check * make good case test work * more tests for bitfields * create sanitize_backed_candidates * fixup tests * update guide * add check referenced in the guide * improve weights code * fmt * fixins * Update roadmap/implementers-guide/src/runtime/inclusion.md Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> * compiling + address review * add comments * fix weight calc * address review comments and test failure * fix * fix: condition * Fix random_sel function * Fix overlength block check * Zeke + Ladi commit for disputes filtering + integration test builder + runtime benchmarks + integration tests * Add benchmarks for code upgrades * Code upgrade bench; Feature gate TestWeightInfo * Try and make CI happier * Feature gate enter test to not(benchmarks) * Make sure no unused imports/fn * refactor, re-use, the beginning * Fix issue with frame benchmarking dep compilation * More precise feature gating for some derives * integrate piece-wise * foo * fixins * chore fmt * fixins * rename const generic * Update runtime/parachains/src/paras_inherent.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Fix compilation * limit to test * remove unused spam slots * spellcheck * remove a tick, fix a typo * Add Code upgrade weights * comment improvements + >= Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * remove another tick * Update runtime/parachains/src/paras_inherent/benchmarking.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * saturating fixins + some spaces * fix * benchmarking - preliminary results * Add training wheels * Refactor some early exit logic for enter * Gracefully handle filtering bitfields & candidates (#4280) This updates the logic for sanitize_bitfields and sanitize_backed_candidates to never error when there is an issue, but instead to simply skip the problematic items. * Refactor inherent data weight limiting logic (#4287) * Apply suggestions from code review * Update runtime/parachains/src/builder.rs Co-authored-by: Zeke Mostov <z.mostov@gmail.com> * Update runtime/parachains/src/builder.rs * Update runtime/parachains/src/paras_inherent.rs * final pass * Run cargo +nightly-2021-10-29 fmt * Update implementors guide with `sanitize_*` & `enter` (#4294) * Make spell check happier * Make wasm runtimes compile with benchmarks enabled (#4303) * comment stuff out, use old toml * Seems to be working? * Remove feature gating from builder * Remove commented out stuff * Remove generic from digest * Update weight files for runtime Co-authored-by: Robert Habermeier <rphmeier@gmail.com> Co-authored-by: Zeke Mostov <32168567+emostov@users.noreply.github.com> Co-authored-by: Lldenaurois <Ljdenaurois@gmail.com> Co-authored-by: Zeke Mostov <z.mostov@gmail.com> Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
committed by
GitHub
parent
4a2e412000
commit
1aa6a4aba4
Generated
+1
@@ -6887,6 +6887,7 @@ dependencies = [
|
||||
"log",
|
||||
"pallet-authority-discovery",
|
||||
"pallet-authorship",
|
||||
"pallet-babe",
|
||||
"pallet-balances",
|
||||
"pallet-session",
|
||||
"pallet-staking",
|
||||
|
||||
@@ -36,3 +36,4 @@ std = [
|
||||
"polkadot-core-primitives/std",
|
||||
"frame-support/std",
|
||||
]
|
||||
runtime-benchmarks = []
|
||||
|
||||
@@ -41,9 +41,19 @@ pub use polkadot_core_primitives::BlockNumber as RelayChainBlockNumber;
|
||||
|
||||
/// Parachain head data included in the chain.
|
||||
#[derive(
|
||||
PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, derive_more::From, TypeInfo,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Clone,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Encode,
|
||||
Decode,
|
||||
RuntimeDebug,
|
||||
derive_more::From,
|
||||
TypeInfo,
|
||||
Default,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Default, Hash, MallocSizeOf))]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))]
|
||||
pub struct HeadData(#[cfg_attr(feature = "std", serde(with = "bytes"))] pub Vec<u8>);
|
||||
|
||||
impl HeadData {
|
||||
|
||||
@@ -55,4 +55,4 @@ std = [
|
||||
"polkadot-core-primitives/std",
|
||||
"bitvec/std",
|
||||
"frame-system/std",
|
||||
]
|
||||
]
|
||||
@@ -107,8 +107,8 @@ impl MallocSizeOf for ValidatorId {
|
||||
}
|
||||
|
||||
/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when appropriate.
|
||||
#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug, Hash, MallocSizeOf))]
|
||||
#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, Debug)]
|
||||
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))]
|
||||
pub struct ValidatorIndex(pub u32);
|
||||
|
||||
// We should really get https://github.com/paritytech/polkadot/issues/2403 going ..
|
||||
|
||||
@@ -327,8 +327,8 @@ fn check_collator_signature<H: AsRef<[u8]>>(
|
||||
}
|
||||
|
||||
/// A unique descriptor of the candidate receipt.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default, Hash, MallocSizeOf))]
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Hash, MallocSizeOf))]
|
||||
pub struct CandidateDescriptor<H = Hash> {
|
||||
/// The ID of the para this is a candidate for.
|
||||
pub para_id: Id,
|
||||
@@ -407,8 +407,8 @@ pub struct FullCandidateReceipt<H = Hash, N = BlockNumber> {
|
||||
}
|
||||
|
||||
/// A candidate-receipt with commitments directly included.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default, Hash, MallocSizeOf))]
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Hash, MallocSizeOf))]
|
||||
pub struct CommittedCandidateReceipt<H = Hash> {
|
||||
/// The descriptor of the candidate.
|
||||
pub descriptor: CandidateDescriptor<H>,
|
||||
@@ -509,8 +509,8 @@ impl<H: Encode, N: Encode> PersistedValidationData<H, N> {
|
||||
}
|
||||
|
||||
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Default, Hash, MallocSizeOf))]
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, Default)]
|
||||
#[cfg_attr(feature = "std", derive(Debug, Hash, MallocSizeOf))]
|
||||
pub struct CandidateCommitments<N = BlockNumber> {
|
||||
/// Messages destined to be interpreted by the Relay chain itself.
|
||||
pub upward_messages: Vec<UpwardMessage>,
|
||||
@@ -534,6 +534,8 @@ impl CandidateCommitments {
|
||||
}
|
||||
|
||||
/// A bitfield concerning availability of backed candidates.
|
||||
///
|
||||
/// Every bit refers to an availability core index.
|
||||
#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
|
||||
pub struct AvailabilityBitfield(pub BitVec<bitvec::order::Lsb0, u8>);
|
||||
|
||||
|
||||
@@ -41,6 +41,13 @@ use crate::v0::{SigningContext, ValidatorId, ValidatorIndex, ValidatorSignature}
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug)]
|
||||
pub struct Signed<Payload, RealPayload = Payload>(UncheckedSigned<Payload, RealPayload>);
|
||||
|
||||
impl<Payload, RealPayload> Signed<Payload, RealPayload> {
|
||||
/// Convert back to an unchecked type.
|
||||
pub fn into_unchecked(self) -> UncheckedSigned<Payload, RealPayload> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Unchecked signed data, can be converted to `Signed` by checking the signature.
|
||||
#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo)]
|
||||
pub struct UncheckedSigned<Payload, RealPayload = Payload> {
|
||||
@@ -253,6 +260,37 @@ impl<Payload: EncodeAs<RealPayload>, RealPayload: Encode> UncheckedSigned<Payloa
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Sign this payload with the given context and pair.
|
||||
///
|
||||
/// # WARNING
|
||||
/// Only meant for usage in tests and and benchmarks.
|
||||
pub fn benchmark_sign<H: Encode>(
|
||||
public: &crate::v0::ValidatorId,
|
||||
payload: Payload,
|
||||
context: &SigningContext<H>,
|
||||
validator_index: ValidatorIndex,
|
||||
) -> Self {
|
||||
use application_crypto::RuntimeAppPublic;
|
||||
let data = Self::payload_data(&payload, context);
|
||||
let signature = public.sign(&data).unwrap();
|
||||
|
||||
Self { payload, validator_index, signature, real_payload: sp_std::marker::PhantomData }
|
||||
}
|
||||
|
||||
/// Immutably access the signature.
|
||||
///
|
||||
/// # WARNING
|
||||
/// Only meant for usage in tests and and benchmarks.
|
||||
pub fn benchmark_signature(&self) -> ValidatorSignature {
|
||||
self.signature.clone()
|
||||
}
|
||||
|
||||
/// Set the signature. Only should be used for creating testing mocks.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn set_signature(&mut self, signature: ValidatorSignature) {
|
||||
self.signature = signature
|
||||
}
|
||||
}
|
||||
|
||||
impl<Payload, RealPayload> From<Signed<Payload, RealPayload>>
|
||||
|
||||
@@ -45,13 +45,38 @@ PendingAvailabilityCommitments: map ParaId => CandidateCommitments;
|
||||
All failed checks should lead to an unrecoverable error making the block invalid.
|
||||
|
||||
* `process_bitfields(expected_bits, Bitfields, core_lookup: Fn(CoreIndex) -> Option<ParaId>)`:
|
||||
1. check that there is at most 1 bitfield per validator and that the number of bits in each bitfield is equal to `expected_bits`.
|
||||
1. check that there are no duplicates
|
||||
1. check all validator signatures.
|
||||
1. call `sanitize_bitfields<true>` and use the sanitized `signed_bitfields` from now on.
|
||||
1. call `sanitize_backed_candidates<true>` and use the sanitized `backed_candidates` from now on.
|
||||
1. apply each bit of bitfield to the corresponding pending candidate. looking up parathread cores using the `core_lookup`. Disregard bitfields that have a `1` bit for any free cores.
|
||||
1. For each applied bit of each availability-bitfield, set the bit for the validator in the `CandidatePendingAvailability`'s `availability_votes` bitfield. Track all candidates that now have >2/3 of bits set in their `availability_votes`. These candidates are now available and can be enacted.
|
||||
1. For all now-available candidates, invoke the `enact_candidate` routine with the candidate and relay-parent number.
|
||||
1. Return a list of `(CoreIndex, CandidateHash)` from freed cores consisting of the cores where candidates have become available.
|
||||
* `sanitize_bitfields<T: crate::inclusion::Config, const CHECK_SIGS: bool>(
|
||||
unchecked_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
disputed_bitfield: DisputedBitfield,
|
||||
expected_bits: usize,
|
||||
parent_hash: T::Hash,
|
||||
session_index: SessionIndex,
|
||||
validators: &[ValidatorId],
|
||||
)`:
|
||||
1. check that `disputed_bitfield` has the same number of bits as the `expected_bits`, iff not return early with an empty vec.
|
||||
1. each of the below checks is for each bitfield. If a check does not pass the bitfield will be skipped.
|
||||
1. check that there are no bits set that reference a disputed candidate.
|
||||
1. check that the number of bits is equal to `expected_bits`.
|
||||
1. check that the validator index is strictly increasing (and thus also unique).
|
||||
1. check that the validator bit index is not out of bounds.
|
||||
1. check the validators signature, iff `CHECK_SIGS=true`.
|
||||
|
||||
* `sanitize_backed_candidates<T: crate::inclusion::Config, F: Fn(CandidateHash) -> bool>(
|
||||
relay_parent: T::Hash,
|
||||
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
||||
candidate_has_concluded_invalid_dispute: F,
|
||||
scheduled: &[CoreAssignment],
|
||||
) `
|
||||
1. filter out any backed candidates that have concluded invalid.
|
||||
1. filter out backed candidates that don't have a matching `relay_parent`.
|
||||
1. filters backed candidates whom's paraid was scheduled by means of the provided `scheduled` parameter.
|
||||
|
||||
* `process_candidates(parent_storage_root, BackedCandidates, scheduled: Vec<CoreAssignment>, group_validators: Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>)`:
|
||||
1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`.
|
||||
1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates.
|
||||
@@ -78,6 +103,7 @@ All failed checks should lead to an unrecoverable error making the block invalid
|
||||
1. call `Hrmp::prune_hrmp` with the para id of the candiate and the candidate's `hrmp_watermark`.
|
||||
1. call `Hrmp::queue_outbound_hrmp` with the para id of the candidate and the list of horizontal messages taken from the commitment,
|
||||
1. Call `Paras::note_new_head` using the `HeadData` from the receipt and `relay_parent_number`.
|
||||
|
||||
* `collect_pending`:
|
||||
|
||||
```rust
|
||||
|
||||
@@ -29,10 +29,19 @@ OnChainVotes: Option<ScrapedOnChainVotes>,
|
||||
|
||||
## Entry Points
|
||||
|
||||
* `enter`: This entry-point accepts three parameters: The relay-chain parent block header, [`Bitfields`](../types/availability.md#signed-availability-bitfield) and [`BackedCandidates`](../types/backing.md#backed-candidate).
|
||||
1. Hash the parent header and make sure that it corresponds to the block hash of the parent (tracked by the `frame_system` FRAME module),
|
||||
* `enter`: This entry-point accepts one parameter: [`ParaInherentData`](../types/runtime.md#ParaInherentData).
|
||||
1. Ensure the origin is none.
|
||||
1. Ensure `Included` is set as `None`.
|
||||
1. Set `Included` as `Some`.
|
||||
1. Unpack `ParachainsInherentData` into `signed_bitfields`, `backed_candidates`, `parent_header`, and `disputes`.
|
||||
1. Hash the parent header and make sure that it corresponds to the block hash of the parent (tracked by the `frame_system` FRAME module).
|
||||
1. Calculate the `candidate_weight`, `bitfields_weight`, and `disputes_weight`.
|
||||
1. If the sum of `candidate_weight`, `bitfields_weight`, and `disputes_weight` is greater than the max block weight we do the following with the goal of prioritizing the inclusion of disputes without making it game-able by block authors:
|
||||
1. clear `bitfields` and set `bitfields_weight` equal to 0.
|
||||
1. clear `backed_candidates` and set `candidate_weight` equal to 0.
|
||||
1. invoke `limit_disputes` on the `disputes` with the max block weight iff the disputes weight is greater than the max block weight.
|
||||
1. Invoke `Disputes::provide_multi_dispute_data`.
|
||||
1. If `Disputes::is_frozen`, return and set `Included` to `Some(())`.
|
||||
1. If `Disputes::is_frozen`, return.
|
||||
1. If there are any concluded disputes from the current session, invoke `Inclusion::collect_disputed` with the disputed candidates. Annotate each returned core with `FreedReason::Concluded`, sort them, and invoke `Scheduler::free_cores` with them.
|
||||
1. The `Bitfields` are first forwarded to the `Inclusion::process_bitfields` routine, returning a set included candidates and the respective freed cores. Provide the number of availability cores (`Scheduler::availability_cores().len()`) as the expected number of bits and a `Scheduler::core_para` as a core-lookup to the `process_bitfields` routine. Annotate each of these freed cores with `FreedReason::Concluded`.
|
||||
1. For each freed candidate from the `Inclusion::process_bitfields` call, invoke `Disputes::note_included(current_session, candidate)`.
|
||||
@@ -48,3 +57,32 @@ OnChainVotes: Option<ScrapedOnChainVotes>,
|
||||
1. Call `Scheduler::occupied` using the `occupied` core indices of the returned above, first sorting the list of assigned core indices.
|
||||
1. Call the `Ump::process_pending_upward_messages` routine to execute all messages in upward dispatch queues.
|
||||
1. If all of the above succeeds, set `Included` to `Some(())`.
|
||||
|
||||
|
||||
* `create_inherent`: This entry-point accepts one parameter: `InherentData`.
|
||||
1. Invoke [`create_inherent_inner(InherentData)`](#routines), the unit testable logic for filtering and sanitzing the inherent data used when invoking `enter`. Save the result as `inherent_data`.
|
||||
1. If the `inherent_data` is an `Err` variant, return the `enter` call signature with all inherent data cleared else return the `enter` call signature with `inherent_data` passed in as the `data` param.
|
||||
|
||||
# Routines
|
||||
|
||||
* `create_inherent_inner(data: &InherentData) -> Option<ParachainsInherentData<T::Header>>`
|
||||
1. Unpack `InherentData` into its parts, `bitfields`, `backed_candidates`, `disputes` and the `parent_header`. If data cannot be unpacked return `None`.
|
||||
1. Hash the `parent_header` and make sure that it corresponds to the block hash of the parent (tracked by the `frame_system` FRAME module).
|
||||
1. Invoke `Disputes::filter_multi_dispute_data` to remove duplicates et al from `disputes`.
|
||||
1. Run the following within a `with_transaction` closure to avoid side effects (we are essentially replicating the logic that would otherwise happen within `enter` so we can get the filtered bitfields and the `concluded_invalid_disputes` + `scheduled` to use in filtering the `backed_candidates`.):
|
||||
1. Invoke `Disputes::provide_multi_dispute_data`.
|
||||
1. Collect `current_concluded_invalid_disputes`, the disputed candidate hashes from the current session that have concluded invalid.
|
||||
1. Collect `concluded_invalid_disputes`, the disputed candidate hashes from the given `backed_candidates`.
|
||||
1. Invoke `Inclusion::collect_disputed` with the newly disputed candidates. Annotate each returned core with `FreedReason::Concluded`, sort them, and invoke `Scheduler::free_cores` with them.
|
||||
1. Collect filtered `bitfields` by invoking [`sanitize_bitfields<false>`](inclusion.md#Routines).
|
||||
1. Collect `freed_concluded` by invoking `update_pending_availability_and_get_freed_cores` on the filtered bitfields.
|
||||
1. Collect all `freed` cores by invoking `collect_all_freed_cores` on `freed_concluding`.
|
||||
1. Invoke `scheduler::Pallet<T>>::clear()`.
|
||||
1. Invoke `scheduler::Pallet<T>>::schedule` with `freed` and the current block number to create the same schedule of the cores that `enter` will create.
|
||||
1. Read the new `<scheduler::Pallet<T>>::scheduled()` into `schedule`.
|
||||
1. From the `with_transaction` closure return `concluded_invalid_disputes`, `bitfields`, and `scheduled`.
|
||||
1. Invoke `sanitize_backed_candidates` using the `scheduled` return from the `with_transaction` and pass the closure `|candidate_hash: CandidateHash| -> bool { DisputesHandler::concluded_invalid(current_session, candidate_hash) }` for the param `candidate_has_concluded_invalid_dispute`.
|
||||
1. create a `rng` from `rand_chacha::ChaChaRng::from_seed(compute_entropy::<T>(parent_hash))`.
|
||||
1. Invoke `limit_disputes` with the max block weight and `rng`, storing the returned weigh in `remaining_weight`.
|
||||
1. Fill up the remaining of the block weight with backed candidates and bitfields by invoking `apply_weight_limit` with `remaining_weigh` and `rng`.
|
||||
1. Return `Some(ParachainsInherentData { bitfields, backed_candidates, disputes, parent_header }`.
|
||||
|
||||
@@ -116,15 +116,17 @@ struct HostConfiguration {
|
||||
|
||||
Inherent data passed to a runtime entry-point for the advancement of parachain consensus.
|
||||
|
||||
This contains 3 pieces of data:
|
||||
This contains 4 pieces of data:
|
||||
1. [`Bitfields`](availability.md#signed-availability-bitfield)
|
||||
2. [`BackedCandidates`](backing.md#backed-candidate)
|
||||
3. [`MultiDisputeStatementSet`](disputes.md#multidisputestatementset)
|
||||
4. `Header`
|
||||
|
||||
```rust
|
||||
struct ParaInherentData {
|
||||
bitfields: Bitfields,
|
||||
backed_candidates: BackedCandidates,
|
||||
dispute_statements: MultiDisputeStatementSet,
|
||||
parent_header: Header
|
||||
}
|
||||
```
|
||||
|
||||
@@ -214,6 +214,7 @@ runtime-benchmarks = [
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"frame-election-provider-support/runtime-benchmarks",
|
||||
"pallet-bags-list/runtime-benchmarks",
|
||||
"runtime-parachains/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
@@ -1201,7 +1201,9 @@ impl parachains_hrmp::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
}
|
||||
|
||||
impl parachains_paras_inherent::Config for Runtime {}
|
||||
impl parachains_paras_inherent::Config for Runtime {
|
||||
type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
impl parachains_scheduler::Config for Runtime {}
|
||||
|
||||
@@ -1933,6 +1935,7 @@ sp_api::impl_runtime_apis! {
|
||||
list_benchmark!(list, extra, runtime_common::paras_registrar, Registrar);
|
||||
list_benchmark!(list, extra, runtime_parachains::configuration, Configuration);
|
||||
list_benchmark!(list, extra, runtime_parachains::initializer, Initializer);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras_inherent, ParaInherent);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras, Paras);
|
||||
// Substrate
|
||||
list_benchmark!(list, extra, pallet_bags_list, BagsList);
|
||||
@@ -2010,6 +2013,7 @@ sp_api::impl_runtime_apis! {
|
||||
add_benchmark!(params, batches, runtime_common::paras_registrar, Registrar);
|
||||
add_benchmark!(params, batches, runtime_parachains::configuration, Configuration);
|
||||
add_benchmark!(params, batches, runtime_parachains::initializer, Initializer);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras_inherent, ParaInherent);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras, Paras);
|
||||
// Substrate
|
||||
add_benchmark!(params, batches, pallet_balances, Balances);
|
||||
|
||||
@@ -47,3 +47,4 @@ pub mod runtime_common_slots;
|
||||
pub mod runtime_parachains_configuration;
|
||||
pub mod runtime_parachains_initializer;
|
||||
pub mod runtime_parachains_paras;
|
||||
pub mod runtime_parachains_paras_inherent;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2021-11-14, STEPS: `50`, REPEAT: 3, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// target/release/polkadot
|
||||
// benchmark
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=3
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs
|
||||
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `runtime_parachains::paras_inherent`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_variable_disputes(v: u32, ) -> Weight {
|
||||
(316_331_000 as Weight)
|
||||
// Standard Error: 112_000
|
||||
.saturating_add((325_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_bitfields() -> Weight {
|
||||
(352_749_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(15 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidates_variable(v: u32, ) -> Weight {
|
||||
(88_047_000 as Weight)
|
||||
// Standard Error: 3_275_000
|
||||
.saturating_add((68_499_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidate_code_upgrade() -> Weight {
|
||||
(53_728_168_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "maste
|
||||
pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-authorship = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
@@ -94,4 +95,4 @@ try-runtime = [
|
||||
"pallet-staking/try-runtime",
|
||||
"pallet-timestamp/try-runtime",
|
||||
"pallet-vesting/try-runtime",
|
||||
]
|
||||
]
|
||||
@@ -0,0 +1,590 @@
|
||||
use crate::{
|
||||
configuration, inclusion, initializer, paras,
|
||||
paras_inherent::{self},
|
||||
scheduler, session_info, shared,
|
||||
};
|
||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use primitives::v1::{
|
||||
collator_signature_payload, AvailabilityBitfield, BackedCandidate, CandidateCommitments,
|
||||
CandidateDescriptor, CandidateHash, CollatorId, CommittedCandidateReceipt, CompactStatement,
|
||||
CoreIndex, CoreOccupied, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData,
|
||||
Id as ParaId, InherentData as ParachainsInherentData, InvalidDisputeStatementKind,
|
||||
PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned,
|
||||
ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
generic::Digest,
|
||||
traits::{Header as HeaderT, One, Zero},
|
||||
RuntimeAppPublic,
|
||||
};
|
||||
use sp_std::{collections::btree_map::BTreeMap, convert::TryInto, prelude::Vec, vec};
|
||||
|
||||
/// Grab an account, seeded by a name and index.
|
||||
///
|
||||
/// This is directly from frame-benchmarking. Copy/pasted so we can use it when not compiling with
|
||||
/// "features = runtime-benchmarks".
|
||||
fn account<AccountId: Decode + Default>(name: &'static str, index: u32, seed: u32) -> AccountId {
|
||||
let entropy = (name, index, seed).using_encoded(sp_io::hashing::blake2_256);
|
||||
AccountId::decode(&mut &entropy[..]).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Create a 32 byte slice based on the given number.
|
||||
fn byte32_slice_from(n: u32) -> [u8; 32] {
|
||||
let mut slice = [0u8; 32];
|
||||
slice[31] = (n % (1 << 8)) as u8;
|
||||
slice[30] = ((n >> 8) % (1 << 8)) as u8;
|
||||
slice[29] = ((n >> 16) % (1 << 8)) as u8;
|
||||
slice[28] = ((n >> 24) % (1 << 8)) as u8;
|
||||
|
||||
slice
|
||||
}
|
||||
|
||||
/// Paras inherent `enter` benchmark scenario builder.
|
||||
pub(crate) struct BenchBuilder<T: paras_inherent::Config> {
|
||||
validators: Option<Vec<ValidatorId>>,
|
||||
block_number: T::BlockNumber,
|
||||
session: SessionIndex,
|
||||
target_session: u32,
|
||||
max_validators_per_core: Option<u32>,
|
||||
max_validators: Option<u32>,
|
||||
dispute_statements: BTreeMap<u32, u32>,
|
||||
_phantom: sp_std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
/// Paras inherent `enter` benchmark scenario.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) struct Bench<T: paras_inherent::Config> {
|
||||
pub(crate) data: ParachainsInherentData<T::Header>,
|
||||
pub(crate) _session: u32,
|
||||
pub(crate) _block_number: T::BlockNumber,
|
||||
}
|
||||
|
||||
impl<T: paras_inherent::Config> BenchBuilder<T> {
|
||||
/// Create a new `BenchBuilder` with some opinionated values that should work with the rest
|
||||
/// of the functions in this implementation.
|
||||
pub(crate) fn new() -> Self {
|
||||
BenchBuilder {
|
||||
// Validators should be declared prior to all other setup.
|
||||
validators: None,
|
||||
// Starting block number; we expect it to get incremented on session setup.
|
||||
block_number: Zero::zero(),
|
||||
// Starting session; we expect it to get incremented on session setup.
|
||||
session: SessionIndex::from(0u32),
|
||||
// Session we want the scenario to take place in. We roll to to this session.
|
||||
target_session: 2u32,
|
||||
// Optionally set the max validators per core; otherwise uses the configuration value.
|
||||
max_validators_per_core: None,
|
||||
// Optionally set the max validators; otherwise uses the configuration value.
|
||||
max_validators: None,
|
||||
// Optionally set the number of dispute statements for each candidate,
|
||||
dispute_statements: BTreeMap::new(),
|
||||
_phantom: sp_std::marker::PhantomData::<T>,
|
||||
}
|
||||
}
|
||||
|
||||
/// Mock header.
|
||||
pub(crate) fn header(block_number: T::BlockNumber) -> T::Header {
|
||||
T::Header::new(
|
||||
block_number, // block_number,
|
||||
Default::default(), // extrinsics_root,
|
||||
Default::default(), // storage_root,
|
||||
Default::default(), // parent_hash,
|
||||
Default::default(), // digest,
|
||||
)
|
||||
}
|
||||
|
||||
/// Number of the relay parent block.
|
||||
fn relay_parent_number(&self) -> u32 {
|
||||
(self.block_number - One::one())
|
||||
.try_into()
|
||||
.map_err(|_| ())
|
||||
.expect("self.block_number is u32")
|
||||
}
|
||||
|
||||
/// Maximum number of validators that may be part of a validator group.
|
||||
pub(crate) fn fallback_max_validators() -> u32 {
|
||||
configuration::Pallet::<T>::config().max_validators.unwrap_or(200)
|
||||
}
|
||||
|
||||
/// Maximum number of validators participating in parachains consensus (a.k.a. active validators).
|
||||
fn max_validators(&self) -> u32 {
|
||||
self.max_validators.unwrap_or(Self::fallback_max_validators())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set_max_validators(mut self, n: u32) -> Self {
|
||||
self.max_validators = Some(n);
|
||||
self
|
||||
}
|
||||
|
||||
/// Maximum number of validators per core (a.k.a. max validators per group). This value is used if none is
|
||||
/// explicitly set on the builder.
|
||||
pub(crate) fn fallback_max_validators_per_core() -> u32 {
|
||||
configuration::Pallet::<T>::config().max_validators_per_core.unwrap_or(5)
|
||||
}
|
||||
|
||||
/// Specify a mapping of core index, para id, group index seed to the number of dispute statements for the
|
||||
/// corresponding dispute statement set. Note that if the number of disputes is not specified it fallbacks
|
||||
/// to having a dispute per every validator. Additionally, an entry is not guaranteed to have a dispute - it
|
||||
/// must line up with the cores marked as disputed as defined in `Self::Build`.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set_dispute_statements(mut self, m: BTreeMap<u32, u32>) -> Self {
|
||||
self.dispute_statements = m;
|
||||
self
|
||||
}
|
||||
|
||||
fn max_validators_per_core(&self) -> u32 {
|
||||
self.max_validators_per_core.unwrap_or(Self::fallback_max_validators_per_core())
|
||||
}
|
||||
|
||||
/// Set maximum number of validators per core.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set_max_validators_per_core(mut self, n: u32) -> Self {
|
||||
self.max_validators_per_core = Some(n);
|
||||
self
|
||||
}
|
||||
|
||||
/// Maximum number of cores we expect from this configuration.
|
||||
pub(crate) fn max_cores(&self) -> u32 {
|
||||
self.max_validators() / self.max_validators_per_core()
|
||||
}
|
||||
|
||||
/// Minimum number of validity votes in order for a backed candidate to be included.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn fallback_min_validity_votes() -> u32 {
|
||||
(Self::fallback_max_validators() / 2) + 1
|
||||
}
|
||||
|
||||
fn create_indexes(&self, seed: u32) -> (ParaId, CoreIndex, GroupIndex) {
|
||||
let para_id = ParaId::from(seed);
|
||||
let core_idx = CoreIndex(seed);
|
||||
let group_idx =
|
||||
scheduler::Pallet::<T>::group_assigned_to_core(core_idx, self.block_number).unwrap();
|
||||
|
||||
(para_id, core_idx, group_idx)
|
||||
}
|
||||
|
||||
fn candidate_availability_mock(
|
||||
group_idx: GroupIndex,
|
||||
core_idx: CoreIndex,
|
||||
candidate_hash: CandidateHash,
|
||||
availability_votes: BitVec<BitOrderLsb0, u8>,
|
||||
) -> inclusion::CandidatePendingAvailability<T::Hash, T::BlockNumber> {
|
||||
inclusion::CandidatePendingAvailability::<T::Hash, T::BlockNumber>::new(
|
||||
core_idx, // core
|
||||
candidate_hash, // hash
|
||||
Default::default(), // candidate descriptor
|
||||
availability_votes, // availability votes
|
||||
Default::default(), // backers
|
||||
Zero::zero(), // relay parent
|
||||
One::one(), // relay chain block this was backed in
|
||||
group_idx, // backing group
|
||||
)
|
||||
}
|
||||
|
||||
fn add_availability(
|
||||
para_id: ParaId,
|
||||
core_idx: CoreIndex,
|
||||
group_idx: GroupIndex,
|
||||
availability_votes: BitVec<BitOrderLsb0, u8>,
|
||||
candidate_hash: CandidateHash,
|
||||
) {
|
||||
let candidate_availability = Self::candidate_availability_mock(
|
||||
group_idx,
|
||||
core_idx,
|
||||
candidate_hash,
|
||||
availability_votes,
|
||||
);
|
||||
// NOTE: commitments does not include any data that would lead to heavy code
|
||||
// paths in `enact_candidate`. But enact_candidates does return a weight which will get
|
||||
// taken into account.
|
||||
let commitments = CandidateCommitments::<u32>::default();
|
||||
inclusion::PendingAvailability::<T>::insert(para_id, candidate_availability);
|
||||
inclusion::PendingAvailabilityCommitments::<T>::insert(¶_id, commitments);
|
||||
}
|
||||
|
||||
fn availability_bitvec(concluding: &BTreeMap<u32, u32>, cores: u32) -> AvailabilityBitfield {
|
||||
let mut bitfields = bitvec::bitvec![bitvec::order::Lsb0, u8; 0; 0];
|
||||
for i in 0..cores {
|
||||
if concluding.get(&(i as u32)).is_some() {
|
||||
bitfields.push(true);
|
||||
} else {
|
||||
bitfields.push(false)
|
||||
}
|
||||
}
|
||||
|
||||
bitfields.into()
|
||||
}
|
||||
|
||||
fn run_to_block(to: u32) {
|
||||
let to = to.into();
|
||||
while frame_system::Pallet::<T>::block_number() < to {
|
||||
let b = frame_system::Pallet::<T>::block_number();
|
||||
initializer::Pallet::<T>::on_finalize(b);
|
||||
|
||||
let b = b + One::one();
|
||||
frame_system::Pallet::<T>::set_block_number(b);
|
||||
initializer::Pallet::<T>::on_initialize(b);
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_para_ids(cores: u32) {
|
||||
// make sure parachains exist prior to session change.
|
||||
for i in 0..cores {
|
||||
let para_id = ParaId::from(i as u32);
|
||||
|
||||
paras::Pallet::<T>::schedule_para_initialize(
|
||||
para_id,
|
||||
paras::ParaGenesisArgs {
|
||||
genesis_head: Default::default(),
|
||||
validation_code: Default::default(),
|
||||
parachain: true,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate validator key pairs and account ids.
|
||||
fn generate_validator_pairs(validator_count: u32) -> Vec<(T::AccountId, ValidatorId)> {
|
||||
(0..validator_count)
|
||||
.map(|i| {
|
||||
let public = ValidatorId::generate_pair(None);
|
||||
|
||||
// The account Id is not actually used anywhere, just necessary to fulfill the
|
||||
// expected type of the `validators` param of `test_trigger_on_new_session`.
|
||||
let account: T::AccountId = account("validator", i, i);
|
||||
(account, public)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn signing_context(&self) -> SigningContext<T::Hash> {
|
||||
SigningContext {
|
||||
parent_hash: Self::header(self.block_number.clone()).hash(),
|
||||
session_index: self.session.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn validator_availability_votes_yes(validators: usize) -> BitVec<bitvec::order::Lsb0, u8> {
|
||||
// every validator confirms availability.
|
||||
bitvec::bitvec![bitvec::order::Lsb0, u8; 1; validators as usize]
|
||||
}
|
||||
|
||||
/// Setup session 1 and create `self.validators_map` and `self.validators`.
|
||||
fn setup_session(
|
||||
mut self,
|
||||
target_session: SessionIndex,
|
||||
validators: Vec<(T::AccountId, ValidatorId)>,
|
||||
total_cores: u32,
|
||||
) -> Self {
|
||||
let mut block = 1;
|
||||
for session in 0..=target_session {
|
||||
initializer::Pallet::<T>::test_trigger_on_new_session(
|
||||
false,
|
||||
session,
|
||||
validators.iter().map(|(a, v)| (a, v.clone())),
|
||||
None,
|
||||
);
|
||||
block += 1;
|
||||
Self::run_to_block(block);
|
||||
}
|
||||
|
||||
let block_number = <T as frame_system::Config>::BlockNumber::from(block);
|
||||
let header = Self::header(block_number.clone());
|
||||
|
||||
frame_system::Pallet::<T>::initialize(
|
||||
&header.number(),
|
||||
&header.hash(),
|
||||
&Digest { logs: Vec::new() },
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
assert_eq!(scheduler::ValidatorGroups::<T>::get().len(), total_cores as usize);
|
||||
assert_eq!(<shared::Pallet<T>>::session_index(), target_session);
|
||||
|
||||
// We need to refetch validators since they have been shuffled.
|
||||
let validators_shuffled: Vec<_> = session_info::Pallet::<T>::session_info(target_session)
|
||||
.unwrap()
|
||||
.validators
|
||||
.clone();
|
||||
|
||||
self.validators = Some(validators_shuffled);
|
||||
self.block_number = block_number;
|
||||
self.session = target_session;
|
||||
assert_eq!(paras::Pallet::<T>::parachains().len(), total_cores as usize);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn create_availability_bitfields(
|
||||
&self,
|
||||
concluding_cores: &BTreeMap<u32, u32>,
|
||||
total_cores: u32,
|
||||
) -> Vec<UncheckedSigned<AvailabilityBitfield>> {
|
||||
let validators =
|
||||
self.validators.as_ref().expect("must have some validators prior to calling");
|
||||
|
||||
let availability_bitvec = Self::availability_bitvec(concluding_cores, total_cores);
|
||||
|
||||
let bitfields: Vec<UncheckedSigned<AvailabilityBitfield>> = validators
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, public)| {
|
||||
let unchecked_signed = UncheckedSigned::<AvailabilityBitfield>::benchmark_sign(
|
||||
public,
|
||||
availability_bitvec.clone(),
|
||||
&self.signing_context(),
|
||||
ValidatorIndex(i as u32),
|
||||
);
|
||||
|
||||
unchecked_signed
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (seed, _) in concluding_cores.iter() {
|
||||
// make sure the candidates that are concluding by becoming available are marked as
|
||||
// pending availability.
|
||||
let (para_id, core_idx, group_idx) = self.create_indexes(seed.clone());
|
||||
Self::add_availability(
|
||||
para_id,
|
||||
core_idx,
|
||||
group_idx,
|
||||
Self::validator_availability_votes_yes(validators.len()),
|
||||
CandidateHash(H256::from(byte32_slice_from(seed.clone()))),
|
||||
);
|
||||
}
|
||||
|
||||
bitfields
|
||||
}
|
||||
|
||||
/// Create backed candidates for `cores_with_backed_candidates`. You need these cores to be
|
||||
/// scheduled _within_ paras inherent, which requires marking the available bitfields as fully
|
||||
/// available.
|
||||
/// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number of
|
||||
/// validity votes.
|
||||
fn create_backed_candidates(
|
||||
&self,
|
||||
cores_with_backed_candidates: &BTreeMap<u32, u32>,
|
||||
includes_code_upgrade: Option<u32>,
|
||||
) -> Vec<BackedCandidate<T::Hash>> {
|
||||
let validators =
|
||||
self.validators.as_ref().expect("must have some validators prior to calling");
|
||||
let config = configuration::Pallet::<T>::config();
|
||||
|
||||
cores_with_backed_candidates
|
||||
.iter()
|
||||
.map(|(seed, num_votes)| {
|
||||
assert!(*num_votes <= validators.len() as u32);
|
||||
let (para_id, _core_idx, group_idx) = self.create_indexes(seed.clone());
|
||||
|
||||
// This generates a pair and adds it to the keystore, returning just the public.
|
||||
let collator_public = CollatorId::generate_pair(None);
|
||||
let header = Self::header(self.block_number.clone());
|
||||
let relay_parent = header.hash();
|
||||
let head_data: HeadData = Default::default();
|
||||
let persisted_validation_data_hash = PersistedValidationData::<H256> {
|
||||
parent_head: head_data.clone(),
|
||||
relay_parent_number: self.relay_parent_number(),
|
||||
relay_parent_storage_root: Default::default(),
|
||||
max_pov_size: config.max_pov_size,
|
||||
}
|
||||
.hash();
|
||||
|
||||
let pov_hash = Default::default();
|
||||
// NOTE: we use the default `ValidationCode` when setting it in `setup_para_ids`,
|
||||
// so using the default again here makes sure things line up.
|
||||
let validation_code_hash = ValidationCode::default().hash();
|
||||
let payload = collator_signature_payload(
|
||||
&relay_parent,
|
||||
¶_id,
|
||||
&persisted_validation_data_hash,
|
||||
&pov_hash,
|
||||
&validation_code_hash,
|
||||
);
|
||||
let signature = collator_public.sign(&payload).unwrap();
|
||||
|
||||
// Set the head data so it can be used while validating the signatures on the
|
||||
// candidate receipt.
|
||||
paras::Pallet::<T>::heads_insert(¶_id, head_data.clone());
|
||||
|
||||
let mut past_code_meta = paras::ParaPastCodeMeta::<T::BlockNumber>::default();
|
||||
past_code_meta.note_replacement(0u32.into(), 0u32.into());
|
||||
|
||||
let group_validators = scheduler::Pallet::<T>::group_validators(group_idx).unwrap();
|
||||
|
||||
let candidate = CommittedCandidateReceipt::<T::Hash> {
|
||||
descriptor: CandidateDescriptor::<T::Hash> {
|
||||
para_id,
|
||||
relay_parent,
|
||||
collator: collator_public,
|
||||
persisted_validation_data_hash,
|
||||
pov_hash,
|
||||
erasure_root: Default::default(),
|
||||
signature,
|
||||
para_head: head_data.hash(),
|
||||
validation_code_hash,
|
||||
},
|
||||
commitments: CandidateCommitments::<u32> {
|
||||
upward_messages: Vec::new(),
|
||||
horizontal_messages: Vec::new(),
|
||||
new_validation_code: includes_code_upgrade
|
||||
.map(|v| ValidationCode(vec![0u8; v as usize])),
|
||||
head_data,
|
||||
processed_downward_messages: 0,
|
||||
hrmp_watermark: self.relay_parent_number(),
|
||||
},
|
||||
};
|
||||
|
||||
let candidate_hash = candidate.hash();
|
||||
|
||||
let validity_votes: Vec<_> = group_validators
|
||||
.iter()
|
||||
.take(*num_votes as usize)
|
||||
.map(|val_idx| {
|
||||
let public = validators.get(val_idx.0 as usize).unwrap();
|
||||
let sig = UncheckedSigned::<CompactStatement>::benchmark_sign(
|
||||
public,
|
||||
CompactStatement::Valid(candidate_hash.clone()),
|
||||
&self.signing_context(),
|
||||
*val_idx,
|
||||
)
|
||||
.benchmark_signature();
|
||||
|
||||
ValidityAttestation::Explicit(sig.clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
BackedCandidate::<T::Hash> {
|
||||
candidate,
|
||||
validity_votes,
|
||||
validator_indices: bitvec::bitvec![bitvec::order::Lsb0, u8; 1; group_validators.len()],
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn create_disputes_with_no_spam(
|
||||
&self,
|
||||
start: u32,
|
||||
last: u32,
|
||||
dispute_sessions: &[u32],
|
||||
) -> Vec<DisputeStatementSet> {
|
||||
let validators =
|
||||
self.validators.as_ref().expect("must have some validators prior to calling");
|
||||
|
||||
(start..last)
|
||||
.map(|seed| {
|
||||
let session =
|
||||
dispute_sessions.get(seed as usize).cloned().unwrap_or(self.target_session);
|
||||
|
||||
let (para_id, core_idx, group_idx) = self.create_indexes(seed);
|
||||
let candidate_hash = CandidateHash(H256::from(byte32_slice_from(seed)));
|
||||
|
||||
Self::add_availability(
|
||||
para_id,
|
||||
core_idx,
|
||||
group_idx,
|
||||
Self::validator_availability_votes_yes(validators.len()),
|
||||
candidate_hash,
|
||||
);
|
||||
|
||||
let statements_len =
|
||||
self.dispute_statements.get(&seed).cloned().unwrap_or(validators.len() as u32);
|
||||
let statements = (0..statements_len)
|
||||
.map(|validator_index| {
|
||||
let validator_public = &validators.get(validator_index as usize).unwrap();
|
||||
|
||||
// We need dispute statements on each side. And we don't want a revert log
|
||||
// so we make sure that we have a super majority with valid statements.
|
||||
let dispute_statement = if validator_index % 4 == 0 {
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit)
|
||||
} else {
|
||||
// Note that in the future we could use some availability votes as an
|
||||
// implicit valid kind.
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit)
|
||||
};
|
||||
let data = dispute_statement.payload_data(candidate_hash.clone(), session);
|
||||
let statement_sig = validator_public.sign(&data).unwrap();
|
||||
|
||||
(dispute_statement, ValidatorIndex(validator_index), statement_sig)
|
||||
})
|
||||
.collect();
|
||||
|
||||
DisputeStatementSet { candidate_hash: candidate_hash.clone(), session, statements }
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Build a scenario for testing or benchmarks.
|
||||
///
|
||||
/// - `backed_and_concluding_cores`: Map from core/para id/group index seed to number of
|
||||
/// validity votes.
|
||||
/// - `dispute_sessions`: Session index of for each dispute. Index of slice corresponds to core.
|
||||
/// The length of this must equal total cores used. Seed index for disputes starts at
|
||||
/// `backed_and_concluding_cores.len()`, so `dispute_sessions` needs to be left padded by
|
||||
/// `backed_and_concluding_cores.len()` values which effectively get ignored.
|
||||
/// TODO we should fix this.
|
||||
pub(crate) fn build(
|
||||
self,
|
||||
backed_and_concluding_cores: BTreeMap<u32, u32>,
|
||||
dispute_sessions: &[u32],
|
||||
includes_code_upgrade: Option<u32>,
|
||||
) -> Bench<T> {
|
||||
// Make sure relevant storage is cleared. This is just to get the asserts to work when
|
||||
// running tests because it seems the storage is not cleared in between.
|
||||
inclusion::PendingAvailabilityCommitments::<T>::remove_all(None);
|
||||
inclusion::PendingAvailability::<T>::remove_all(None);
|
||||
|
||||
// We don't allow a core to have both disputes and be marked fully available at this block.
|
||||
let cores = self.max_cores();
|
||||
let used_cores = dispute_sessions.len() as u32;
|
||||
assert!(used_cores <= cores);
|
||||
|
||||
// NOTE: there is an n+2 session delay for these actions to take effect
|
||||
// We are currently in Session 0, so these changes will take effect in Session 2
|
||||
Self::setup_para_ids(used_cores);
|
||||
|
||||
let validator_ids = Self::generate_validator_pairs(self.max_validators());
|
||||
let target_session = SessionIndex::from(self.target_session);
|
||||
let builder = self.setup_session(target_session, validator_ids, used_cores);
|
||||
|
||||
let bitfields =
|
||||
builder.create_availability_bitfields(&backed_and_concluding_cores, used_cores);
|
||||
let backed_candidates =
|
||||
builder.create_backed_candidates(&backed_and_concluding_cores, includes_code_upgrade);
|
||||
|
||||
let disputes = builder.create_disputes_with_no_spam(
|
||||
backed_and_concluding_cores.len() as u32,
|
||||
used_cores,
|
||||
dispute_sessions,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inclusion::PendingAvailabilityCommitments::<T>::iter().count(),
|
||||
used_cores as usize,
|
||||
);
|
||||
assert_eq!(inclusion::PendingAvailability::<T>::iter().count(), used_cores as usize,);
|
||||
|
||||
// Mark all the use cores as occupied. We expect that their are `backed_and_concluding_cores`
|
||||
// that are pending availability and that there are `used_cores - backed_and_concluding_cores `
|
||||
// which are about to be disputed.
|
||||
scheduler::AvailabilityCores::<T>::set(vec![
|
||||
Some(CoreOccupied::Parachain);
|
||||
used_cores as usize
|
||||
]);
|
||||
|
||||
Bench::<T> {
|
||||
data: ParachainsInherentData {
|
||||
bitfields,
|
||||
backed_candidates,
|
||||
disputes,
|
||||
parent_header: Self::header(builder.block_number.clone()),
|
||||
},
|
||||
_session: target_session,
|
||||
_block_number: builder.block_number,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,10 @@ pub trait DisputesHandler<BlockNumber> {
|
||||
included_in: BlockNumber,
|
||||
);
|
||||
|
||||
/// Retrieve the included state of a given candidate in a particular session. If it
|
||||
/// returns `Some`, then we have a local dispute for the given `candidate_hash`.
|
||||
fn included_state(session: SessionIndex, candidate_hash: CandidateHash) -> Option<BlockNumber>;
|
||||
|
||||
/// Whether the given candidate concluded invalid in a dispute with supermajority.
|
||||
fn concluded_invalid(session: SessionIndex, candidate_hash: CandidateHash) -> bool;
|
||||
|
||||
@@ -164,6 +168,13 @@ impl<BlockNumber> DisputesHandler<BlockNumber> for () {
|
||||
) {
|
||||
}
|
||||
|
||||
fn included_state(
|
||||
_session: SessionIndex,
|
||||
_candidate_hash: CandidateHash,
|
||||
) -> Option<BlockNumber> {
|
||||
None
|
||||
}
|
||||
|
||||
fn concluded_invalid(_session: SessionIndex, _candidate_hash: CandidateHash) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -200,6 +211,13 @@ impl<T: Config> DisputesHandler<T::BlockNumber> for pallet::Pallet<T> {
|
||||
pallet::Pallet::<T>::note_included(session, candidate_hash, included_in)
|
||||
}
|
||||
|
||||
fn included_state(
|
||||
session: SessionIndex,
|
||||
candidate_hash: CandidateHash,
|
||||
) -> Option<T::BlockNumber> {
|
||||
pallet::Pallet::<T>::included_state(session, candidate_hash)
|
||||
}
|
||||
|
||||
fn concluded_invalid(session: SessionIndex, candidate_hash: CandidateHash) -> bool {
|
||||
pallet::Pallet::<T>::concluded_invalid(session, candidate_hash)
|
||||
}
|
||||
@@ -738,6 +756,7 @@ impl<T: Config> Pallet<T> {
|
||||
Ok(fresh)
|
||||
}
|
||||
|
||||
/// Removes all duplicate disputes.
|
||||
fn filter_multi_dispute_data(statement_sets: &mut MultiDisputeStatementSet) {
|
||||
frame_support::storage::with_transaction(|| {
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
@@ -1116,6 +1135,13 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn included_state(
|
||||
session: SessionIndex,
|
||||
candidate_hash: CandidateHash,
|
||||
) -> Option<T::BlockNumber> {
|
||||
<Included<T>>::get(session, candidate_hash)
|
||||
}
|
||||
|
||||
pub(crate) fn concluded_invalid(session: SessionIndex, candidate_hash: CandidateHash) -> bool {
|
||||
<Disputes<T>>::get(&session, &candidate_hash).map_or(false, |dispute| {
|
||||
// A dispute that has concluded with supermajority-against.
|
||||
|
||||
@@ -20,23 +20,27 @@
|
||||
//! It is responsible for carrying candidates from being backable to being backed, and then from backed
|
||||
//! to included.
|
||||
|
||||
use crate::{
|
||||
configuration, disputes, dmp, hrmp, paras,
|
||||
paras_inherent::{sanitize_bitfields, DisputedBitfield, VERIFY_SIGS},
|
||||
scheduler::CoreAssignment,
|
||||
shared, ump,
|
||||
};
|
||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||
use frame_support::pallet_prelude::*;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::v1::{
|
||||
AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor,
|
||||
CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash,
|
||||
HeadData, Id as ParaId, SigningContext, UncheckedSignedAvailabilityBitfields, ValidatorIndex,
|
||||
ValidityAttestation,
|
||||
HeadData, Id as ParaId, SigningContext, UncheckedSignedAvailabilityBitfields, ValidatorId,
|
||||
ValidatorIndex, ValidityAttestation,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
traits::{One, Saturating},
|
||||
DispatchError,
|
||||
};
|
||||
use sp_std::prelude::*;
|
||||
|
||||
use crate::{configuration, disputes, dmp, hrmp, paras, scheduler::CoreAssignment, shared, ump};
|
||||
use sp_std::{collections::btree_set::BTreeSet, prelude::*};
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -54,7 +58,7 @@ pub struct AvailabilityBitfieldRecord<N> {
|
||||
|
||||
/// A backed candidate pending availability.
|
||||
#[derive(Encode, Decode, PartialEq, TypeInfo)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
#[cfg_attr(test, derive(Debug, Default))]
|
||||
pub struct CandidatePendingAvailability<H, N> {
|
||||
/// The availability core this is assigned to.
|
||||
core: CoreIndex,
|
||||
@@ -99,6 +103,29 @@ impl<H, N> CandidatePendingAvailability<H, N> {
|
||||
pub(crate) fn candidate_descriptor(&self) -> &CandidateDescriptor<H> {
|
||||
&self.descriptor
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "runtime-benchmarks", test))]
|
||||
pub(crate) fn new(
|
||||
core: CoreIndex,
|
||||
hash: CandidateHash,
|
||||
descriptor: CandidateDescriptor<H>,
|
||||
availability_votes: BitVec<BitOrderLsb0, u8>,
|
||||
backers: BitVec<BitOrderLsb0, u8>,
|
||||
relay_parent_number: N,
|
||||
backed_in_number: N,
|
||||
backing_group: GroupIndex,
|
||||
) -> Self {
|
||||
Self {
|
||||
core,
|
||||
hash,
|
||||
descriptor,
|
||||
availability_votes,
|
||||
backers,
|
||||
relay_parent_number,
|
||||
backed_in_number,
|
||||
backing_group,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A hook for applying validator rewards
|
||||
@@ -212,6 +239,10 @@ pub mod pallet {
|
||||
/// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual para head in the
|
||||
/// commitments.
|
||||
ParaHeadMismatch,
|
||||
/// A bitfield that references a freed core,
|
||||
/// either intentionally or as part of a concluded
|
||||
/// invalid dispute.
|
||||
BitfieldReferencesFreedCore,
|
||||
}
|
||||
|
||||
/// The latest bitfield for each validator, referred to by their index in the validator set.
|
||||
@@ -255,18 +286,18 @@ impl<T: Config> Pallet<T> {
|
||||
for _ in <AvailabilityBitfields<T>>::drain() {}
|
||||
}
|
||||
|
||||
/// Process a set of incoming bitfields.
|
||||
/// Extract the freed cores based on cores that became available.
|
||||
///
|
||||
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available,
|
||||
/// and cores free.
|
||||
pub(crate) fn process_bitfields(
|
||||
/// Updates storage items `PendingAvailability` and `AvailabilityBitfields`.
|
||||
pub(crate) fn update_pending_availability_and_get_freed_cores<F, const ON_CHAIN_USE: bool>(
|
||||
expected_bits: usize,
|
||||
unchecked_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
core_lookup: impl Fn(CoreIndex) -> Option<ParaId>,
|
||||
) -> Result<Vec<(CoreIndex, CandidateHash)>, DispatchError> {
|
||||
let validators = shared::Pallet::<T>::active_validator_keys();
|
||||
let session_index = shared::Pallet::<T>::session_index();
|
||||
|
||||
validators: &[ValidatorId],
|
||||
signed_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
core_lookup: F,
|
||||
) -> Vec<(CoreIndex, CandidateHash)>
|
||||
where
|
||||
F: Fn(CoreIndex) -> Option<ParaId>,
|
||||
{
|
||||
let mut assigned_paras_record = (0..expected_bits)
|
||||
.map(|bit_index| core_lookup(CoreIndex::from(bit_index as u32)))
|
||||
.map(|opt_para_id| {
|
||||
@@ -274,57 +305,15 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// do sanity checks on the bitfields:
|
||||
// 1. no more than one bitfield per validator
|
||||
// 2. bitfields are ascending by validator index.
|
||||
// 3. each bitfield has exactly `expected_bits`
|
||||
// 4. signature is valid.
|
||||
let signed_bitfields = {
|
||||
let mut last_index = None;
|
||||
|
||||
let signing_context = SigningContext {
|
||||
parent_hash: <frame_system::Pallet<T>>::parent_hash(),
|
||||
session_index,
|
||||
};
|
||||
|
||||
let mut signed_bitfields = Vec::with_capacity(unchecked_bitfields.len());
|
||||
|
||||
for unchecked_bitfield in unchecked_bitfields {
|
||||
ensure!(
|
||||
unchecked_bitfield.unchecked_payload().0.len() == expected_bits,
|
||||
Error::<T>::WrongBitfieldSize,
|
||||
);
|
||||
|
||||
ensure!(
|
||||
last_index
|
||||
.map_or(true, |last| last < unchecked_bitfield.unchecked_validator_index()),
|
||||
Error::<T>::BitfieldDuplicateOrUnordered,
|
||||
);
|
||||
|
||||
ensure!(
|
||||
(unchecked_bitfield.unchecked_validator_index().0 as usize) < validators.len(),
|
||||
Error::<T>::ValidatorIndexOutOfBounds,
|
||||
);
|
||||
|
||||
let validator_public =
|
||||
&validators[unchecked_bitfield.unchecked_validator_index().0 as usize];
|
||||
|
||||
last_index = Some(unchecked_bitfield.unchecked_validator_index());
|
||||
|
||||
signed_bitfields.push(
|
||||
unchecked_bitfield
|
||||
.try_into_checked(&signing_context, validator_public)
|
||||
.map_err(|_| Error::<T>::InvalidBitfieldSignature)?,
|
||||
);
|
||||
}
|
||||
signed_bitfields
|
||||
};
|
||||
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
for signed_bitfield in signed_bitfields {
|
||||
for (bit_idx, _) in
|
||||
signed_bitfield.payload().0.iter().enumerate().filter(|(_, is_av)| **is_av)
|
||||
{
|
||||
for (checked_bitfield, validator_index) in
|
||||
signed_bitfields.into_iter().map(|signed_bitfield| {
|
||||
// extracting unchecked data, since it's checked in `fn sanitize_bitfields` already.
|
||||
let validator_idx = signed_bitfield.unchecked_validator_index();
|
||||
let checked_bitfield = signed_bitfield.unchecked_into_payload();
|
||||
(checked_bitfield, validator_idx)
|
||||
}) {
|
||||
for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) {
|
||||
let pending_availability = if let Some((_, pending_availability)) =
|
||||
assigned_paras_record[bit_idx].as_mut()
|
||||
{
|
||||
@@ -339,20 +328,17 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
// defensive check - this is constructed by loading the availability bitfield record,
|
||||
// which is always `Some` if the core is occupied - that's why we're here.
|
||||
let val_idx = signed_bitfield.validator_index().0 as usize;
|
||||
let validator_index = validator_index.0 as usize;
|
||||
if let Some(mut bit) =
|
||||
pending_availability.as_mut().and_then(|candidate_pending_availability| {
|
||||
candidate_pending_availability.availability_votes.get_mut(val_idx)
|
||||
candidate_pending_availability.availability_votes.get_mut(validator_index)
|
||||
}) {
|
||||
*bit = true;
|
||||
}
|
||||
}
|
||||
|
||||
let validator_index = signed_bitfield.validator_index();
|
||||
let record = AvailabilityBitfieldRecord {
|
||||
bitfield: signed_bitfield.into_payload(),
|
||||
submitted_at: now,
|
||||
};
|
||||
let record =
|
||||
AvailabilityBitfieldRecord { bitfield: checked_bitfield, submitted_at: now };
|
||||
|
||||
<AvailabilityBitfields<T>>::insert(&validator_index, record);
|
||||
}
|
||||
@@ -379,18 +365,20 @@ impl<T: Config> Pallet<T> {
|
||||
},
|
||||
};
|
||||
|
||||
let receipt = CommittedCandidateReceipt {
|
||||
descriptor: pending_availability.descriptor,
|
||||
commitments,
|
||||
};
|
||||
Self::enact_candidate(
|
||||
pending_availability.relay_parent_number,
|
||||
receipt,
|
||||
pending_availability.backers,
|
||||
pending_availability.availability_votes,
|
||||
pending_availability.core,
|
||||
pending_availability.backing_group,
|
||||
);
|
||||
if ON_CHAIN_USE {
|
||||
let receipt = CommittedCandidateReceipt {
|
||||
descriptor: pending_availability.descriptor,
|
||||
commitments,
|
||||
};
|
||||
let _weight = Self::enact_candidate(
|
||||
pending_availability.relay_parent_number,
|
||||
receipt,
|
||||
pending_availability.backers,
|
||||
pending_availability.availability_votes,
|
||||
pending_availability.core,
|
||||
pending_availability.backing_group,
|
||||
);
|
||||
}
|
||||
|
||||
freed_cores.push((pending_availability.core, pending_availability.hash));
|
||||
} else {
|
||||
@@ -398,7 +386,40 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(freed_cores)
|
||||
freed_cores
|
||||
}
|
||||
|
||||
/// Process a set of incoming bitfields.
|
||||
///
|
||||
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available,
|
||||
/// and cores free.
|
||||
pub(crate) fn process_bitfields(
|
||||
expected_bits: usize,
|
||||
signed_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
disputed_bitfield: DisputedBitfield,
|
||||
core_lookup: impl Fn(CoreIndex) -> Option<ParaId>,
|
||||
) -> Vec<(CoreIndex, CandidateHash)> {
|
||||
let validators = shared::Pallet::<T>::active_validator_keys();
|
||||
let session_index = shared::Pallet::<T>::session_index();
|
||||
let parent_hash = frame_system::Pallet::<T>::parent_hash();
|
||||
|
||||
let checked_bitfields = sanitize_bitfields::<T, VERIFY_SIGS>(
|
||||
signed_bitfields,
|
||||
disputed_bitfield,
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validators[..],
|
||||
);
|
||||
|
||||
let freed_cores = Self::update_pending_availability_and_get_freed_cores::<_, true>(
|
||||
expected_bits,
|
||||
&validators[..],
|
||||
checked_bitfields,
|
||||
core_lookup,
|
||||
);
|
||||
|
||||
freed_cores
|
||||
}
|
||||
|
||||
/// Process candidates that have been backed. Provide the relay storage root, a set of candidates
|
||||
@@ -563,10 +584,10 @@ impl<T: Config> Pallet<T> {
|
||||
&backed_candidate,
|
||||
&signing_context,
|
||||
group_vals.len(),
|
||||
|idx| {
|
||||
|intra_group_vi| {
|
||||
group_vals
|
||||
.get(idx)
|
||||
.and_then(|i| validators.get(i.0 as usize))
|
||||
.get(intra_group_vi)
|
||||
.and_then(|vi| validators.get(vi.0 as usize))
|
||||
.map(|v| v.clone())
|
||||
},
|
||||
);
|
||||
@@ -822,7 +843,7 @@ impl<T: Config> Pallet<T> {
|
||||
/// Cleans up all paras pending availability that are in the given list of disputed candidates.
|
||||
///
|
||||
/// Returns a vector of cleaned-up core IDs.
|
||||
pub(crate) fn collect_disputed(disputed: Vec<CandidateHash>) -> Vec<CoreIndex> {
|
||||
pub(crate) fn collect_disputed(disputed: &BTreeSet<CandidateHash>) -> Vec<CoreIndex> {
|
||||
let mut cleaned_up_ids = Vec::new();
|
||||
let mut cleaned_up_cores = Vec::new();
|
||||
|
||||
@@ -974,9 +995,8 @@ impl<T: Config> CandidateCheckContext<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::{
|
||||
configuration::HostConfiguration,
|
||||
initializer::SessionChangeNotification,
|
||||
@@ -985,8 +1005,10 @@ mod tests {
|
||||
System, Test,
|
||||
},
|
||||
paras::ParaGenesisArgs,
|
||||
paras_inherent::DisputedBitfield,
|
||||
scheduler::AssignmentKind,
|
||||
};
|
||||
use frame_support::assert_noop;
|
||||
use futures::executor::block_on;
|
||||
use keyring::Sr25519Keyring;
|
||||
use primitives::{
|
||||
@@ -1008,7 +1030,7 @@ mod tests {
|
||||
config
|
||||
}
|
||||
|
||||
fn genesis_config(paras: Vec<(ParaId, bool)>) -> MockGenesisConfig {
|
||||
pub(crate) fn genesis_config(paras: Vec<(ParaId, bool)>) -> MockGenesisConfig {
|
||||
MockGenesisConfig {
|
||||
paras: paras::GenesisConfig {
|
||||
paras: paras
|
||||
@@ -1035,14 +1057,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
enum BackingKind {
|
||||
pub(crate) enum BackingKind {
|
||||
#[allow(unused)]
|
||||
Unanimous,
|
||||
Threshold,
|
||||
Lacking,
|
||||
}
|
||||
|
||||
fn collator_sign_candidate(
|
||||
pub(crate) fn collator_sign_candidate(
|
||||
collator: Sr25519Keyring,
|
||||
candidate: &mut CommittedCandidateReceipt,
|
||||
) {
|
||||
@@ -1060,7 +1082,7 @@ mod tests {
|
||||
assert!(candidate.descriptor().check_collator_signature().is_ok());
|
||||
}
|
||||
|
||||
async fn back_candidate(
|
||||
pub(crate) async fn back_candidate(
|
||||
candidate: CommittedCandidateReceipt,
|
||||
validators: &[Sr25519Keyring],
|
||||
group: &[ValidatorIndex],
|
||||
@@ -1102,11 +1124,6 @@ mod tests {
|
||||
|
||||
let backed = BackedCandidate { candidate, validity_votes, validator_indices };
|
||||
|
||||
let should_pass = match kind {
|
||||
BackingKind::Unanimous | BackingKind::Threshold => true,
|
||||
BackingKind::Lacking => false,
|
||||
};
|
||||
|
||||
let successfully_backed =
|
||||
primitives::v1::check_candidate_backing(&backed, signing_context, group.len(), |i| {
|
||||
Some(validators[group[i].0 as usize].public().into())
|
||||
@@ -1115,16 +1132,15 @@ mod tests {
|
||||
.unwrap_or(0) * 2 >
|
||||
group.len();
|
||||
|
||||
if should_pass {
|
||||
assert!(successfully_backed);
|
||||
} else {
|
||||
assert!(!successfully_backed);
|
||||
}
|
||||
match kind {
|
||||
BackingKind::Unanimous | BackingKind::Threshold => assert!(successfully_backed),
|
||||
BackingKind::Lacking => assert!(!successfully_backed),
|
||||
};
|
||||
|
||||
backed
|
||||
}
|
||||
|
||||
fn run_to_block(
|
||||
pub(crate) fn run_to_block(
|
||||
to: BlockNumber,
|
||||
new_session: impl Fn(BlockNumber) -> Option<SessionChangeNotification<BlockNumber>>,
|
||||
) {
|
||||
@@ -1157,7 +1173,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_bits() -> usize {
|
||||
pub(crate) fn expected_bits() -> usize {
|
||||
Paras::parachains().len() + Configuration::config().parathread_cores as usize
|
||||
}
|
||||
|
||||
@@ -1181,11 +1197,11 @@ mod tests {
|
||||
b
|
||||
}
|
||||
|
||||
fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
|
||||
pub(crate) fn validator_pubkeys(val_ids: &[Sr25519Keyring]) -> Vec<ValidatorId> {
|
||||
val_ids.iter().map(|v| v.public().into()).collect()
|
||||
}
|
||||
|
||||
async fn sign_bitfield(
|
||||
pub(crate) async fn sign_bitfield(
|
||||
keystore: &SyncCryptoStorePtr,
|
||||
key: &Sr25519Keyring,
|
||||
validator_index: ValidatorIndex,
|
||||
@@ -1205,20 +1221,20 @@ mod tests {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestCandidateBuilder {
|
||||
para_id: ParaId,
|
||||
head_data: HeadData,
|
||||
para_head_hash: Option<Hash>,
|
||||
pov_hash: Hash,
|
||||
relay_parent: Hash,
|
||||
persisted_validation_data_hash: Hash,
|
||||
new_validation_code: Option<ValidationCode>,
|
||||
validation_code: ValidationCode,
|
||||
hrmp_watermark: BlockNumber,
|
||||
pub(crate) struct TestCandidateBuilder {
|
||||
pub(crate) para_id: ParaId,
|
||||
pub(crate) head_data: HeadData,
|
||||
pub(crate) para_head_hash: Option<Hash>,
|
||||
pub(crate) pov_hash: Hash,
|
||||
pub(crate) relay_parent: Hash,
|
||||
pub(crate) persisted_validation_data_hash: Hash,
|
||||
pub(crate) new_validation_code: Option<ValidationCode>,
|
||||
pub(crate) validation_code: ValidationCode,
|
||||
pub(crate) hrmp_watermark: BlockNumber,
|
||||
}
|
||||
|
||||
impl TestCandidateBuilder {
|
||||
fn build(self) -> CommittedCandidateReceipt {
|
||||
pub(crate) fn build(self) -> CommittedCandidateReceipt {
|
||||
CommittedCandidateReceipt {
|
||||
descriptor: CandidateDescriptor {
|
||||
para_id: self.para_id,
|
||||
@@ -1239,7 +1255,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_vdata_hash(para_id: ParaId) -> Option<Hash> {
|
||||
pub(crate) fn make_vdata_hash(para_id: ParaId) -> Option<Hash> {
|
||||
let relay_parent_number = <frame_system::Pallet<Test>>::block_number() - 1;
|
||||
let persisted_validation_data = crate::util::make_persisted_validation_data::<Test>(
|
||||
para_id,
|
||||
@@ -1332,7 +1348,7 @@ mod tests {
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
||||
new_test_ext(genesis_config(paras.clone())).execute_with(|| {
|
||||
shared::Pallet::<Test>::set_active_validators_ascending(validator_public.clone());
|
||||
shared::Pallet::<Test>::set_session_index(5);
|
||||
|
||||
@@ -1347,7 +1363,20 @@ mod tests {
|
||||
_ => panic!("out of bounds for testing"),
|
||||
};
|
||||
|
||||
// wrong number of bits.
|
||||
// mark all candidates as pending availability
|
||||
let set_pending_av = || {
|
||||
for (p_id, _) in paras {
|
||||
PendingAvailability::<Test>::insert(
|
||||
p_id,
|
||||
CandidatePendingAvailability {
|
||||
availability_votes: default_availability_votes(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// too many bits in bitfield
|
||||
{
|
||||
let mut bare_bitfield = default_bitfield();
|
||||
bare_bitfield.0.push(false);
|
||||
@@ -1359,15 +1388,18 @@ mod tests {
|
||||
&signing_context,
|
||||
));
|
||||
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
&core_lookup,
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
),
|
||||
vec![]
|
||||
);
|
||||
}
|
||||
|
||||
// wrong number of bits: other way around.
|
||||
// not enough bits
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
let signed = block_on(sign_bitfield(
|
||||
@@ -1378,42 +1410,77 @@ mod tests {
|
||||
&signing_context,
|
||||
));
|
||||
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits() + 1,
|
||||
vec![signed.into()],
|
||||
&core_lookup,
|
||||
)
|
||||
.is_err());
|
||||
assert_eq!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits() + 1,
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
),
|
||||
vec![]
|
||||
);
|
||||
}
|
||||
|
||||
// duplicate.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
set_pending_av.clone()();
|
||||
let back_core_0_bitfield = {
|
||||
let mut b = default_bitfield();
|
||||
b.0.set(0, true);
|
||||
b
|
||||
};
|
||||
let signed: UncheckedSignedAvailabilityBitfield = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
ValidatorIndex(0),
|
||||
bare_bitfield,
|
||||
back_core_0_bitfield,
|
||||
&signing_context,
|
||||
))
|
||||
.into();
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
0
|
||||
);
|
||||
|
||||
// the threshold to free a core is 4 availability votes, but we only expect 1 valid
|
||||
// valid bitfield.
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.clone(), signed],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_err());
|
||||
.is_empty());
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
1
|
||||
);
|
||||
|
||||
// clean up
|
||||
PendingAvailability::<Test>::remove_all(None);
|
||||
}
|
||||
|
||||
// out of order.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
set_pending_av.clone()();
|
||||
let back_core_0_bitfield = {
|
||||
let mut b = default_bitfield();
|
||||
b.0.set(0, true);
|
||||
b
|
||||
};
|
||||
let signed_0 = block_on(sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
ValidatorIndex(0),
|
||||
bare_bitfield.clone(),
|
||||
back_core_0_bitfield.clone(),
|
||||
&signing_context,
|
||||
))
|
||||
.into();
|
||||
@@ -1422,17 +1489,38 @@ mod tests {
|
||||
&keystore,
|
||||
&validators[1],
|
||||
ValidatorIndex(1),
|
||||
bare_bitfield,
|
||||
back_core_0_bitfield,
|
||||
&signing_context,
|
||||
))
|
||||
.into();
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
0
|
||||
);
|
||||
|
||||
// the threshold to free a core is 4 availability votes, but we only expect 1 valid
|
||||
// valid bitfield because `signed_0` will get skipped for being out of order.
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed_1, signed_0],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_err());
|
||||
.is_empty());
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
1
|
||||
);
|
||||
|
||||
PendingAvailability::<Test>::remove_all(None);
|
||||
}
|
||||
|
||||
// non-pending bit set.
|
||||
@@ -1446,17 +1534,17 @@ mod tests {
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
));
|
||||
assert_eq!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
&core_lookup,
|
||||
),
|
||||
Ok(vec![])
|
||||
);
|
||||
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_empty());
|
||||
}
|
||||
|
||||
// empty bitfield signed: always OK, but kind of useless.
|
||||
// empty bitfield signed: always ok, but kind of useless.
|
||||
{
|
||||
let bare_bitfield = default_bitfield();
|
||||
let signed = block_on(sign_bitfield(
|
||||
@@ -1470,9 +1558,10 @@ mod tests {
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_ok());
|
||||
.is_empty());
|
||||
}
|
||||
|
||||
// bitfield signed with pending bit signed.
|
||||
@@ -1512,9 +1601,10 @@ mod tests {
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_ok());
|
||||
.is_empty());
|
||||
|
||||
<PendingAvailability<Test>>::remove(chain_a);
|
||||
PendingAvailabilityCommitments::<Test>::remove(chain_a);
|
||||
@@ -1551,14 +1641,13 @@ mod tests {
|
||||
));
|
||||
|
||||
// no core is freed
|
||||
assert_eq!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
&core_lookup,
|
||||
),
|
||||
Ok(vec![]),
|
||||
);
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
)
|
||||
.is_empty());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1614,7 +1703,7 @@ mod tests {
|
||||
CandidatePendingAvailability {
|
||||
core: CoreIndex::from(0),
|
||||
hash: candidate_a.hash(),
|
||||
descriptor: candidate_a.descriptor,
|
||||
descriptor: candidate_a.clone().descriptor,
|
||||
availability_votes: default_availability_votes(),
|
||||
relay_parent_number: 0,
|
||||
backed_in_number: 0,
|
||||
@@ -1622,7 +1711,10 @@ mod tests {
|
||||
backing_group: GroupIndex::from(0),
|
||||
},
|
||||
);
|
||||
PendingAvailabilityCommitments::<Test>::insert(chain_a, candidate_a.commitments);
|
||||
PendingAvailabilityCommitments::<Test>::insert(
|
||||
chain_a,
|
||||
candidate_a.clone().commitments,
|
||||
);
|
||||
|
||||
let candidate_b = TestCandidateBuilder {
|
||||
para_id: chain_b,
|
||||
@@ -1694,12 +1786,16 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
signed_bitfields,
|
||||
&core_lookup,
|
||||
)
|
||||
.is_ok());
|
||||
// only chain A's core is freed.
|
||||
assert_eq!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
signed_bitfields,
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
),
|
||||
vec![(CoreIndex(0), candidate_a.hash())]
|
||||
);
|
||||
|
||||
// chain A had 4 signing off, which is >= threshold.
|
||||
// chain B has 3 signing off, which is < threshold.
|
||||
@@ -1833,14 +1929,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_b_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::UnscheduledCandidate.into()),
|
||||
Error::<Test>::UnscheduledCandidate
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1888,14 +1984,14 @@ mod tests {
|
||||
));
|
||||
|
||||
// out-of-order manifests as unscheduled.
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed_b, backed_a],
|
||||
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::UnscheduledCandidate.into()),
|
||||
Error::<Test>::UnscheduledCandidate
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1921,14 +2017,14 @@ mod tests {
|
||||
BackingKind::Lacking,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::InsufficientBacking.into()),
|
||||
Error::<Test>::InsufficientBacking
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1956,14 +2052,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::CandidateNotInParentContext.into()),
|
||||
Error::<Test>::CandidateNotInParentContext
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1991,7 +2087,7 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
@@ -2002,7 +2098,7 @@ mod tests {
|
||||
],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::WrongCollator.into()),
|
||||
Error::<Test>::WrongCollator,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2033,14 +2129,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![thread_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::NotCollatorSigned.into()),
|
||||
Error::<Test>::NotCollatorSigned
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2083,14 +2179,14 @@ mod tests {
|
||||
);
|
||||
<PendingAvailabilityCommitments<Test>>::insert(&chain_a, candidate.commitments);
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::CandidateScheduledBeforeParaFree.into()),
|
||||
Error::<Test>::CandidateScheduledBeforeParaFree
|
||||
);
|
||||
|
||||
<PendingAvailability<Test>>::remove(&chain_a);
|
||||
@@ -2126,14 +2222,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::CandidateScheduledBeforeParaFree.into()),
|
||||
Error::<Test>::CandidateScheduledBeforeParaFree
|
||||
);
|
||||
|
||||
<PendingAvailabilityCommitments<Test>>::remove(&chain_a);
|
||||
@@ -2177,14 +2273,14 @@ mod tests {
|
||||
assert_eq!(Paras::last_code_upgrade(chain_a, true), Some(expected_at));
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::PrematureCodeUpgrade.into()),
|
||||
Error::<Test>::PrematureCodeUpgrade
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2246,14 +2342,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::InvalidValidationCodeHash.into()),
|
||||
Error::<Test>::InvalidValidationCodeHash
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2281,14 +2377,14 @@ mod tests {
|
||||
BackingKind::Threshold,
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
assert_noop!(
|
||||
ParaInclusion::process_candidates(
|
||||
Default::default(),
|
||||
vec![backed],
|
||||
vec![chain_a_assignment.clone()],
|
||||
&group_validators,
|
||||
),
|
||||
Err(Error::<Test>::ParaHeadMismatch.into()),
|
||||
Error::<Test>::ParaHeadMismatch
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -294,7 +294,7 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
// Allow to trigger on_new_session in tests, this is needed as long as pallet_session is not
|
||||
// implemented in mock.
|
||||
#[cfg(test)]
|
||||
#[cfg(any(test, feature = "runtime-benchmarks"))]
|
||||
pub(crate) fn test_trigger_on_new_session<'a, I: 'a>(
|
||||
changed: bool,
|
||||
session_index: SessionIndex,
|
||||
|
||||
@@ -42,6 +42,8 @@ pub mod runtime_api_impl;
|
||||
|
||||
mod util;
|
||||
|
||||
#[cfg(any(feature = "runtime-benchmarks", test))]
|
||||
mod builder;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
|
||||
|
||||
@@ -22,15 +22,24 @@ use crate::{
|
||||
ump::{self, MessageId, UmpSink},
|
||||
ParaId,
|
||||
};
|
||||
use frame_support::{parameter_types, traits::GenesisBuild, weights::Weight};
|
||||
|
||||
use frame_support::{
|
||||
parameter_types,
|
||||
traits::{GenesisBuild, KeyOwnerProofSystem},
|
||||
weights::Weight,
|
||||
};
|
||||
use frame_support_test::TestRandomness;
|
||||
use parity_scale_codec::Decode;
|
||||
use primitives::v1::{
|
||||
AuthorityDiscoveryId, Balance, BlockNumber, Header, SessionIndex, UpwardMessage, ValidatorIndex,
|
||||
AuthorityDiscoveryId, Balance, BlockNumber, Header, Moment, SessionIndex, UpwardMessage,
|
||||
ValidatorIndex,
|
||||
};
|
||||
use sp_core::H256;
|
||||
use sp_io::TestExternalities;
|
||||
use sp_runtime::traits::{BlakeTwo256, IdentityLookup};
|
||||
use sp_runtime::{
|
||||
traits::{BlakeTwo256, IdentityLookup},
|
||||
KeyTypeId,
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
|
||||
@@ -56,6 +65,7 @@ frame_support::construct_runtime!(
|
||||
Hrmp: hrmp::{Pallet, Call, Storage, Event<T>},
|
||||
SessionInfo: session_info::{Pallet, Storage},
|
||||
Disputes: disputes::{Pallet, Storage, Event<T>},
|
||||
Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -109,6 +119,52 @@ impl pallet_balances::Config for Test {
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const EpochDuration: u64 = 10;
|
||||
pub const ExpectedBlockTime: Moment = 6_000;
|
||||
pub const ReportLongevity: u64 = 10;
|
||||
pub const MaxAuthorities: u32 = 100_000;
|
||||
}
|
||||
|
||||
impl pallet_babe::Config for Test {
|
||||
type EpochDuration = EpochDuration;
|
||||
type ExpectedBlockTime = ExpectedBlockTime;
|
||||
|
||||
// session module is the trigger
|
||||
type EpochChangeTrigger = pallet_babe::ExternalTrigger;
|
||||
|
||||
type DisabledValidators = ();
|
||||
|
||||
type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
|
||||
KeyTypeId,
|
||||
pallet_babe::AuthorityId,
|
||||
)>>::Proof;
|
||||
|
||||
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
|
||||
KeyTypeId,
|
||||
pallet_babe::AuthorityId,
|
||||
)>>::IdentificationTuple;
|
||||
|
||||
type KeyOwnerProofSystem = ();
|
||||
|
||||
type HandleEquivocation = ();
|
||||
|
||||
type WeightInfo = ();
|
||||
|
||||
type MaxAuthorities = MaxAuthorities;
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub const MinimumPeriod: Moment = 6_000 / 2;
|
||||
}
|
||||
|
||||
impl pallet_timestamp::Config for Test {
|
||||
type Moment = Moment;
|
||||
type OnTimestampSet = ();
|
||||
type MinimumPeriod = MinimumPeriod;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
impl crate::initializer::Config for Test {
|
||||
type Randomness = TestRandomness<Self>;
|
||||
type ForceOrigin = frame_system::EnsureRoot<u64>;
|
||||
@@ -203,7 +259,9 @@ impl crate::inclusion::Config for Test {
|
||||
type RewardValidators = TestRewardValidators;
|
||||
}
|
||||
|
||||
impl crate::paras_inherent::Config for Test {}
|
||||
impl crate::paras_inherent::Config for Test {
|
||||
type WeightInfo = crate::paras_inherent::TestWeightInfo;
|
||||
}
|
||||
|
||||
impl crate::session_info::Config for Test {}
|
||||
|
||||
@@ -299,6 +357,8 @@ impl inclusion::RewardValidators for TestRewardValidators {
|
||||
|
||||
/// Create a new set of test externalities.
|
||||
pub fn new_test_ext(state: MockGenesisConfig) -> TestExternalities {
|
||||
use sp_keystore::{testing::KeyStore, KeystoreExt, SyncCryptoStorePtr};
|
||||
use sp_std::sync::Arc;
|
||||
BACKING_REWARDS.with(|r| r.borrow_mut().clear());
|
||||
AVAILABILITY_REWARDS.with(|r| r.borrow_mut().clear());
|
||||
|
||||
@@ -306,7 +366,10 @@ pub fn new_test_ext(state: MockGenesisConfig) -> TestExternalities {
|
||||
state.configuration.assimilate_storage(&mut t).unwrap();
|
||||
GenesisBuild::<Test>::assimilate_storage(&state.paras, &mut t).unwrap();
|
||||
|
||||
t.into()
|
||||
let mut ext: TestExternalities = t.into();
|
||||
ext.register_extension(KeystoreExt(Arc::new(KeyStore::new()) as SyncCryptoStorePtr));
|
||||
|
||||
ext
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -42,7 +42,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub use crate::Origin as ParachainOrigin;
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
mod benchmarking;
|
||||
pub(crate) mod benchmarking;
|
||||
|
||||
pub use pallet::*;
|
||||
|
||||
@@ -160,7 +160,7 @@ impl ParaLifecycle {
|
||||
|
||||
impl<N: Ord + Copy + PartialEq> ParaPastCodeMeta<N> {
|
||||
// note a replacement has occurred at a given block number.
|
||||
fn note_replacement(&mut self, expected_at: N, activated_at: N) {
|
||||
pub(crate) fn note_replacement(&mut self, expected_at: N, activated_at: N) {
|
||||
self.upgrade_times.push(ReplacementTimes { expected_at, activated_at })
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ pub mod pallet {
|
||||
/// All parachains. Ordered ascending by `ParaId`. Parathreads are not included.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn parachains)]
|
||||
pub(super) type Parachains<T: Config> = StorageValue<_, Vec<ParaId>, ValueQuery>;
|
||||
pub(crate) type Parachains<T: Config> = StorageValue<_, Vec<ParaId>, ValueQuery>;
|
||||
|
||||
/// The current lifecycle of a all known Para IDs.
|
||||
#[pallet::storage]
|
||||
@@ -1168,6 +1168,11 @@ impl<T: Config> Pallet<T> {
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "runtime-benchmarks", test))]
|
||||
pub fn heads_insert(para_id: &ParaId, head_data: HeadData) {
|
||||
Heads::<T>::insert(para_id, head_data);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -47,7 +47,7 @@ fn generate_disordered_pruning<T: Config>() {
|
||||
<Pallet<T> as Store>::PastCodePruning::put(needs_pruning);
|
||||
}
|
||||
|
||||
fn generate_disordered_upgrades<T: Config>() {
|
||||
pub(crate) fn generate_disordered_upgrades<T: Config>() {
|
||||
let mut upgrades = Vec::new();
|
||||
let mut cooldowns = Vec::new();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
// Copyright 2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
use crate::{inclusion, ParaId};
|
||||
use frame_benchmarking::{benchmarks, impl_benchmark_test_suite};
|
||||
use frame_system::RawOrigin;
|
||||
use sp_std::collections::btree_map::BTreeMap;
|
||||
|
||||
use crate::builder::BenchBuilder;
|
||||
|
||||
benchmarks! {
|
||||
// Variant over `v`, the number of dispute statements in a dispute statement set. This gives the
|
||||
// weight of a single dispute statement set.
|
||||
enter_variable_disputes {
|
||||
let v in 10..BenchBuilder::<T>::fallback_max_validators();
|
||||
|
||||
let scenario = BenchBuilder::<T>::new()
|
||||
.build(Default::default(), &[2], None);
|
||||
|
||||
let mut benchmark = scenario.data.clone();
|
||||
let dispute = benchmark.disputes.pop().unwrap();
|
||||
|
||||
benchmark.bitfields.clear();
|
||||
benchmark.backed_candidates.clear();
|
||||
benchmark.disputes.clear();
|
||||
|
||||
benchmark.disputes.push(dispute);
|
||||
benchmark.disputes.get_mut(0).unwrap().statements.drain(v as usize..);
|
||||
}: enter(RawOrigin::None, benchmark)
|
||||
verify {
|
||||
// Assert that the block was not discarded
|
||||
assert!(Included::<T>::get().is_some());
|
||||
// Assert that there are on-chain votes that got scraped
|
||||
let onchain_votes = OnChainVotes::<T>::get();
|
||||
assert!(onchain_votes.is_some());
|
||||
let vote = onchain_votes.unwrap();
|
||||
// Ensure that the votes are for the correct session
|
||||
assert_eq!(vote.session, scenario._session);
|
||||
}
|
||||
|
||||
// The weight of one bitfield.
|
||||
enter_bitfields {
|
||||
let cores_with_backed: BTreeMap<_, _>
|
||||
= vec![(0, BenchBuilder::<T>::fallback_max_validators())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let scenario = BenchBuilder::<T>::new()
|
||||
.build(cores_with_backed, &[1], None);
|
||||
|
||||
let mut benchmark = scenario.data.clone();
|
||||
let bitfield = benchmark.bitfields.pop().unwrap();
|
||||
|
||||
benchmark.bitfields.clear();
|
||||
benchmark.backed_candidates.clear();
|
||||
benchmark.disputes.clear();
|
||||
|
||||
benchmark.bitfields.push(bitfield);
|
||||
}: enter(RawOrigin::None, benchmark)
|
||||
verify {
|
||||
// Assert that the block was not discarded
|
||||
assert!(Included::<T>::get().is_some());
|
||||
// Assert that there are on-chain votes that got scraped
|
||||
let onchain_votes = OnChainVotes::<T>::get();
|
||||
assert!(onchain_votes.is_some());
|
||||
let vote = onchain_votes.unwrap();
|
||||
// Ensure that the votes are for the correct session
|
||||
assert_eq!(vote.session, scenario._session);
|
||||
}
|
||||
|
||||
// Variant over `v`, the amount of validity votes for a backed candidate. This gives the weight
|
||||
// of a single backed candidate.
|
||||
enter_backed_candidates_variable {
|
||||
// NOTE: the starting value must be over half of `max_validators` so the backed candidate is
|
||||
// not rejected.
|
||||
let v
|
||||
in (BenchBuilder::<T>::fallback_min_validity_votes())
|
||||
..BenchBuilder::<T>::fallback_max_validators();
|
||||
|
||||
let cores_with_backed: BTreeMap<_, _>
|
||||
= vec![(0, v)] // The backed candidate will have `v` validity votes.
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let scenario = BenchBuilder::<T>::new()
|
||||
.build(cores_with_backed.clone(), &[1], None);
|
||||
|
||||
let mut benchmark = scenario.data.clone();
|
||||
|
||||
// There is 1 backed,
|
||||
assert_eq!(benchmark.backed_candidates.len(), 1);
|
||||
// with `v` validity votes.
|
||||
assert_eq!(benchmark.backed_candidates.get(0).unwrap().validity_votes.len(), v as usize);
|
||||
|
||||
benchmark.bitfields.clear();
|
||||
benchmark.disputes.clear();
|
||||
}: enter(RawOrigin::None, benchmark)
|
||||
verify {
|
||||
let max_validators_per_core = BenchBuilder::<T>::fallback_max_validators_per_core();
|
||||
// Assert that the block was not discarded
|
||||
assert!(Included::<T>::get().is_some());
|
||||
// Assert that there are on-chain votes that got scraped
|
||||
let onchain_votes = OnChainVotes::<T>::get();
|
||||
assert!(onchain_votes.is_some());
|
||||
let vote = onchain_votes.unwrap();
|
||||
// Ensure that the votes are for the correct session
|
||||
assert_eq!(vote.session, scenario._session);
|
||||
// Ensure that there are an expected number of candidates
|
||||
let header = BenchBuilder::<T>::header(scenario._block_number.clone());
|
||||
// Traverse candidates and assert descriptors are as expected
|
||||
for (para_id, backing_validators) in vote.backing_validators_per_candidate.iter().enumerate() {
|
||||
let descriptor = backing_validators.0.descriptor();
|
||||
assert_eq!(ParaId::from(para_id), descriptor.para_id);
|
||||
assert_eq!(header.hash(), descriptor.relay_parent);
|
||||
assert_eq!(backing_validators.1.len(), v as usize);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
inclusion::PendingAvailabilityCommitments::<T>::iter().count(),
|
||||
cores_with_backed.len()
|
||||
);
|
||||
assert_eq!(
|
||||
inclusion::PendingAvailability::<T>::iter().count(),
|
||||
cores_with_backed.len()
|
||||
);
|
||||
}
|
||||
|
||||
enter_backed_candidate_code_upgrade {
|
||||
// For now we always assume worst case code size. In the future we could vary over this.
|
||||
let v = crate::configuration::Pallet::<T>::config().max_code_size;
|
||||
|
||||
let cores_with_backed: BTreeMap<_, _>
|
||||
= vec![(0, BenchBuilder::<T>::fallback_min_validity_votes())]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let scenario = BenchBuilder::<T>::new()
|
||||
.build(cores_with_backed.clone(), &[1], Some(v));
|
||||
|
||||
let mut benchmark = scenario.data.clone();
|
||||
|
||||
// There is 1 backed
|
||||
assert_eq!(benchmark.backed_candidates.len(), 1);
|
||||
assert_eq!(
|
||||
benchmark.backed_candidates.get(0).unwrap().validity_votes.len() as u32,
|
||||
BenchBuilder::<T>::fallback_min_validity_votes()
|
||||
);
|
||||
|
||||
benchmark.bitfields.clear();
|
||||
benchmark.disputes.clear();
|
||||
crate::paras::benchmarking::generate_disordered_upgrades::<T>();
|
||||
}: enter(RawOrigin::None, benchmark)
|
||||
verify {
|
||||
let max_validators_per_core = BenchBuilder::<T>::fallback_max_validators_per_core();
|
||||
// Assert that the block was not discarded
|
||||
assert!(Included::<T>::get().is_some());
|
||||
// Assert that there are on-chain votes that got scraped
|
||||
let onchain_votes = OnChainVotes::<T>::get();
|
||||
assert!(onchain_votes.is_some());
|
||||
let vote = onchain_votes.unwrap();
|
||||
// Ensure that the votes are for the correct session
|
||||
assert_eq!(vote.session, scenario._session);
|
||||
// Ensure that there are an expected number of candidates
|
||||
let header = BenchBuilder::<T>::header(scenario._block_number.clone());
|
||||
// Traverse candidates and assert descriptors are as expected
|
||||
for (para_id, backing_validators)
|
||||
in vote.backing_validators_per_candidate.iter().enumerate() {
|
||||
let descriptor = backing_validators.0.descriptor();
|
||||
assert_eq!(ParaId::from(para_id), descriptor.para_id);
|
||||
assert_eq!(header.hash(), descriptor.relay_parent);
|
||||
assert_eq!(
|
||||
backing_validators.1.len() as u32,
|
||||
BenchBuilder::<T>::fallback_min_validity_votes()
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
inclusion::PendingAvailabilityCommitments::<T>::iter().count(),
|
||||
cores_with_backed.len()
|
||||
);
|
||||
assert_eq!(
|
||||
inclusion::PendingAvailability::<T>::iter().count(),
|
||||
cores_with_backed.len()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::new_test_ext(Default::default()),
|
||||
crate::mock::Test
|
||||
);
|
||||
@@ -90,6 +90,7 @@ impl ParathreadClaimQueue {
|
||||
}
|
||||
|
||||
/// Reasons a core might be freed
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum FreedReason {
|
||||
/// The core's work concluded and the parablock assigned to it is considered available.
|
||||
Concluded,
|
||||
|
||||
@@ -192,6 +192,7 @@ runtime-benchmarks = [
|
||||
"frame-system-benchmarking",
|
||||
"hex-literal",
|
||||
"frame-election-provider-support/runtime-benchmarks",
|
||||
"runtime-parachains/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
@@ -1182,7 +1182,9 @@ impl parachains_hrmp::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
}
|
||||
|
||||
impl parachains_paras_inherent::Config for Runtime {}
|
||||
impl parachains_paras_inherent::Config for Runtime {
|
||||
type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
impl parachains_scheduler::Config for Runtime {}
|
||||
|
||||
@@ -1755,6 +1757,7 @@ sp_api::impl_runtime_apis! {
|
||||
list_benchmark!(list, extra, runtime_parachains::configuration, Configuration);
|
||||
list_benchmark!(list, extra, runtime_parachains::initializer, Initializer);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras, Paras);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras_inherent, ParaInherent);
|
||||
// Substrate
|
||||
list_benchmark!(list, extra, pallet_bags_list, BagsList);
|
||||
list_benchmark!(list, extra, pallet_balances, Balances);
|
||||
@@ -1831,6 +1834,7 @@ sp_api::impl_runtime_apis! {
|
||||
add_benchmark!(params, batches, runtime_parachains::configuration, Configuration);
|
||||
add_benchmark!(params, batches, runtime_parachains::initializer, Initializer);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras, Paras);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras_inherent, ParaInherent);
|
||||
// Substrate
|
||||
add_benchmark!(params, batches, pallet_bags_list, BagsList);
|
||||
add_benchmark!(params, batches, pallet_balances, Balances);
|
||||
@@ -1880,7 +1884,6 @@ mod test_fees {
|
||||
MaxNominatorRewardedPerValidator::get(),
|
||||
) as f64;
|
||||
let block_weight = BlockWeights::get().max_block as f64;
|
||||
|
||||
println!(
|
||||
"a full payout takes {:.2} of the block weight [{} / {}]",
|
||||
payout_weight / block_weight,
|
||||
|
||||
@@ -46,3 +46,4 @@ pub mod runtime_common_slots;
|
||||
pub mod runtime_parachains_configuration;
|
||||
pub mod runtime_parachains_initializer;
|
||||
pub mod runtime_parachains_paras;
|
||||
pub mod runtime_parachains_paras_inherent;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2021-11-14, STEPS: `50`, REPEAT: 3, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// target/release/polkadot
|
||||
// benchmark
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=3
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs
|
||||
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `runtime_parachains::paras_inherent`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_variable_disputes(v: u32, ) -> Weight {
|
||||
(316_331_000 as Weight)
|
||||
// Standard Error: 112_000
|
||||
.saturating_add((325_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_bitfields() -> Weight {
|
||||
(352_749_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(15 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidates_variable(v: u32, ) -> Weight {
|
||||
(88_047_000 as Weight)
|
||||
// Standard Error: 3_275_000
|
||||
.saturating_add((68_499_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidate_code_upgrade() -> Weight {
|
||||
(53_728_168_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,8 @@ runtime-benchmarks = [
|
||||
"xcm-builder/runtime-benchmarks",
|
||||
"pallet-multisig/runtime-benchmarks",
|
||||
"frame-benchmarking",
|
||||
"hex-literal"
|
||||
"hex-literal",
|
||||
"runtime-parachains/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
@@ -750,7 +750,9 @@ impl parachains_hrmp::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
}
|
||||
|
||||
impl parachains_paras_inherent::Config for Runtime {}
|
||||
impl parachains_paras_inherent::Config for Runtime {
|
||||
type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
impl parachains_scheduler::Config for Runtime {}
|
||||
|
||||
@@ -1616,6 +1618,7 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
list_benchmark!(list, extra, runtime_parachains::configuration, Configuration);
|
||||
list_benchmark!(list, extra, runtime_parachains::disputes, ParasDisputes);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras_inherent, ParaInherent);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras, Paras);
|
||||
|
||||
let storage_info = AllPalletsWithSystem::storage_info();
|
||||
@@ -1648,6 +1651,7 @@ sp_api::impl_runtime_apis! {
|
||||
|
||||
add_benchmark!(params, batches, runtime_parachains::configuration, Configuration);
|
||||
add_benchmark!(params, batches, runtime_parachains::disputes, ParasDisputes);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras_inherent, ParaInherent);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras, Paras);
|
||||
|
||||
if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
|
||||
|
||||
@@ -18,3 +18,4 @@
|
||||
pub mod runtime_parachains_configuration;
|
||||
pub mod runtime_parachains_disputes;
|
||||
pub mod runtime_parachains_paras;
|
||||
pub mod runtime_parachains_paras_inherent;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2021-11-14, STEPS: `50`, REPEAT: 3, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// target/release/polkadot
|
||||
// benchmark
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=3
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs
|
||||
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `runtime_parachains::paras_inherent`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_variable_disputes(v: u32, ) -> Weight {
|
||||
(316_331_000 as Weight)
|
||||
// Standard Error: 112_000
|
||||
.saturating_add((325_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_bitfields() -> Weight {
|
||||
(352_749_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(15 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidates_variable(v: u32, ) -> Weight {
|
||||
(88_047_000 as Weight)
|
||||
// Standard Error: 3_275_000
|
||||
.saturating_add((68_499_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidate_code_upgrade() -> Weight {
|
||||
(53_728_168_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
}
|
||||
@@ -476,7 +476,9 @@ impl parachains_disputes::Config for Runtime {
|
||||
type WeightInfo = parachains_disputes::TestWeightInfo;
|
||||
}
|
||||
|
||||
impl parachains_paras_inherent::Config for Runtime {}
|
||||
impl parachains_paras_inherent::Config for Runtime {
|
||||
type WeightInfo = parachains_paras_inherent::TestWeightInfo;
|
||||
}
|
||||
|
||||
impl parachains_initializer::Config for Runtime {
|
||||
type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
|
||||
|
||||
@@ -206,6 +206,7 @@ runtime-benchmarks = [
|
||||
"pallet-xcm-benchmarks",
|
||||
"frame-election-provider-support/runtime-benchmarks",
|
||||
"pallet-bags-list/runtime-benchmarks",
|
||||
"runtime-parachains/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"frame-executive/try-runtime",
|
||||
|
||||
@@ -846,7 +846,9 @@ impl parachains_hrmp::Config for Runtime {
|
||||
type Currency = Balances;
|
||||
}
|
||||
|
||||
impl parachains_paras_inherent::Config for Runtime {}
|
||||
impl parachains_paras_inherent::Config for Runtime {
|
||||
type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo<Runtime>;
|
||||
}
|
||||
|
||||
impl parachains_scheduler::Config for Runtime {}
|
||||
|
||||
@@ -1482,6 +1484,7 @@ sp_api::impl_runtime_apis! {
|
||||
list_benchmark!(list, extra, runtime_common::slots, Slots);
|
||||
list_benchmark!(list, extra, runtime_parachains::configuration, Configuration);
|
||||
list_benchmark!(list, extra, runtime_parachains::initializer, Initializer);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras_inherent, ParaInherent);
|
||||
list_benchmark!(list, extra, runtime_parachains::paras, Paras);
|
||||
|
||||
// Substrate
|
||||
@@ -1595,6 +1598,7 @@ sp_api::impl_runtime_apis! {
|
||||
add_benchmark!(params, batches, runtime_parachains::configuration, Configuration);
|
||||
add_benchmark!(params, batches, runtime_parachains::initializer, Initializer);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras, Paras);
|
||||
add_benchmark!(params, batches, runtime_parachains::paras_inherent, ParaInherent);
|
||||
|
||||
// Substrate
|
||||
add_benchmark!(params, batches, pallet_bags_list, BagsList);
|
||||
|
||||
@@ -37,4 +37,5 @@ pub mod runtime_common_slots;
|
||||
pub mod runtime_parachains_configuration;
|
||||
pub mod runtime_parachains_initializer;
|
||||
pub mod runtime_parachains_paras;
|
||||
pub mod runtime_parachains_paras_inherent;
|
||||
pub mod xcm;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
// Copyright 2017-2021 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Polkadot.
|
||||
|
||||
// Polkadot is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Polkadot is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2021-11-14, STEPS: `50`, REPEAT: 3, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 128
|
||||
|
||||
// Executed Command:
|
||||
// target/release/polkadot
|
||||
// benchmark
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=3
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs
|
||||
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use frame_support::{traits::Get, weights::Weight};
|
||||
use sp_std::marker::PhantomData;
|
||||
|
||||
/// Weight functions for `runtime_parachains::paras_inherent`.
|
||||
pub struct WeightInfo<T>(PhantomData<T>);
|
||||
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_variable_disputes(v: u32, ) -> Weight {
|
||||
(316_331_000 as Weight)
|
||||
// Standard Error: 112_000
|
||||
.saturating_add((325_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_bitfields() -> Weight {
|
||||
(352_749_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(23 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(15 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidates_variable(v: u32, ) -> Weight {
|
||||
(88_047_000 as Weight)
|
||||
// Standard Error: 3_275_000
|
||||
.saturating_add((68_499_000 as Weight).saturating_mul(v as Weight))
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
// Storage: ParaInherent Included (r:1 w:1)
|
||||
// Storage: System ParentHash (r:1 w:0)
|
||||
// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
// Storage: Paras Parachains (r:1 w:0)
|
||||
// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
// Storage: Session Validators (r:1 w:0)
|
||||
// Storage: ParasShared ActiveValidatorIndices (r:1 w:0)
|
||||
// Storage: Staking ActiveEra (r:1 w:0)
|
||||
// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
// Storage: Dmp DownwardMessageQueues (r:1 w:1)
|
||||
// Storage: Hrmp HrmpChannelDigests (r:1 w:1)
|
||||
// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
// Storage: ParaScheduler Scheduled (r:1 w:1)
|
||||
// Storage: ParaScheduler ValidatorGroups (r:1 w:0)
|
||||
// Storage: Paras PastCodeMeta (r:1 w:0)
|
||||
// Storage: Paras CurrentCodeHash (r:1 w:0)
|
||||
// Storage: Ump RelayDispatchQueueSize (r:1 w:0)
|
||||
// Storage: Ump NeedsDispatch (r:1 w:1)
|
||||
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1)
|
||||
// Storage: ParaInherent OnChainVotes (r:0 w:1)
|
||||
// Storage: Hrmp HrmpWatermarks (r:0 w:1)
|
||||
// Storage: Paras Heads (r:0 w:1)
|
||||
fn enter_backed_candidate_code_upgrade() -> Weight {
|
||||
(53_728_168_000 as Weight)
|
||||
.saturating_add(T::DbWeight::get().reads(26 as Weight))
|
||||
.saturating_add(T::DbWeight::get().writes(14 as Weight))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user