mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 07:01:03 +00:00
Unify code paths of create_inherent and enter (#7137)
* Remove redundant enter call. * Remove optionality in dispute signature checking * Make enter_inner and create_inherent the same. * Remove redundant metric. * Unification: enter and create_inherent. * Remove `enter_inner` function. * Remove dead code. * Remove redundant import. * Remove dead code in disputes. * ".git/.scripts/commands/bench/bench.sh" runtime polkadot runtime_parachains::paras_inherent * ".git/.scripts/commands/bench/bench.sh" runtime kusama runtime_parachains::paras_inherent * ".git/.scripts/commands/bench/bench.sh" runtime westend runtime_parachains::paras_inherent * Merge fix. * Fix tests. * Remove obsolete comment. * ".git/.scripts/commands/bench/bench.sh" runtime polkadot runtime_parachains::paras_inherent * ".git/.scripts/commands/bench/bench.sh" runtime westend runtime_parachains::paras_inherent * ".git/.scripts/commands/bench/bench.sh" runtime kusama runtime_parachains::paras_inherent * Review remarks, fixes. * Guide updates. * Fmt. * ".git/.scripts/commands/bench/bench.sh" runtime polkadot runtime_parachains::paras_inherent --------- Co-authored-by: eskimor <eskimor@no-such-url.com> Co-authored-by: command-bot <>
This commit is contained in:
@@ -21,13 +21,12 @@ use crate::runtime::RuntimeMetricsProvider;
|
||||
use primitives::metric_definitions::{
|
||||
PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS,
|
||||
PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED, PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED,
|
||||
PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED, PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED,
|
||||
PARACHAIN_INHERENT_DATA_WEIGHT, PARACHAIN_VERIFY_DISPUTE_SIGNATURE,
|
||||
PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED, PARACHAIN_INHERENT_DATA_WEIGHT,
|
||||
PARACHAIN_VERIFY_DISPUTE_SIGNATURE,
|
||||
};
|
||||
|
||||
/// Register the parachain runtime metrics.
|
||||
pub fn register_metrics(runtime_metrics_provider: &RuntimeMetricsProvider) {
|
||||
runtime_metrics_provider.register_counter(PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED);
|
||||
runtime_metrics_provider.register_counter(PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED);
|
||||
|
||||
runtime_metrics_provider.register_countervec(PARACHAIN_INHERENT_DATA_WEIGHT);
|
||||
|
||||
@@ -147,45 +147,39 @@ pub mod metric_definitions {
|
||||
labels: &["when"],
|
||||
};
|
||||
|
||||
/// Counts the number of bitfields processed in `enter_inner`.
|
||||
/// Counts the number of bitfields processed in `process_inherent_data`.
|
||||
pub const PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED: CounterDefinition = CounterDefinition {
|
||||
name: "polkadot_parachain_inherent_data_bitfields_processed",
|
||||
description: "Counts the number of bitfields processed in `enter_inner`.",
|
||||
description: "Counts the number of bitfields processed in `process_inherent_data`.",
|
||||
};
|
||||
|
||||
/// Counts the `total`, `sanitized` and `included` number of parachain block candidates
|
||||
/// in `enter_inner`.
|
||||
/// in `process_inherent_data`.
|
||||
pub const PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_inherent_data_candidates_processed",
|
||||
description:
|
||||
"Counts the number of parachain block candidates processed in `enter_inner`.",
|
||||
"Counts the number of parachain block candidates processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of `imported`, `current` and `concluded_invalid` dispute statements sets
|
||||
/// processed in `enter_inner`. The `current` label refers to the disputes statement sets of
|
||||
/// processed in `process_inherent_data`. The `current` label refers to the disputes statement sets of
|
||||
/// the current session.
|
||||
pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_inherent_data_dispute_sets_processed",
|
||||
description: "Counts the number of dispute statements sets processed in `enter_inner`.",
|
||||
description:
|
||||
"Counts the number of dispute statements sets processed in `process_inherent_data`.",
|
||||
labels: &["category"],
|
||||
};
|
||||
|
||||
/// Counts the number of dispute statements sets included in a block in `enter_inner`.
|
||||
pub const PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED: CounterDefinition =
|
||||
CounterDefinition {
|
||||
name: "polkadot_parachain_inherent_data_dispute_sets_included",
|
||||
description:
|
||||
"Counts the number of dispute statements sets included in a block in `enter_inner`.",
|
||||
};
|
||||
|
||||
/// Counts the number of `valid` and `invalid` bitfields signature checked in `enter_inner`.
|
||||
/// Counts the number of `valid` and `invalid` bitfields signature checked in `process_inherent_data`.
|
||||
pub const PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS: CounterVecDefinition =
|
||||
CounterVecDefinition {
|
||||
name: "polkadot_parachain_create_inherent_bitfields_signature_checks",
|
||||
description: "Counts the number of bitfields signature checked in `enter_inner`.",
|
||||
description:
|
||||
"Counts the number of bitfields signature checked in `process_inherent_data`.",
|
||||
labels: &["validity"],
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# `ParaInherent`
|
||||
|
||||
This module is responsible for providing all data given to the runtime by the block author to the various parachains modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also "inherent", in that it is provided with no origin by the block author. The data within it carries its own authentication; i.e. the data takes the form of signed statements by validators. If any of the steps within fails, the entry-point is considered as having failed and the block will be invalid.
|
||||
This module is responsible for providing all data given to the runtime by the block author to the various parachains modules. The entry-point is mandatory, in that it must be invoked exactly once within every block, and it is also "inherent", in that it is provided with no origin by the block author. The data within it carries its own authentication; i.e. the data takes the form of signed statements by validators. Invalid data will be filtered and not applied.
|
||||
|
||||
This module does not have the same initialization/finalization concerns as the others, as it only requires that entry points be triggered after all modules have initialized and that finalization happens after entry points are triggered. Both of these are assumptions we have already made about the runtime's order of operations, so this module doesn't need to be initialized or finalized by the `Initializer`.
|
||||
|
||||
@@ -30,59 +30,28 @@ OnChainVotes: Option<ScrapedOnChainVotes>,
|
||||
## Entry Points
|
||||
|
||||
* `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.
|
||||
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)`.
|
||||
1. If `Scheduler::availability_timeout_predicate` is `Some`, invoke `Inclusion::collect_pending` using it and annotate each of those freed cores with `FreedReason::TimedOut`.
|
||||
1. Combine and sort the the bitfield-freed cores and the timed-out cores.
|
||||
1. Invoke `Scheduler::clear`
|
||||
1. Invoke `Scheduler::schedule(freed_cores, System::current_block())`
|
||||
1. Extract `parent_storage_root` from the parent header,
|
||||
1. If `Disputes::concluded_invalid(current_session, candidate)` is true for any of the `backed_candidates`, fail.
|
||||
1. Invoke the `Inclusion::process_candidates` routine with the parameters `(parent_storage_root, backed_candidates, Scheduler::scheduled(), Scheduler::group_validators)`.
|
||||
1. Deconstruct the returned `ProcessedCandidates` value into `occupied` core indices, and backing validators by candidate `backing_validators_per_candidate` represented by `Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>`.
|
||||
1. Set `OnChainVotes` to `ScrapedOnChainVotes`, based on the `current_session`, concluded `disputes`, and `backing_validators_per_candidate`.
|
||||
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
|
||||
Both entry points share mostly the same code. `create_inherent` will
|
||||
meaningfully limit inherent data to adhere to the weight limit, in addition to
|
||||
sanitizing any inputs and filtering out invalid data. Conceptually it is part of
|
||||
the block production. The `enter` call on the other hand is part of block import
|
||||
and consumes/imports the data previously produced by `create_inherent`.
|
||||
|
||||
In practice both calls process inherent data and apply it to the state. Block
|
||||
production and block import should arrive at the same new state. Hence we re-use
|
||||
the same logic to ensure this is the case.
|
||||
|
||||
The only real difference between the two is, that on `create_inherent` we
|
||||
actually need the processed and filtered inherent data to build the block, while
|
||||
on `enter` the processed data should for one be identical to the incoming
|
||||
inherent data (assuming honest block producers) and second it is irrelevant, as
|
||||
we are not building a block but just processing it, so the processed inherent
|
||||
data is simply dropped.
|
||||
|
||||
This also means that the `enter` function keeps data around for no good reason.
|
||||
This seems acceptable though as the size of a block is rather limited.
|
||||
Nevertheless if we ever wanted to optimize this we can easily implement an
|
||||
inherent collector that has two implementations, where one clones and stores the
|
||||
data and the other just passes it on.
|
||||
|
||||
* `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 }`.
|
||||
|
||||
@@ -17,24 +17,26 @@
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// target/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=kusama-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --chain=kusama-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/kusama/src/weights/runtime_parachains_paras_inherent.rs
|
||||
// --output=./runtime/kusama/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -53,6 +55,10 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaSessionInfo Sessions (r:1 w:0)
|
||||
@@ -61,8 +67,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes BackersOnDisputes (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Included (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -73,12 +77,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen)
|
||||
/// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
@@ -91,8 +95,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
@@ -112,11 +114,11 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `50671`
|
||||
// Estimated: `56611 + v * (23 ±0)`
|
||||
// Minimum execution time: 765_925_000 picoseconds.
|
||||
Weight::from_parts(297_309_443, 0)
|
||||
// Minimum execution time: 800_725_000 picoseconds.
|
||||
Weight::from_parts(336_254_020, 0)
|
||||
.saturating_add(Weight::from_parts(0, 56611))
|
||||
// Standard Error: 26_133
|
||||
.saturating_add(Weight::from_parts(48_559_543, 0).saturating_mul(v.into()))
|
||||
// Standard Error: 25_581
|
||||
.saturating_add(Weight::from_parts(48_329_153, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(27))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
.saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into()))
|
||||
@@ -127,18 +129,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -157,8 +161,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
@@ -183,8 +185,8 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42504`
|
||||
// Estimated: `48444`
|
||||
// Minimum execution time: 317_981_000 picoseconds.
|
||||
Weight::from_parts(326_881_000, 0)
|
||||
// Minimum execution time: 352_534_000 picoseconds.
|
||||
Weight::from_parts(361_737_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48444))
|
||||
.saturating_add(T::DbWeight::get().reads(25))
|
||||
.saturating_add(T::DbWeight::get().writes(16))
|
||||
@@ -195,18 +197,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -225,9 +229,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -256,12 +258,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42540`
|
||||
// Estimated: `48480`
|
||||
// Minimum execution time: 5_573_801_000 picoseconds.
|
||||
Weight::from_parts(827_804_247, 0)
|
||||
// Minimum execution time: 5_727_163_000 picoseconds.
|
||||
Weight::from_parts(969_937_276, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48480))
|
||||
// Standard Error: 49_742
|
||||
.saturating_add(Weight::from_parts(47_813_417, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(29))
|
||||
// Standard Error: 52_405
|
||||
.saturating_add(Weight::from_parts(47_875_548, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(28))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
/// Storage: ParaInherent Included (r:1 w:1)
|
||||
@@ -270,18 +272,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -300,9 +304,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -334,10 +336,10 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42567`
|
||||
// Estimated: `48507`
|
||||
// Minimum execution time: 33_592_912_000 picoseconds.
|
||||
Weight::from_parts(34_625_823_000, 0)
|
||||
// Minimum execution time: 32_796_206_000 picoseconds.
|
||||
Weight::from_parts(33_220_759_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48507))
|
||||
.saturating_add(T::DbWeight::get().reads(31))
|
||||
.saturating_add(T::DbWeight::get().reads(30))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,19 +136,6 @@ impl<BlockNumber> SlashingHandler<BlockNumber> for () {
|
||||
fn initializer_on_new_session(_: SessionIndex) {}
|
||||
}
|
||||
|
||||
/// Binary discriminator to determine if the expensive signature
|
||||
/// checks are necessary.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum VerifyDisputeSignatures {
|
||||
/// Yes, verify the signatures.
|
||||
Yes,
|
||||
/// No, skip the signature verification.
|
||||
///
|
||||
/// Only done if there exists an invariant that
|
||||
/// can guaranteed the signature was checked before.
|
||||
Skip,
|
||||
}
|
||||
|
||||
/// Provide a `Ordering` for the two provided dispute statement sets according to the
|
||||
/// following prioritization:
|
||||
/// 1. Prioritize local disputes over remote disputes
|
||||
@@ -184,36 +171,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
use super::paras_inherent::IsSortedBy;
|
||||
|
||||
/// Returns `true` if duplicate items were found, otherwise `false`.
|
||||
///
|
||||
/// `check_equal(a: &T, b: &T)` _must_ return `true`, iff `a` and `b` are equal, otherwise `false.
|
||||
/// The definition of _equal_ is to be defined by the user.
|
||||
///
|
||||
/// Attention: Requires the input `iter` to be sorted, such that _equals_
|
||||
/// would be adjacent in respect whatever `check_equal` defines as equality!
|
||||
fn contains_duplicates_in_sorted_iter<
|
||||
'a,
|
||||
T: 'a,
|
||||
I: 'a + IntoIterator<Item = &'a T>,
|
||||
C: 'static + FnMut(&T, &T) -> bool,
|
||||
>(
|
||||
iter: I,
|
||||
mut check_equal: C,
|
||||
) -> bool {
|
||||
let mut iter = iter.into_iter();
|
||||
if let Some(mut previous) = iter.next() {
|
||||
while let Some(current) = iter.next() {
|
||||
if check_equal(previous, current) {
|
||||
return true
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/// Hook into disputes handling.
|
||||
///
|
||||
/// Allows decoupling parachains handling from disputes so that it can
|
||||
@@ -223,23 +180,6 @@ pub trait DisputesHandler<BlockNumber: Ord> {
|
||||
/// any new parachain blocks for backing or inclusion.
|
||||
fn is_frozen() -> bool;
|
||||
|
||||
/// Assure sanity
|
||||
fn assure_deduplicated_and_sorted(statement_sets: &MultiDisputeStatementSet) -> Result<(), ()> {
|
||||
if !IsSortedBy::is_sorted_by(
|
||||
statement_sets.as_slice(),
|
||||
dispute_ordering_compare::<Self, BlockNumber>,
|
||||
) {
|
||||
return Err(())
|
||||
}
|
||||
// Sorted, so according to session and candidate hash, this will detect duplicates.
|
||||
if contains_duplicates_in_sorted_iter(statement_sets, |previous, current| {
|
||||
current.session == previous.session && current.candidate_hash == previous.candidate_hash
|
||||
}) {
|
||||
return Err(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove dispute statement duplicates and sort the non-duplicates based on
|
||||
/// local (lower indicies) vs remotes (higher indices) and age (older with lower indices).
|
||||
///
|
||||
@@ -274,7 +214,6 @@ pub trait DisputesHandler<BlockNumber: Ord> {
|
||||
fn filter_dispute_data(
|
||||
statement_set: DisputeStatementSet,
|
||||
post_conclusion_acceptance_period: BlockNumber,
|
||||
verify_sigs: VerifyDisputeSignatures,
|
||||
) -> Option<CheckedDisputeStatementSet>;
|
||||
|
||||
/// Handle sets of dispute statements corresponding to 0 or more candidates.
|
||||
@@ -322,7 +261,6 @@ impl<BlockNumber: Ord> DisputesHandler<BlockNumber> for () {
|
||||
fn filter_dispute_data(
|
||||
_set: DisputeStatementSet,
|
||||
_post_conclusion_acceptance_period: BlockNumber,
|
||||
_verify_sigs: VerifyDisputeSignatures,
|
||||
) -> Option<CheckedDisputeStatementSet> {
|
||||
None
|
||||
}
|
||||
@@ -371,14 +309,9 @@ where
|
||||
fn filter_dispute_data(
|
||||
set: DisputeStatementSet,
|
||||
post_conclusion_acceptance_period: T::BlockNumber,
|
||||
verify_sigs: VerifyDisputeSignatures,
|
||||
) -> Option<CheckedDisputeStatementSet> {
|
||||
pallet::Pallet::<T>::filter_dispute_data(
|
||||
&set,
|
||||
post_conclusion_acceptance_period,
|
||||
verify_sigs,
|
||||
)
|
||||
.filter_statement_set(set)
|
||||
pallet::Pallet::<T>::filter_dispute_data(&set, post_conclusion_acceptance_period)
|
||||
.filter_statement_set(set)
|
||||
}
|
||||
|
||||
fn process_checked_multi_dispute_data(
|
||||
@@ -1005,7 +938,6 @@ impl<T: Config> Pallet<T> {
|
||||
fn filter_dispute_data(
|
||||
set: &DisputeStatementSet,
|
||||
post_conclusion_acceptance_period: <T as frame_system::Config>::BlockNumber,
|
||||
verify_sigs: VerifyDisputeSignatures,
|
||||
) -> StatementSetFilter {
|
||||
let mut filter = StatementSetFilter::RemoveIndices(Vec::new());
|
||||
|
||||
@@ -1068,29 +1000,26 @@ impl<T: Config> Pallet<T> {
|
||||
},
|
||||
};
|
||||
|
||||
// Avoid checking signatures repeatedly.
|
||||
if let VerifyDisputeSignatures::Yes = verify_sigs {
|
||||
// Check signature after attempting import.
|
||||
//
|
||||
// Since we expect that this filter will be applied to
|
||||
// disputes long after they're concluded, 99% of the time,
|
||||
// the duplicate filter above will catch them before needing
|
||||
// to do a heavy signature check.
|
||||
//
|
||||
// This is only really important until the post-conclusion acceptance threshold
|
||||
// is reached, and then no part of this loop will be hit.
|
||||
if let Err(()) = check_signature(
|
||||
&validator_public,
|
||||
set.candidate_hash,
|
||||
set.session,
|
||||
statement,
|
||||
signature,
|
||||
) {
|
||||
importer.undo(undo);
|
||||
filter.remove_index(i);
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Check signature after attempting import.
|
||||
//
|
||||
// Since we expect that this filter will be applied to
|
||||
// disputes long after they're concluded, 99% of the time,
|
||||
// the duplicate filter above will catch them before needing
|
||||
// to do a heavy signature check.
|
||||
//
|
||||
// This is only really important until the post-conclusion acceptance threshold
|
||||
// is reached, and then no part of this loop will be hit.
|
||||
if let Err(()) = check_signature(
|
||||
&validator_public,
|
||||
set.candidate_hash,
|
||||
set.session,
|
||||
statement,
|
||||
signature,
|
||||
) {
|
||||
importer.undo(undo);
|
||||
filter.remove_index(i);
|
||||
continue
|
||||
};
|
||||
}
|
||||
|
||||
importer.finish()
|
||||
|
||||
@@ -42,16 +42,41 @@ fn filter_dispute_set(stmts: MultiDisputeStatementSet) -> CheckedMultiDisputeSta
|
||||
stmts
|
||||
.into_iter()
|
||||
.filter_map(|set| {
|
||||
let filter = Pallet::<Test>::filter_dispute_data(
|
||||
&set,
|
||||
post_conclusion_acceptance_period,
|
||||
VerifyDisputeSignatures::Skip,
|
||||
);
|
||||
let filter =
|
||||
Pallet::<Test>::filter_dispute_data(&set, post_conclusion_acceptance_period);
|
||||
filter.filter_statement_set(set)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Returns `true` if duplicate items were found, otherwise `false`.
|
||||
///
|
||||
/// `check_equal(a: &T, b: &T)` _must_ return `true`, iff `a` and `b` are equal, otherwise `false.
|
||||
/// The definition of _equal_ is to be defined by the user.
|
||||
///
|
||||
/// Attention: Requires the input `iter` to be sorted, such that _equals_
|
||||
/// would be adjacent in respect whatever `check_equal` defines as equality!
|
||||
fn contains_duplicates_in_sorted_iter<
|
||||
'a,
|
||||
T: 'a,
|
||||
I: 'a + IntoIterator<Item = &'a T>,
|
||||
C: 'static + FnMut(&T, &T) -> bool,
|
||||
>(
|
||||
iter: I,
|
||||
mut check_equal: C,
|
||||
) -> bool {
|
||||
let mut iter = iter.into_iter();
|
||||
if let Some(mut previous) = iter.next() {
|
||||
while let Some(current) = iter.next() {
|
||||
if check_equal(previous, current) {
|
||||
return true
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// All arguments for `initializer::on_new_session`
|
||||
type NewSession<'a> = (
|
||||
bool,
|
||||
@@ -2061,7 +2086,6 @@ fn apply_filter_all<T: Config, I: IntoIterator<Item = DisputeStatementSet>>(
|
||||
if let Some(checked) = <Pallet<T> as DisputesHandler<<T>::BlockNumber>>::filter_dispute_data(
|
||||
dispute_statement,
|
||||
post_conclusion_acceptance_period,
|
||||
VerifyDisputeSignatures::Yes,
|
||||
) {
|
||||
acc.push(checked);
|
||||
}
|
||||
@@ -2136,11 +2160,7 @@ fn filter_removes_duplicates_within_set() {
|
||||
let post_conclusion_acceptance_period = 10;
|
||||
let statements = <Pallet<Test> as DisputesHandler<
|
||||
<Test as frame_system::Config>::BlockNumber,
|
||||
>>::filter_dispute_data(
|
||||
statements,
|
||||
post_conclusion_acceptance_period,
|
||||
VerifyDisputeSignatures::Yes,
|
||||
);
|
||||
>>::filter_dispute_data(statements, post_conclusion_acceptance_period);
|
||||
|
||||
assert_eq!(
|
||||
statements,
|
||||
@@ -2441,144 +2461,6 @@ fn filter_removes_duplicate_statements_sets() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assure_no_duplicate_statements_sets_are_fine() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
let v0 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v1 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
|
||||
run_to_block(3, |b| {
|
||||
// a new session at each block
|
||||
Some((
|
||||
true,
|
||||
b,
|
||||
vec![(&0, v0.public()), (&1, v1.public())],
|
||||
Some(vec![(&0, v0.public()), (&1, v1.public())]),
|
||||
))
|
||||
});
|
||||
|
||||
let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
|
||||
let payload = ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
}
|
||||
.signing_payload();
|
||||
|
||||
let payload_against = ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
}
|
||||
.signing_payload();
|
||||
|
||||
let sig_a = v0.sign(&payload);
|
||||
let sig_a_against = v1.sign(&payload_against);
|
||||
|
||||
let statements = vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(0),
|
||||
sig_a.clone(),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(1),
|
||||
sig_a_against.clone(),
|
||||
),
|
||||
];
|
||||
|
||||
let sets = vec![
|
||||
DisputeStatementSet {
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
statements: statements.clone(),
|
||||
},
|
||||
DisputeStatementSet {
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 2,
|
||||
statements: statements.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
// `Err(())` indicates presence of duplicates
|
||||
assert!(<Pallet::<Test> as DisputesHandler<
|
||||
<Test as frame_system::Config>::BlockNumber,
|
||||
>>::assure_deduplicated_and_sorted(&sets)
|
||||
.is_ok());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assure_detects_duplicate_statements_sets() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
let v0 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
let v1 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
|
||||
run_to_block(3, |b| {
|
||||
// a new session at each block
|
||||
Some((
|
||||
true,
|
||||
b,
|
||||
vec![(&0, v0.public()), (&1, v1.public())],
|
||||
Some(vec![(&0, v0.public()), (&1, v1.public())]),
|
||||
))
|
||||
});
|
||||
|
||||
let candidate_hash_a = CandidateHash(sp_core::H256::repeat_byte(1));
|
||||
|
||||
let payload = ExplicitDisputeStatement {
|
||||
valid: true,
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
}
|
||||
.signing_payload();
|
||||
|
||||
let payload_against = ExplicitDisputeStatement {
|
||||
valid: false,
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
}
|
||||
.signing_payload();
|
||||
|
||||
let sig_a = v0.sign(&payload);
|
||||
let sig_a_against = v1.sign(&payload_against);
|
||||
|
||||
let statements = vec![
|
||||
(
|
||||
DisputeStatement::Valid(ValidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(0),
|
||||
sig_a.clone(),
|
||||
),
|
||||
(
|
||||
DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit),
|
||||
ValidatorIndex(1),
|
||||
sig_a_against.clone(),
|
||||
),
|
||||
];
|
||||
|
||||
let sets = vec![
|
||||
DisputeStatementSet {
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
statements: statements.clone(),
|
||||
},
|
||||
DisputeStatementSet {
|
||||
candidate_hash: candidate_hash_a.clone(),
|
||||
session: 1,
|
||||
statements: statements.clone(),
|
||||
},
|
||||
];
|
||||
|
||||
// `Err(())` indicates presence of duplicates
|
||||
assert!(<Pallet::<Test> as DisputesHandler<
|
||||
<Test as frame_system::Config>::BlockNumber,
|
||||
>>::assure_deduplicated_and_sorted(&sets)
|
||||
.is_err());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_ignores_single_sided() {
|
||||
new_test_ext(Default::default()).execute_with(|| {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
disputes, dmp, hrmp, paras,
|
||||
paras_inherent::DisputedBitfield,
|
||||
scheduler::CoreAssignment,
|
||||
shared,
|
||||
};
|
||||
@@ -39,8 +38,8 @@ use parity_scale_codec::{Decode, Encode};
|
||||
use primitives::{
|
||||
supermajority_threshold, well_known_keys, AvailabilityBitfield, BackedCandidate,
|
||||
CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt,
|
||||
CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId, SigningContext,
|
||||
UncheckedSignedAvailabilityBitfields, UpwardMessage, ValidatorId, ValidatorIndex,
|
||||
CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId,
|
||||
SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex,
|
||||
ValidityAttestation,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
@@ -92,19 +91,6 @@ pub struct AvailabilityBitfieldRecord<N> {
|
||||
submitted_at: N, // for accounting, as meaning of bits may change over time.
|
||||
}
|
||||
|
||||
/// Determines if all checks should be applied or if a subset was already completed
|
||||
/// in a code path that will be executed afterwards or was already executed before.
|
||||
#[derive(Clone, Copy, Encode, Decode, PartialEq, Eq, RuntimeDebug, TypeInfo)]
|
||||
pub(crate) enum FullCheck {
|
||||
/// Yes, do a full check, skip nothing.
|
||||
Yes,
|
||||
/// Skip a subset of checks that are already completed before.
|
||||
///
|
||||
/// Attention: Should only be used when absolutely sure that the required
|
||||
/// checks are completed before.
|
||||
Skip,
|
||||
}
|
||||
|
||||
/// A backed candidate pending availability.
|
||||
#[derive(Encode, Decode, PartialEq, TypeInfo)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
@@ -497,13 +483,17 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
/// Extract the freed cores based on cores that became available.
|
||||
///
|
||||
/// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`!
|
||||
///
|
||||
/// Updates storage items `PendingAvailability` and `AvailabilityBitfields`.
|
||||
///
|
||||
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available,
|
||||
/// and cores free.
|
||||
pub(crate) fn update_pending_availability_and_get_freed_cores<F>(
|
||||
expected_bits: usize,
|
||||
validators: &[ValidatorId],
|
||||
signed_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
signed_bitfields: SignedAvailabilityBitfields,
|
||||
core_lookup: F,
|
||||
enact_candidate: bool,
|
||||
) -> Vec<(CoreIndex, CandidateHash)>
|
||||
where
|
||||
F: Fn(CoreIndex) -> Option<ParaId>,
|
||||
@@ -518,9 +508,8 @@ impl<T: Config> Pallet<T> {
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
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();
|
||||
let validator_idx = signed_bitfield.validator_index();
|
||||
let checked_bitfield = signed_bitfield.into_payload();
|
||||
(checked_bitfield, validator_idx)
|
||||
}) {
|
||||
for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) {
|
||||
@@ -575,20 +564,18 @@ impl<T: Config> Pallet<T> {
|
||||
},
|
||||
};
|
||||
|
||||
if enact_candidate {
|
||||
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,
|
||||
);
|
||||
}
|
||||
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 {
|
||||
@@ -599,42 +586,6 @@ impl<T: Config> Pallet<T> {
|
||||
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>,
|
||||
full_check: FullCheck,
|
||||
) -> Result<Vec<(CoreIndex, CandidateHash)>, crate::inclusion::Error<T>> {
|
||||
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 = crate::paras_inherent::assure_sanity_bitfields::<T>(
|
||||
signed_bitfields,
|
||||
disputed_bitfield,
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validators[..],
|
||||
full_check,
|
||||
)?;
|
||||
|
||||
let freed_cores = Self::update_pending_availability_and_get_freed_cores::<_>(
|
||||
expected_bits,
|
||||
&validators[..],
|
||||
checked_bitfields,
|
||||
core_lookup,
|
||||
true,
|
||||
);
|
||||
|
||||
Ok(freed_cores)
|
||||
}
|
||||
|
||||
/// Process candidates that have been backed. Provide the relay storage root, a set of candidates
|
||||
/// and scheduled cores.
|
||||
///
|
||||
|
||||
@@ -26,23 +26,20 @@ use crate::{
|
||||
paras_inherent::DisputedBitfield,
|
||||
scheduler::AssignmentKind,
|
||||
};
|
||||
use assert_matches::assert_matches;
|
||||
use primitives::{SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields};
|
||||
|
||||
use frame_support::assert_noop;
|
||||
use keyring::Sr25519Keyring;
|
||||
use parity_scale_codec::DecodeAll;
|
||||
use primitives::{
|
||||
BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId,
|
||||
CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement,
|
||||
UncheckedSignedAvailabilityBitfield, ValidationCode, ValidatorId, ValidityAttestation,
|
||||
PARACHAIN_KEY_TYPE_ID,
|
||||
ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID,
|
||||
};
|
||||
use sc_keystore::LocalKeystore;
|
||||
use sp_keystore::{Keystore, KeystorePtr};
|
||||
use std::sync::Arc;
|
||||
use test_helpers::{
|
||||
dummy_candidate_receipt, dummy_collator, dummy_collator_signature, dummy_hash,
|
||||
dummy_validation_code,
|
||||
};
|
||||
use test_helpers::{dummy_collator, dummy_collator_signature, dummy_validation_code};
|
||||
|
||||
fn default_config() -> HostConfiguration<BlockNumber> {
|
||||
let mut config = HostConfiguration::default();
|
||||
@@ -313,6 +310,41 @@ pub(crate) fn make_vdata_hash(para_id: ParaId) -> Option<Hash> {
|
||||
Some(persisted_validation_data.hash())
|
||||
}
|
||||
|
||||
/// Wrapper around `sanitize_bitfields` with less parameters.
|
||||
fn simple_sanitize_bitfields(
|
||||
unchecked_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
disputed_bitfield: DisputedBitfield,
|
||||
expected_bits: usize,
|
||||
) -> SignedAvailabilityBitfields {
|
||||
let parent_hash = frame_system::Pallet::<Test>::parent_hash();
|
||||
let session_index = shared::Pallet::<Test>::session_index();
|
||||
let validators = shared::Pallet::<Test>::active_validator_keys();
|
||||
|
||||
crate::paras_inherent::sanitize_bitfields::<Test>(
|
||||
unchecked_bitfields,
|
||||
disputed_bitfield,
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validators,
|
||||
)
|
||||
}
|
||||
/// Process a set of already sanitized bitfields.
|
||||
pub(crate) fn process_bitfields(
|
||||
expected_bits: usize,
|
||||
signed_bitfields: SignedAvailabilityBitfields,
|
||||
core_lookup: impl Fn(CoreIndex) -> Option<ParaId>,
|
||||
) -> Vec<(CoreIndex, CandidateHash)> {
|
||||
let validators = shared::Pallet::<Test>::active_validator_keys();
|
||||
|
||||
ParaInclusion::update_pending_availability_and_get_freed_cores::<_>(
|
||||
expected_bits,
|
||||
&validators[..],
|
||||
signed_bitfields,
|
||||
core_lookup,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collect_pending_cleans_up_pending() {
|
||||
let chain_a = ParaId::from(1_u32);
|
||||
@@ -419,26 +451,6 @@ fn bitfield_checks() {
|
||||
_ => panic!("out of bounds for testing"),
|
||||
};
|
||||
|
||||
// mark all candidates as pending availability
|
||||
let set_pending_av = || {
|
||||
for (p_id, _) in paras {
|
||||
let receipt = dummy_candidate_receipt(dummy_hash());
|
||||
PendingAvailability::<Test>::insert(
|
||||
p_id,
|
||||
CandidatePendingAvailability {
|
||||
availability_votes: default_availability_votes(),
|
||||
core: CoreIndex(0),
|
||||
hash: receipt.hash(),
|
||||
descriptor: receipt.descriptor,
|
||||
backers: BitVec::default(),
|
||||
relay_parent_number: BlockNumber::from(0_u32),
|
||||
backed_in_number: BlockNumber::from(0_u32),
|
||||
backing_group: GroupIndex(0),
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
// too many bits in bitfield
|
||||
{
|
||||
let mut bare_bitfield = default_bitfield();
|
||||
@@ -451,15 +463,15 @@ fn bitfield_checks() {
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
),
|
||||
Err(Error::<Test>::WrongBitfieldSize)
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(
|
||||
checked_bitfields.len(),
|
||||
0,
|
||||
"Bitfield has wrong size, it should have been filtered."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -474,126 +486,16 @@ fn bitfield_checks() {
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits() + 1,
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
),
|
||||
Err(Error::<Test>::WrongBitfieldSize)
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
expected_bits() + 1,
|
||||
);
|
||||
}
|
||||
|
||||
// duplicate.
|
||||
{
|
||||
set_pending_av.clone()();
|
||||
let back_core_0_bitfield = {
|
||||
let mut b = default_bitfield();
|
||||
b.0.set(0, true);
|
||||
b
|
||||
};
|
||||
let signed: UncheckedSignedAvailabilityBitfield = sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
ValidatorIndex(0),
|
||||
back_core_0_bitfield,
|
||||
&signing_context,
|
||||
)
|
||||
.into();
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
0
|
||||
checked_bitfields.len(),
|
||||
0,
|
||||
"Bitfield has wrong size, it should have been filtered."
|
||||
);
|
||||
|
||||
// the threshold to free a core is 4 availability votes, but we only expect 1 valid
|
||||
// valid bitfield.
|
||||
assert_matches!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed.clone(), signed],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
),
|
||||
Err(Error::<Test>::UnsortedOrDuplicateValidatorIndices)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
0
|
||||
);
|
||||
|
||||
// clean up
|
||||
#[allow(deprecated)]
|
||||
PendingAvailability::<Test>::remove_all(None);
|
||||
}
|
||||
|
||||
// out of order.
|
||||
{
|
||||
set_pending_av.clone()();
|
||||
let back_core_0_bitfield = {
|
||||
let mut b = default_bitfield();
|
||||
b.0.set(0, true);
|
||||
b
|
||||
};
|
||||
let signed_0 = sign_bitfield(
|
||||
&keystore,
|
||||
&validators[0],
|
||||
ValidatorIndex(0),
|
||||
back_core_0_bitfield.clone(),
|
||||
&signing_context,
|
||||
)
|
||||
.into();
|
||||
|
||||
let signed_1 = sign_bitfield(
|
||||
&keystore,
|
||||
&validators[1],
|
||||
ValidatorIndex(1),
|
||||
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_matches!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
vec![signed_1, signed_0],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
),
|
||||
Err(Error::<Test>::UnsortedOrDuplicateValidatorIndices)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
<PendingAvailability<Test>>::get(chain_a)
|
||||
.unwrap()
|
||||
.availability_votes
|
||||
.count_ones(),
|
||||
0
|
||||
);
|
||||
|
||||
#[allow(deprecated)]
|
||||
PendingAvailability::<Test>::remove_all(None);
|
||||
}
|
||||
|
||||
// non-pending bit set.
|
||||
@@ -608,13 +510,17 @@ fn bitfield_checks() {
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
assert_matches!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
// 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.
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
), Ok(x) => { assert!(x.is_empty())});
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!");
|
||||
|
||||
let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup);
|
||||
assert!(x.is_empty(), "No core should be freed.");
|
||||
}
|
||||
|
||||
// empty bitfield signed: always ok, but kind of useless.
|
||||
@@ -627,14 +533,15 @@ fn bitfield_checks() {
|
||||
bare_bitfield,
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
assert_matches!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
), Ok(x) => { assert!(x.is_empty())});
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!");
|
||||
|
||||
let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup);
|
||||
assert!(x.is_empty(), "No core should be freed.");
|
||||
}
|
||||
|
||||
// bitfield signed with pending bit signed.
|
||||
@@ -668,13 +575,15 @@ fn bitfield_checks() {
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
assert_matches!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
), Ok(v) => { assert!(v.is_empty())} );
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!");
|
||||
|
||||
let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup);
|
||||
assert!(x.is_empty(), "No core should be freed.");
|
||||
|
||||
<PendingAvailability<Test>>::remove(chain_a);
|
||||
PendingAvailabilityCommitments::<Test>::remove(chain_a);
|
||||
@@ -710,14 +619,16 @@ fn bitfield_checks() {
|
||||
&signing_context,
|
||||
);
|
||||
|
||||
// no core is freed
|
||||
assert_matches!(ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
vec![signed.into()],
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
), Ok(v) => { assert!(v.is_empty()) });
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(checked_bitfields.len(), 1, "No bitfields should have been filtered!");
|
||||
|
||||
let x = process_bitfields(expected_bits(), checked_bitfields, core_lookup);
|
||||
// no core is freed
|
||||
assert!(x.is_empty(), "No core should be freed.");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -862,21 +773,19 @@ fn supermajority_bitfields_trigger_availability() {
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let old_len = signed_bitfields.len();
|
||||
let checked_bitfields = simple_sanitize_bitfields(
|
||||
signed_bitfields,
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
expected_bits(),
|
||||
);
|
||||
assert_eq!(checked_bitfields.len(), old_len, "No bitfields should have been filtered!");
|
||||
|
||||
// only chain A's core is freed.
|
||||
assert_matches!(
|
||||
ParaInclusion::process_bitfields(
|
||||
expected_bits(),
|
||||
signed_bitfields,
|
||||
DisputedBitfield::zeros(expected_bits()),
|
||||
&core_lookup,
|
||||
FullCheck::Yes,
|
||||
),
|
||||
Ok(v) => {
|
||||
assert_eq!(vec![(CoreIndex(0), candidate_a.hash())], v);
|
||||
}
|
||||
);
|
||||
let v = process_bitfields(expected_bits(), checked_bitfields, core_lookup);
|
||||
assert_eq!(vec![(CoreIndex(0), candidate_a.hash())], v);
|
||||
|
||||
// chain A had 4 signing off, which is >= threshold.
|
||||
// chain B has 3 signing off, which is < threshold.
|
||||
|
||||
@@ -20,22 +20,20 @@ use polkadot_runtime_metrics::{Counter, CounterVec, Histogram};
|
||||
use primitives::metric_definitions::{
|
||||
PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS,
|
||||
PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED, PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED,
|
||||
PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED, PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED,
|
||||
PARACHAIN_INHERENT_DATA_WEIGHT, PARACHAIN_VERIFY_DISPUTE_SIGNATURE,
|
||||
PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED, PARACHAIN_INHERENT_DATA_WEIGHT,
|
||||
PARACHAIN_VERIFY_DISPUTE_SIGNATURE,
|
||||
};
|
||||
|
||||
pub struct Metrics {
|
||||
/// Samples inherent data weight.
|
||||
inherent_data_weight: CounterVec,
|
||||
/// Counts how many inherent bitfields processed in `enter_inner`.
|
||||
/// Counts how many inherent bitfields processed in `process_inherent_data`.
|
||||
bitfields_processed: Counter,
|
||||
/// Counts how many parachain candidates processed in `enter_inner`.
|
||||
/// Counts how many parachain candidates processed in `process_inherent_data`.
|
||||
candidates_processed: CounterVec,
|
||||
/// Counts dispute statements sets processed in `enter_inner`.
|
||||
/// Counts dispute statements sets processed in `process_inherent_data`.
|
||||
dispute_sets_processed: CounterVec,
|
||||
/// Counts dispute statements sets included in `enter_inner`.
|
||||
disputes_included: Counter,
|
||||
/// Counts bitfield signature checks in `enter_inner`.
|
||||
/// Counts bitfield signature checks in `process_inherent_data`.
|
||||
bitfields_signature_checks: CounterVec,
|
||||
|
||||
/// Histogram with the time spent checking a validator signature of a dispute statement
|
||||
@@ -68,22 +66,17 @@ impl Metrics {
|
||||
self.candidates_processed.with_label_values(&["sanitized"]).inc_by(value);
|
||||
}
|
||||
|
||||
/// Increment the total number of parachain candidates received in `enter_inner`.
|
||||
/// Increment the total number of parachain candidates received in `process_inherent_data`.
|
||||
pub fn on_candidates_processed_total(&self, value: u64) {
|
||||
self.candidates_processed.with_label_values(&["total"]).inc_by(value);
|
||||
}
|
||||
|
||||
/// Sample the relay chain freeze events causing runtime to not process candidates in
|
||||
/// `enter_inner`.
|
||||
/// `process_inherent_data`.
|
||||
pub fn on_relay_chain_freeze(&self) {
|
||||
self.dispute_sets_processed.with_label_values(&["frozen"]).inc();
|
||||
}
|
||||
|
||||
/// Sample the number of dispute sets processed from the current session.
|
||||
pub fn on_current_session_disputes_processed(&self, value: u64) {
|
||||
self.dispute_sets_processed.with_label_values(&["current"]).inc_by(value);
|
||||
}
|
||||
|
||||
/// Increment the number of disputes that have concluded as invalid.
|
||||
pub fn on_disputes_concluded_invalid(&self, value: u64) {
|
||||
self.dispute_sets_processed
|
||||
@@ -96,10 +89,6 @@ impl Metrics {
|
||||
self.dispute_sets_processed.with_label_values(&["imported"]).inc_by(value);
|
||||
}
|
||||
|
||||
pub fn on_disputes_included(&self, value: u64) {
|
||||
self.disputes_included.inc_by(value);
|
||||
}
|
||||
|
||||
pub fn on_valid_bitfield_signature(&self) {
|
||||
self.bitfields_signature_checks.with_label_values(&["valid"]).inc_by(1);
|
||||
}
|
||||
@@ -118,7 +107,6 @@ pub const METRICS: Metrics = Metrics {
|
||||
bitfields_processed: Counter::new(PARACHAIN_INHERENT_DATA_BITFIELDS_PROCESSED),
|
||||
candidates_processed: CounterVec::new(PARACHAIN_INHERENT_DATA_CANDIDATES_PROCESSED),
|
||||
dispute_sets_processed: CounterVec::new(PARACHAIN_INHERENT_DATA_DISPUTE_SETS_PROCESSED),
|
||||
disputes_included: Counter::new(PARACHAIN_INHERENT_DATA_DISPUTE_SETS_INCLUDED),
|
||||
bitfields_signature_checks: CounterVec::new(
|
||||
PARACHAIN_CREATE_INHERENT_BITFIELDS_SIGNATURE_CHECKS,
|
||||
),
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
use crate::{
|
||||
configuration,
|
||||
disputes::{DisputesHandler, VerifyDisputeSignatures},
|
||||
disputes::DisputesHandler,
|
||||
inclusion,
|
||||
inclusion::{CandidateCheckContext, FullCheck},
|
||||
inclusion::CandidateCheckContext,
|
||||
initializer,
|
||||
metrics::METRICS,
|
||||
scheduler::{self, CoreAssignment, FreedReason},
|
||||
@@ -33,6 +33,7 @@ use crate::{
|
||||
};
|
||||
use bitvec::prelude::BitVec;
|
||||
use frame_support::{
|
||||
dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo},
|
||||
inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent},
|
||||
pallet_prelude::*,
|
||||
traits::Randomness,
|
||||
@@ -43,7 +44,7 @@ use primitives::{
|
||||
BackedCandidate, CandidateHash, CandidateReceipt, CheckedDisputeStatementSet,
|
||||
CheckedMultiDisputeStatementSet, CoreIndex, DisputeStatementSet,
|
||||
InherentData as ParachainsInherentData, MultiDisputeStatementSet, ScrapedOnChainVotes,
|
||||
SessionIndex, SigningContext, UncheckedSignedAvailabilityBitfield,
|
||||
SessionIndex, SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield,
|
||||
UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation,
|
||||
PARACHAINS_INHERENT_IDENTIFIER,
|
||||
};
|
||||
@@ -209,32 +210,6 @@ pub mod pallet {
|
||||
|
||||
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
|
||||
let inherent_data = Self::create_inherent_inner(data)?;
|
||||
// Sanity check: session changes can invalidate an inherent,
|
||||
// and we _really_ don't want that to happen.
|
||||
// See <https://github.com/paritytech/polkadot/issues/1327>
|
||||
|
||||
// Calling `Self::enter` here is a safe-guard, to avoid any discrepancy between on-chain checks
|
||||
// (`enter`) and the off-chain checks by the block author (this function). Once we are confident
|
||||
// in all the logic in this module this check should be removed to optimize performance.
|
||||
|
||||
let inherent_data = match Self::enter_inner(inherent_data.clone(), FullCheck::Skip) {
|
||||
Ok(_) => inherent_data,
|
||||
Err(err) => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
"dropping paras inherent data because they produced \
|
||||
an invalid paras inherent: {:?}",
|
||||
err.error,
|
||||
);
|
||||
|
||||
ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes: Vec::new(),
|
||||
parent_header: inherent_data.parent_header,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Some(Call::enter { data: inherent_data })
|
||||
}
|
||||
@@ -294,259 +269,16 @@ pub mod pallet {
|
||||
ensure!(!Included::<T>::exists(), Error::<T>::TooManyInclusionInherents);
|
||||
Included::<T>::set(Some(()));
|
||||
|
||||
Self::enter_inner(data, FullCheck::Yes)
|
||||
Self::process_inherent_data(data).map(|(_processed, post_info)| post_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub(crate) fn enter_inner(
|
||||
data: ParachainsInherentData<T::Header>,
|
||||
full_check: FullCheck,
|
||||
) -> DispatchResultWithPostInfo {
|
||||
let ParachainsInherentData {
|
||||
bitfields: mut signed_bitfields,
|
||||
mut backed_candidates,
|
||||
parent_header,
|
||||
mut disputes,
|
||||
} = data;
|
||||
#[cfg(feature = "runtime-metrics")]
|
||||
sp_io::init_tracing();
|
||||
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"[enter_inner] parent_header={:?} bitfields.len(): {}, backed_candidates.len(): {}, disputes.len(): {}",
|
||||
parent_header.hash(),
|
||||
signed_bitfields.len(),
|
||||
backed_candidates.len(),
|
||||
disputes.len()
|
||||
);
|
||||
|
||||
// Check that the submitted parent header indeed corresponds to the previous block hash.
|
||||
let parent_hash = <frame_system::Pallet<T>>::parent_hash();
|
||||
ensure!(
|
||||
parent_header.hash().as_ref() == parent_hash.as_ref(),
|
||||
Error::<T>::InvalidParentHeader,
|
||||
);
|
||||
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
|
||||
let mut candidates_weight = backed_candidates_weight::<T>(&backed_candidates);
|
||||
let mut bitfields_weight = signed_bitfields_weight::<T>(signed_bitfields.len());
|
||||
let disputes_weight = multi_dispute_statement_sets_weight::<T, _, _>(&disputes);
|
||||
|
||||
let current_session = <shared::Pallet<T>>::session_index();
|
||||
|
||||
let max_block_weight = <T as frame_system::Config>::BlockWeights::get().max_block;
|
||||
|
||||
METRICS
|
||||
.on_before_filter((candidates_weight + bitfields_weight + disputes_weight).ref_time());
|
||||
|
||||
T::DisputesHandler::assure_deduplicated_and_sorted(&mut disputes)
|
||||
.map_err(|_e| Error::<T>::DisputeStatementsUnsortedOrDuplicates)?;
|
||||
|
||||
let (checked_disputes, total_consumed_weight) = {
|
||||
// Obtain config params..
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
let post_conclusion_acceptance_period =
|
||||
config.dispute_post_conclusion_acceptance_period;
|
||||
|
||||
let verify_dispute_sigs = if let FullCheck::Yes = full_check {
|
||||
VerifyDisputeSignatures::Yes
|
||||
} else {
|
||||
VerifyDisputeSignatures::Skip
|
||||
};
|
||||
|
||||
// .. and prepare a helper closure.
|
||||
let dispute_set_validity_check = move |set| {
|
||||
T::DisputesHandler::filter_dispute_data(
|
||||
set,
|
||||
post_conclusion_acceptance_period,
|
||||
verify_dispute_sigs,
|
||||
)
|
||||
};
|
||||
|
||||
// In case of an overweight block, consume up to the entire block weight
|
||||
// in disputes, since we will never process anything else, but invalidate
|
||||
// the block. It's still reasonable to protect against a massive amount of disputes.
|
||||
if candidates_weight
|
||||
.saturating_add(bitfields_weight)
|
||||
.saturating_add(disputes_weight)
|
||||
.any_gt(max_block_weight)
|
||||
{
|
||||
log::warn!("Overweight para inherent data reached the runtime {:?}", parent_hash);
|
||||
backed_candidates.clear();
|
||||
candidates_weight = Weight::zero();
|
||||
signed_bitfields.clear();
|
||||
bitfields_weight = Weight::zero();
|
||||
}
|
||||
|
||||
let entropy = compute_entropy::<T>(parent_hash);
|
||||
let mut rng = rand_chacha::ChaChaRng::from_seed(entropy.into());
|
||||
|
||||
let (checked_disputes, checked_disputes_weight) = limit_and_sanitize_disputes::<T, _>(
|
||||
disputes,
|
||||
&dispute_set_validity_check,
|
||||
max_block_weight,
|
||||
&mut rng,
|
||||
);
|
||||
(
|
||||
checked_disputes,
|
||||
checked_disputes_weight
|
||||
.saturating_add(candidates_weight)
|
||||
.saturating_add(bitfields_weight),
|
||||
)
|
||||
};
|
||||
|
||||
let expected_bits = <scheduler::Pallet<T>>::availability_cores().len();
|
||||
|
||||
// Handle disputes logic.
|
||||
let disputed_bitfield = {
|
||||
let new_current_dispute_sets: Vec<_> = checked_disputes
|
||||
.iter()
|
||||
.map(AsRef::as_ref)
|
||||
.filter(|s| s.session == current_session)
|
||||
.map(|s| (s.session, s.candidate_hash))
|
||||
.collect();
|
||||
|
||||
// Note that `process_checked_multi_dispute_data` will iterate and import each
|
||||
// dispute; so the input here must be reasonably bounded,
|
||||
// which is guaranteed by the checks and weight limitation above.
|
||||
let _ = T::DisputesHandler::process_checked_multi_dispute_data(&checked_disputes)?;
|
||||
METRICS.on_disputes_imported(checked_disputes.len() as u64);
|
||||
|
||||
if T::DisputesHandler::is_frozen() {
|
||||
// Relay chain freeze, at this point we will not include any parachain blocks.
|
||||
METRICS.on_relay_chain_freeze();
|
||||
|
||||
// The relay chain we are currently on is invalid. Proceed no further on parachains.
|
||||
return Ok(Some(total_consumed_weight).into())
|
||||
}
|
||||
|
||||
// Process the dispute sets of the current session.
|
||||
METRICS.on_current_session_disputes_processed(new_current_dispute_sets.len() as u64);
|
||||
|
||||
let mut freed_disputed = if !new_current_dispute_sets.is_empty() {
|
||||
let concluded_invalid_disputes = new_current_dispute_sets
|
||||
.iter()
|
||||
.filter(|(session, candidate)| {
|
||||
T::DisputesHandler::concluded_invalid(*session, *candidate)
|
||||
})
|
||||
.map(|(_, candidate)| *candidate)
|
||||
.collect::<BTreeSet<CandidateHash>>();
|
||||
|
||||
// Count invalid dispute sets.
|
||||
METRICS.on_disputes_concluded_invalid(concluded_invalid_disputes.len() as u64);
|
||||
|
||||
let freed_disputed: Vec<_> =
|
||||
<inclusion::Pallet<T>>::collect_disputed(&concluded_invalid_disputes)
|
||||
.into_iter()
|
||||
.map(|core| (core, FreedReason::Concluded))
|
||||
.collect();
|
||||
|
||||
freed_disputed
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
// Create a bit index from the set of core indices where each index corresponds to
|
||||
// a core index that was freed due to a dispute.
|
||||
//
|
||||
// I.e. 010100 would indicate, the candidates on Core 1 and 3 would be disputed.
|
||||
let disputed_bitfield = create_disputed_bitfield(
|
||||
expected_bits,
|
||||
freed_disputed.iter().map(|(core_index, _)| core_index),
|
||||
);
|
||||
|
||||
if !freed_disputed.is_empty() {
|
||||
// unstable sort is fine, because core indices are unique
|
||||
// i.e. the same candidate can't occupy 2 cores at once.
|
||||
freed_disputed.sort_unstable_by_key(|pair| pair.0); // sort by core index
|
||||
<scheduler::Pallet<T>>::free_cores(freed_disputed);
|
||||
}
|
||||
|
||||
disputed_bitfield
|
||||
};
|
||||
|
||||
METRICS.on_bitfields_processed(signed_bitfields.len() as u64);
|
||||
|
||||
// Process new availability bitfields, yielding any availability cores whose
|
||||
// work has now concluded.
|
||||
let freed_concluded = <inclusion::Pallet<T>>::process_bitfields(
|
||||
expected_bits,
|
||||
signed_bitfields,
|
||||
disputed_bitfield,
|
||||
<scheduler::Pallet<T>>::core_para,
|
||||
full_check,
|
||||
)?;
|
||||
// any error in the previous function will cause an invalid block and not include
|
||||
// the `DisputeState` to be written to the storage, hence this is ok.
|
||||
set_scrapable_on_chain_disputes::<T>(current_session, checked_disputes.clone());
|
||||
|
||||
// Inform the disputes module of all included candidates.
|
||||
for (_, candidate_hash) in &freed_concluded {
|
||||
T::DisputesHandler::note_included(current_session, *candidate_hash, now);
|
||||
}
|
||||
|
||||
METRICS.on_candidates_included(freed_concluded.len() as u64);
|
||||
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned());
|
||||
|
||||
<scheduler::Pallet<T>>::clear();
|
||||
<scheduler::Pallet<T>>::schedule(freed, now);
|
||||
|
||||
METRICS.on_candidates_processed_total(backed_candidates.len() as u64);
|
||||
|
||||
let scheduled = <scheduler::Pallet<T>>::scheduled();
|
||||
assure_sanity_backed_candidates::<T, _>(
|
||||
parent_hash,
|
||||
&backed_candidates,
|
||||
move |_candidate_index: usize, backed_candidate: &BackedCandidate<T::Hash>| -> bool {
|
||||
<T>::DisputesHandler::concluded_invalid(current_session, backed_candidate.hash())
|
||||
// `fn process_candidates` does the verification checks
|
||||
},
|
||||
&scheduled[..],
|
||||
)?;
|
||||
|
||||
METRICS.on_candidates_sanitized(backed_candidates.len() as u64);
|
||||
|
||||
// Process backed candidates according to scheduled cores.
|
||||
let parent_storage_root = *parent_header.state_root();
|
||||
let inclusion::ProcessedCandidates::<<T::Header as HeaderT>::Hash> {
|
||||
core_indices: occupied,
|
||||
candidate_receipt_with_backing_validator_indices,
|
||||
} = <inclusion::Pallet<T>>::process_candidates(
|
||||
parent_storage_root,
|
||||
backed_candidates,
|
||||
scheduled,
|
||||
<scheduler::Pallet<T>>::group_validators,
|
||||
)?;
|
||||
|
||||
METRICS.on_disputes_included(checked_disputes.len() as u64);
|
||||
|
||||
set_scrapable_on_chain_backings::<T>(
|
||||
current_session,
|
||||
candidate_receipt_with_backing_validator_indices,
|
||||
);
|
||||
|
||||
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
||||
<scheduler::Pallet<T>>::occupied(&occupied);
|
||||
|
||||
METRICS.on_after_filter(total_consumed_weight.ref_time());
|
||||
|
||||
Ok(Some(total_consumed_weight).into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Create the `ParachainsInherentData` that gets passed to [`Self::enter`] in [`Self::create_inherent`].
|
||||
/// This code is pulled out of [`Self::create_inherent`] so it can be unit tested.
|
||||
fn create_inherent_inner(data: &InherentData) -> Option<ParachainsInherentData<T::Header>> {
|
||||
let ParachainsInherentData::<T::Header> {
|
||||
bitfields,
|
||||
backed_candidates,
|
||||
mut disputes,
|
||||
parent_header,
|
||||
} = match data.get_data(&Self::INHERENT_IDENTIFIER) {
|
||||
let parachains_inherent_data = match data.get_data(&Self::INHERENT_IDENTIFIER) {
|
||||
Ok(Some(d)) => d,
|
||||
Ok(None) => return None,
|
||||
Err(_) => {
|
||||
@@ -554,10 +286,45 @@ impl<T: Config> Pallet<T> {
|
||||
return None
|
||||
},
|
||||
};
|
||||
match Self::process_inherent_data(parachains_inherent_data) {
|
||||
Ok((processed, _)) => Some(processed),
|
||||
Err(err) => {
|
||||
log::warn!(target: LOG_TARGET, "Processing inherent data failed: {:?}", err);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Process inherent data.
|
||||
///
|
||||
/// The given inherent data is processed and state is altered accordingly. If any data could
|
||||
/// not be applied (inconsitencies, weight limit, ...) it is removed.
|
||||
///
|
||||
/// This function can both be called on block creation in `create_inherent` and on block import
|
||||
/// in `enter`. The mutation of `data` is only useful in the `create_inherent` case as it
|
||||
/// avoids overweight blocks for example.
|
||||
///
|
||||
/// Returns: Result containing processed inherent data and weight, the processed inherent would
|
||||
/// consume.
|
||||
fn process_inherent_data(
|
||||
data: ParachainsInherentData<T::Header>,
|
||||
) -> sp_std::result::Result<
|
||||
(ParachainsInherentData<T::Header>, PostDispatchInfo),
|
||||
DispatchErrorWithPostInfo,
|
||||
> {
|
||||
#[cfg(feature = "runtime-metrics")]
|
||||
sp_io::init_tracing();
|
||||
|
||||
let ParachainsInherentData {
|
||||
mut bitfields,
|
||||
mut backed_candidates,
|
||||
parent_header,
|
||||
mut disputes,
|
||||
} = data;
|
||||
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"[create_inherent_inner] bitfields.len(): {}, backed_candidates.len(): {}, disputes.len() {}",
|
||||
"[process_inherent_data] bitfields.len(): {}, backed_candidates.len(): {}, disputes.len() {}",
|
||||
bitfields.len(),
|
||||
backed_candidates.len(),
|
||||
disputes.len()
|
||||
@@ -565,13 +332,19 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
let parent_hash = <frame_system::Pallet<T>>::parent_hash();
|
||||
|
||||
if parent_hash != parent_header.hash() {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"ParachainsInherentData references a different parent header hash than frame"
|
||||
);
|
||||
return None
|
||||
}
|
||||
ensure!(
|
||||
parent_header.hash().as_ref() == parent_hash.as_ref(),
|
||||
Error::<T>::InvalidParentHeader,
|
||||
);
|
||||
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
|
||||
let candidates_weight = backed_candidates_weight::<T>(&backed_candidates);
|
||||
let bitfields_weight = signed_bitfields_weight::<T>(bitfields.len());
|
||||
let disputes_weight = multi_dispute_statement_sets_weight::<T, _, _>(&disputes);
|
||||
|
||||
METRICS
|
||||
.on_before_filter((candidates_weight + bitfields_weight + disputes_weight).ref_time());
|
||||
|
||||
let current_session = <shared::Pallet<T>>::session_index();
|
||||
let expected_bits = <scheduler::Pallet<T>>::availability_cores().len();
|
||||
@@ -582,181 +355,208 @@ impl<T: Config> Pallet<T> {
|
||||
let mut rng = rand_chacha::ChaChaRng::from_seed(entropy.into());
|
||||
|
||||
// Filter out duplicates and continue.
|
||||
if let Err(_) = T::DisputesHandler::deduplicate_and_sort_dispute_data(&mut disputes) {
|
||||
if let Err(()) = T::DisputesHandler::deduplicate_and_sort_dispute_data(&mut disputes) {
|
||||
log::debug!(target: LOG_TARGET, "Found duplicate statement sets, retaining the first");
|
||||
}
|
||||
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
let post_conclusion_acceptance_period = config.dispute_post_conclusion_acceptance_period;
|
||||
|
||||
// TODO: Better if we can convert this to `with_transactional` and handle an error if
|
||||
// too many transactional layers are spawned.
|
||||
let (
|
||||
mut backed_candidates,
|
||||
mut bitfields,
|
||||
checked_disputes_sets,
|
||||
checked_disputes_sets_consumed_weight,
|
||||
) = frame_support::storage::with_transaction_unchecked(|| {
|
||||
let dispute_statement_set_valid = move |set: DisputeStatementSet| {
|
||||
T::DisputesHandler::filter_dispute_data(
|
||||
set,
|
||||
post_conclusion_acceptance_period,
|
||||
// `DisputeCoordinator` on the node side only forwards
|
||||
// valid dispute statement sets and hence this does not
|
||||
// need to be checked.
|
||||
VerifyDisputeSignatures::Skip,
|
||||
)
|
||||
};
|
||||
let dispute_statement_set_valid = move |set: DisputeStatementSet| {
|
||||
T::DisputesHandler::filter_dispute_data(set, post_conclusion_acceptance_period)
|
||||
};
|
||||
|
||||
// Limit the disputes first, since the following statements depend on the votes include here.
|
||||
let (checked_disputes_sets, checked_disputes_sets_consumed_weight) =
|
||||
limit_and_sanitize_disputes::<T, _>(
|
||||
disputes,
|
||||
dispute_statement_set_valid,
|
||||
max_block_weight,
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
// we don't care about fresh or not disputes
|
||||
// this writes them to storage, so let's query it via those means
|
||||
// if this fails for whatever reason, that's ok
|
||||
let _ = T::DisputesHandler::process_checked_multi_dispute_data(&checked_disputes_sets)
|
||||
.map_err(|e| {
|
||||
log::warn!(target: LOG_TARGET, "MultiDisputesData failed to update: {:?}", e);
|
||||
e
|
||||
});
|
||||
|
||||
// Contains the disputes that are concluded in the current session only,
|
||||
// since these are the only ones that are relevant for the occupied cores
|
||||
// and lightens the load on `collect_disputed` significantly.
|
||||
// Cores can't be occupied with candidates of the previous sessions, and only
|
||||
// things with new votes can have just concluded. We only need to collect
|
||||
// cores with disputes that conclude just now, because disputes that
|
||||
// concluded longer ago have already had any corresponding cores cleaned up.
|
||||
let current_concluded_invalid_disputes = checked_disputes_sets
|
||||
.iter()
|
||||
.map(AsRef::as_ref)
|
||||
.filter(|dss| dss.session == current_session)
|
||||
.map(|dss| (dss.session, dss.candidate_hash))
|
||||
.filter(|(session, candidate)| {
|
||||
<T>::DisputesHandler::concluded_invalid(*session, *candidate)
|
||||
})
|
||||
.map(|(_session, candidate)| candidate)
|
||||
.collect::<BTreeSet<CandidateHash>>();
|
||||
|
||||
// All concluded invalid disputes, that are relevant for the set of candidates
|
||||
// the inherent provided.
|
||||
let concluded_invalid_disputes = backed_candidates
|
||||
.iter()
|
||||
.map(|backed_candidate| backed_candidate.hash())
|
||||
.filter(|candidate| {
|
||||
<T>::DisputesHandler::concluded_invalid(current_session, *candidate)
|
||||
})
|
||||
.collect::<BTreeSet<CandidateHash>>();
|
||||
|
||||
let mut freed_disputed: Vec<_> =
|
||||
<inclusion::Pallet<T>>::collect_disputed(¤t_concluded_invalid_disputes)
|
||||
.into_iter()
|
||||
.map(|core| (core, FreedReason::Concluded))
|
||||
.collect();
|
||||
|
||||
let disputed_bitfield =
|
||||
create_disputed_bitfield(expected_bits, freed_disputed.iter().map(|(x, _)| x));
|
||||
|
||||
if !freed_disputed.is_empty() {
|
||||
// unstable sort is fine, because core indices are unique
|
||||
// i.e. the same candidate can't occupy 2 cores at once.
|
||||
freed_disputed.sort_unstable_by_key(|pair| pair.0); // sort by core index
|
||||
<scheduler::Pallet<T>>::free_cores(freed_disputed.clone());
|
||||
}
|
||||
|
||||
// The following 3 calls are equiv to a call to `process_bitfields`
|
||||
// but we can retain access to `bitfields`.
|
||||
let bitfields = sanitize_bitfields::<T>(
|
||||
bitfields,
|
||||
disputed_bitfield,
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
current_session,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes,
|
||||
// Limit the disputes first, since the following statements depend on the votes include here.
|
||||
let (checked_disputes_sets, checked_disputes_sets_consumed_weight) =
|
||||
limit_and_sanitize_disputes::<T, _>(
|
||||
disputes,
|
||||
dispute_statement_set_valid,
|
||||
max_block_weight,
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
let freed_concluded =
|
||||
<inclusion::Pallet<T>>::update_pending_availability_and_get_freed_cores::<_>(
|
||||
expected_bits,
|
||||
&validator_public[..],
|
||||
bitfields.clone(),
|
||||
<scheduler::Pallet<T>>::core_para,
|
||||
false,
|
||||
);
|
||||
|
||||
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned());
|
||||
|
||||
<scheduler::Pallet<T>>::clear();
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
<scheduler::Pallet<T>>::schedule(freed, now);
|
||||
|
||||
let scheduled = <scheduler::Pallet<T>>::scheduled();
|
||||
|
||||
let relay_parent_number = now - One::one();
|
||||
let parent_storage_root = *parent_header.state_root();
|
||||
|
||||
let check_ctx = CandidateCheckContext::<T>::new(now, relay_parent_number);
|
||||
let backed_candidates = sanitize_backed_candidates::<T, _>(
|
||||
parent_hash,
|
||||
backed_candidates,
|
||||
move |candidate_idx: usize,
|
||||
backed_candidate: &BackedCandidate<<T as frame_system::Config>::Hash>|
|
||||
-> bool {
|
||||
// never include a concluded-invalid candidate
|
||||
concluded_invalid_disputes.contains(&backed_candidate.hash()) ||
|
||||
// Instead of checking the candidates with code upgrades twice
|
||||
// move the checking up here and skip it in the training wheels fallback.
|
||||
// That way we avoid possible duplicate checks while assuring all
|
||||
// backed candidates fine to pass on.
|
||||
check_ctx
|
||||
.verify_backed_candidate(parent_hash, parent_storage_root, candidate_idx, backed_candidate)
|
||||
.is_err()
|
||||
},
|
||||
&scheduled[..],
|
||||
);
|
||||
|
||||
frame_support::storage::TransactionOutcome::Rollback((
|
||||
// filtered backed candidates
|
||||
backed_candidates,
|
||||
// filtered bitfields
|
||||
bitfields,
|
||||
// checked disputes sets
|
||||
checked_disputes_sets,
|
||||
checked_disputes_sets_consumed_weight,
|
||||
))
|
||||
});
|
||||
|
||||
// Assure the maximum block weight is adhered, by limiting bitfields and backed
|
||||
// candidates. Dispute statement sets were already limited before.
|
||||
let actual_weight = apply_weight_limit::<T>(
|
||||
let non_disputes_weight = apply_weight_limit::<T>(
|
||||
&mut backed_candidates,
|
||||
&mut bitfields,
|
||||
max_block_weight.saturating_sub(checked_disputes_sets_consumed_weight),
|
||||
&mut rng,
|
||||
);
|
||||
|
||||
if actual_weight.any_gt(max_block_weight) {
|
||||
let full_weight = non_disputes_weight.saturating_add(checked_disputes_sets_consumed_weight);
|
||||
|
||||
METRICS.on_after_filter(full_weight.ref_time());
|
||||
|
||||
if full_weight.any_gt(max_block_weight) {
|
||||
log::warn!(target: LOG_TARGET, "Post weight limiting weight is still too large.");
|
||||
}
|
||||
|
||||
// Note that `process_checked_multi_dispute_data` will iterate and import each
|
||||
// dispute; so the input here must be reasonably bounded,
|
||||
// which is guaranteed by the checks and weight limitation above.
|
||||
// We don't care about fresh or not disputes
|
||||
// this writes them to storage, so let's query it via those means
|
||||
// if this fails for whatever reason, that's ok.
|
||||
if let Err(e) =
|
||||
T::DisputesHandler::process_checked_multi_dispute_data(&checked_disputes_sets)
|
||||
{
|
||||
log::warn!(target: LOG_TARGET, "MultiDisputesData failed to update: {:?}", e);
|
||||
};
|
||||
METRICS.on_disputes_imported(checked_disputes_sets.len() as u64);
|
||||
|
||||
set_scrapable_on_chain_disputes::<T>(current_session, checked_disputes_sets.clone());
|
||||
|
||||
if T::DisputesHandler::is_frozen() {
|
||||
// Relay chain freeze, at this point we will not include any parachain blocks.
|
||||
METRICS.on_relay_chain_freeze();
|
||||
|
||||
let disputes = checked_disputes_sets
|
||||
.into_iter()
|
||||
.map(|checked| checked.into())
|
||||
.collect::<Vec<_>>();
|
||||
let processed = ParachainsInherentData {
|
||||
bitfields: Vec::new(),
|
||||
backed_candidates: Vec::new(),
|
||||
disputes,
|
||||
parent_header,
|
||||
};
|
||||
|
||||
// The relay chain we are currently on is invalid. Proceed no further on parachains.
|
||||
return Ok((processed, Some(checked_disputes_sets_consumed_weight).into()))
|
||||
}
|
||||
|
||||
// Contains the disputes that are concluded in the current session only,
|
||||
// since these are the only ones that are relevant for the occupied cores
|
||||
// and lightens the load on `collect_disputed` significantly.
|
||||
// Cores can't be occupied with candidates of the previous sessions, and only
|
||||
// things with new votes can have just concluded. We only need to collect
|
||||
// cores with disputes that conclude just now, because disputes that
|
||||
// concluded longer ago have already had any corresponding cores cleaned up.
|
||||
let current_concluded_invalid_disputes = checked_disputes_sets
|
||||
.iter()
|
||||
.map(AsRef::as_ref)
|
||||
.filter(|dss| dss.session == current_session)
|
||||
.map(|dss| (dss.session, dss.candidate_hash))
|
||||
.filter(|(session, candidate)| {
|
||||
<T>::DisputesHandler::concluded_invalid(*session, *candidate)
|
||||
})
|
||||
.map(|(_session, candidate)| candidate)
|
||||
.collect::<BTreeSet<CandidateHash>>();
|
||||
|
||||
let mut freed_disputed: Vec<_> =
|
||||
<inclusion::Pallet<T>>::collect_disputed(¤t_concluded_invalid_disputes)
|
||||
.into_iter()
|
||||
.map(|core| (core, FreedReason::Concluded))
|
||||
.collect();
|
||||
|
||||
// Create a bit index from the set of core indices where each index corresponds to
|
||||
// a core index that was freed due to a dispute.
|
||||
//
|
||||
// I.e. 010100 would indicate, the candidates on Core 1 and 3 would be disputed.
|
||||
let disputed_bitfield = create_disputed_bitfield(
|
||||
expected_bits,
|
||||
freed_disputed.iter().map(|(core_index, _)| core_index),
|
||||
);
|
||||
|
||||
if !freed_disputed.is_empty() {
|
||||
// unstable sort is fine, because core indices are unique
|
||||
// i.e. the same candidate can't occupy 2 cores at once.
|
||||
freed_disputed.sort_unstable_by_key(|pair| pair.0); // sort by core index
|
||||
<scheduler::Pallet<T>>::free_cores(freed_disputed.clone());
|
||||
}
|
||||
|
||||
let bitfields = sanitize_bitfields::<T>(
|
||||
bitfields,
|
||||
disputed_bitfield,
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
current_session,
|
||||
&validator_public[..],
|
||||
);
|
||||
METRICS.on_bitfields_processed(bitfields.len() as u64);
|
||||
|
||||
// Process new availability bitfields, yielding any availability cores whose
|
||||
// work has now concluded.
|
||||
let freed_concluded =
|
||||
<inclusion::Pallet<T>>::update_pending_availability_and_get_freed_cores::<_>(
|
||||
expected_bits,
|
||||
&validator_public[..],
|
||||
bitfields.clone(),
|
||||
<scheduler::Pallet<T>>::core_para,
|
||||
);
|
||||
|
||||
// Inform the disputes module of all included candidates.
|
||||
for (_, candidate_hash) in &freed_concluded {
|
||||
T::DisputesHandler::note_included(current_session, *candidate_hash, now);
|
||||
}
|
||||
|
||||
METRICS.on_candidates_included(freed_concluded.len() as u64);
|
||||
|
||||
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned());
|
||||
|
||||
<scheduler::Pallet<T>>::clear();
|
||||
<scheduler::Pallet<T>>::schedule(freed, now);
|
||||
|
||||
let scheduled = <scheduler::Pallet<T>>::scheduled();
|
||||
|
||||
let relay_parent_number = now - One::one();
|
||||
let parent_storage_root = *parent_header.state_root();
|
||||
|
||||
let check_ctx = CandidateCheckContext::<T>::new(now, relay_parent_number);
|
||||
|
||||
METRICS.on_candidates_processed_total(backed_candidates.len() as u64);
|
||||
|
||||
let backed_candidates = sanitize_backed_candidates::<T, _>(
|
||||
parent_hash,
|
||||
backed_candidates,
|
||||
move |candidate_idx: usize,
|
||||
backed_candidate: &BackedCandidate<<T as frame_system::Config>::Hash>|
|
||||
-> bool {
|
||||
// never include a concluded-invalid candidate
|
||||
current_concluded_invalid_disputes.contains(&backed_candidate.hash()) ||
|
||||
// Instead of checking the candidates with code upgrades twice
|
||||
// move the checking up here and skip it in the training wheels fallback.
|
||||
// That way we avoid possible duplicate checks while assuring all
|
||||
// backed candidates fine to pass on.
|
||||
check_ctx
|
||||
.verify_backed_candidate(parent_hash, parent_storage_root, candidate_idx, backed_candidate)
|
||||
.is_err()
|
||||
},
|
||||
&scheduled[..],
|
||||
);
|
||||
|
||||
METRICS.on_candidates_sanitized(backed_candidates.len() as u64);
|
||||
|
||||
// Process backed candidates according to scheduled cores.
|
||||
let parent_storage_root = *parent_header.state_root();
|
||||
let inclusion::ProcessedCandidates::<<T::Header as HeaderT>::Hash> {
|
||||
core_indices: occupied,
|
||||
candidate_receipt_with_backing_validator_indices,
|
||||
} = <inclusion::Pallet<T>>::process_candidates(
|
||||
parent_storage_root,
|
||||
backed_candidates.clone(),
|
||||
scheduled,
|
||||
<scheduler::Pallet<T>>::group_validators,
|
||||
)?;
|
||||
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
||||
<scheduler::Pallet<T>>::occupied(&occupied);
|
||||
|
||||
set_scrapable_on_chain_backings::<T>(
|
||||
current_session,
|
||||
candidate_receipt_with_backing_validator_indices,
|
||||
);
|
||||
|
||||
let disputes = checked_disputes_sets
|
||||
.into_iter()
|
||||
.map(|checked| checked.into())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Some(ParachainsInherentData::<T::Header> {
|
||||
bitfields,
|
||||
backed_candidates,
|
||||
disputes,
|
||||
parent_header,
|
||||
})
|
||||
let bitfields = bitfields.into_iter().map(|v| v.into_unchecked()).collect();
|
||||
|
||||
let processed =
|
||||
ParachainsInherentData { bitfields, backed_candidates, disputes, parent_header };
|
||||
Ok((processed, Some(full_weight).into()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,13 +729,6 @@ fn apply_weight_limit<T: Config + inclusion::Config>(
|
||||
/// 5. remove any disputed core indices
|
||||
///
|
||||
/// If any of those is not passed, the bitfield is dropped.
|
||||
///
|
||||
/// While this function technically returns a set of unchecked bitfields,
|
||||
/// they were actually checked and filtered to allow using it in both
|
||||
/// cases, as `filtering` and `checking` stage.
|
||||
///
|
||||
/// `full_check` determines if validator signatures are checked. If `::Yes`,
|
||||
/// bitfields that have an invalid signature will be filtered out.
|
||||
pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
unchecked_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
disputed_bitfield: DisputedBitfield,
|
||||
@@ -943,8 +736,7 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
parent_hash: T::Hash,
|
||||
session_index: SessionIndex,
|
||||
validators: &[ValidatorId],
|
||||
full_check: FullCheck,
|
||||
) -> UncheckedSignedAvailabilityBitfields {
|
||||
) -> SignedAvailabilityBitfields {
|
||||
let mut bitfields = Vec::with_capacity(unchecked_bitfields.len());
|
||||
|
||||
let mut last_index: Option<ValidatorIndex> = None;
|
||||
@@ -963,8 +755,7 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
if unchecked_bitfield.unchecked_payload().0.len() != expected_bits {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"[{:?}] bad bitfield length: {} != {:?}",
|
||||
full_check,
|
||||
"bad bitfield length: {} != {:?}",
|
||||
unchecked_bitfield.unchecked_payload().0.len(),
|
||||
expected_bits,
|
||||
);
|
||||
@@ -976,8 +767,7 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
{
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"[{:?}] bitfield contains disputed cores: {:?}",
|
||||
full_check,
|
||||
"bitfield contains disputed cores: {:?}",
|
||||
unchecked_bitfield.unchecked_payload().0.clone() & disputed_bitfield.0.clone()
|
||||
);
|
||||
continue
|
||||
@@ -988,8 +778,7 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
if !last_index.map_or(true, |last_index: ValidatorIndex| last_index < validator_index) {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"[{:?}] bitfield validator index is not greater than last: !({:?} < {})",
|
||||
full_check,
|
||||
"bitfield validator index is not greater than last: !({:?} < {})",
|
||||
last_index.as_ref().map(|x| x.0),
|
||||
validator_index.0
|
||||
);
|
||||
@@ -999,8 +788,7 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
if unchecked_bitfield.unchecked_validator_index().0 as usize >= validators.len() {
|
||||
log::trace!(
|
||||
target: LOG_TARGET,
|
||||
"[{:?}] bitfield validator index is out of bounds: {} >= {}",
|
||||
full_check,
|
||||
"bitfield validator index is out of bounds: {} >= {}",
|
||||
validator_index.0,
|
||||
validators.len(),
|
||||
);
|
||||
@@ -1009,81 +797,22 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
|
||||
|
||||
let validator_public = &validators[validator_index.0 as usize];
|
||||
|
||||
if let FullCheck::Yes = full_check {
|
||||
// Validate bitfield signature.
|
||||
if let Ok(signed_bitfield) =
|
||||
unchecked_bitfield.try_into_checked(&signing_context, validator_public)
|
||||
{
|
||||
bitfields.push(signed_bitfield.into_unchecked());
|
||||
METRICS.on_valid_bitfield_signature();
|
||||
} else {
|
||||
log::warn!(target: LOG_TARGET, "Invalid bitfield signature");
|
||||
METRICS.on_invalid_bitfield_signature();
|
||||
};
|
||||
// Validate bitfield signature.
|
||||
if let Ok(signed_bitfield) =
|
||||
unchecked_bitfield.try_into_checked(&signing_context, validator_public)
|
||||
{
|
||||
bitfields.push(signed_bitfield);
|
||||
METRICS.on_valid_bitfield_signature();
|
||||
} else {
|
||||
bitfields.push(unchecked_bitfield);
|
||||
}
|
||||
log::warn!(target: LOG_TARGET, "Invalid bitfield signature");
|
||||
METRICS.on_invalid_bitfield_signature();
|
||||
};
|
||||
|
||||
last_index = Some(validator_index);
|
||||
}
|
||||
bitfields
|
||||
}
|
||||
|
||||
pub(crate) fn assure_sanity_bitfields<T: crate::inclusion::Config>(
|
||||
unchecked_bitfields: UncheckedSignedAvailabilityBitfields,
|
||||
disputed_bitfield: DisputedBitfield,
|
||||
expected_bits: usize,
|
||||
parent_hash: T::Hash,
|
||||
session_index: SessionIndex,
|
||||
validators: &[ValidatorId],
|
||||
full_check: FullCheck,
|
||||
) -> Result<UncheckedSignedAvailabilityBitfields, crate::inclusion::Error<T>> {
|
||||
let mut last_index: Option<ValidatorIndex> = None;
|
||||
|
||||
use crate::inclusion::Error;
|
||||
|
||||
ensure!(disputed_bitfield.0.len() == expected_bits, Error::<T>::WrongBitfieldSize);
|
||||
|
||||
let mut bitfields = Vec::with_capacity(unchecked_bitfields.len());
|
||||
|
||||
let signing_context = SigningContext { parent_hash, session_index };
|
||||
for unchecked_bitfield in unchecked_bitfields {
|
||||
// Find and skip invalid bitfields.
|
||||
ensure!(
|
||||
unchecked_bitfield.unchecked_payload().0.len() == expected_bits,
|
||||
Error::<T>::WrongBitfieldSize
|
||||
);
|
||||
|
||||
let validator_index = unchecked_bitfield.unchecked_validator_index();
|
||||
|
||||
if !last_index.map_or(true, |last_index: ValidatorIndex| last_index < validator_index) {
|
||||
return Err(Error::<T>::UnsortedOrDuplicateValidatorIndices)
|
||||
}
|
||||
|
||||
if unchecked_bitfield.unchecked_validator_index().0 as usize >= validators.len() {
|
||||
return Err(Error::<T>::ValidatorIndexOutOfBounds)
|
||||
}
|
||||
|
||||
let validator_public = &validators[validator_index.0 as usize];
|
||||
|
||||
if let FullCheck::Yes = full_check {
|
||||
// Validate bitfield signature.
|
||||
if let Ok(signed_bitfield) =
|
||||
unchecked_bitfield.try_into_checked(&signing_context, validator_public)
|
||||
{
|
||||
bitfields.push(signed_bitfield.into_unchecked());
|
||||
} else {
|
||||
return Err(Error::<T>::InvalidBitfieldSignature)
|
||||
}
|
||||
} else {
|
||||
bitfields.push(unchecked_bitfield);
|
||||
}
|
||||
|
||||
last_index = Some(validator_index);
|
||||
}
|
||||
Ok(bitfields)
|
||||
}
|
||||
|
||||
/// Filter out any candidates that have a concluded invalid dispute.
|
||||
///
|
||||
/// `scheduled` follows the same naming scheme as provided in the
|
||||
@@ -1139,46 +868,6 @@ fn sanitize_backed_candidates<
|
||||
backed_candidates
|
||||
}
|
||||
|
||||
/// Assumes sorted candidates.
|
||||
pub(crate) fn assure_sanity_backed_candidates<
|
||||
T: crate::inclusion::Config,
|
||||
F: FnMut(usize, &BackedCandidate<T::Hash>) -> bool,
|
||||
>(
|
||||
relay_parent: T::Hash,
|
||||
backed_candidates: &[BackedCandidate<T::Hash>],
|
||||
mut candidate_has_concluded_invalid_dispute_or_is_invalid: F,
|
||||
scheduled: &[CoreAssignment],
|
||||
) -> Result<(), crate::inclusion::Error<T>> {
|
||||
use crate::inclusion::Error;
|
||||
|
||||
for (idx, backed_candidate) in backed_candidates.iter().enumerate() {
|
||||
if candidate_has_concluded_invalid_dispute_or_is_invalid(idx, backed_candidate) {
|
||||
return Err(Error::<T>::UnsortedOrDuplicateBackedCandidates)
|
||||
}
|
||||
// Assure the backed candidate's `ParaId`'s core is free.
|
||||
// This holds under the assumption that `Scheduler::schedule` is called _before_.
|
||||
// Also checks the candidate references the correct relay parent.
|
||||
let desc = backed_candidate.descriptor();
|
||||
if desc.relay_parent != relay_parent {
|
||||
return Err(Error::<T>::UnexpectedRelayParent)
|
||||
}
|
||||
}
|
||||
|
||||
let scheduled_paras_to_core_idx = scheduled
|
||||
.into_iter()
|
||||
.map(|core_assignment| (core_assignment.para_id, core_assignment.core))
|
||||
.collect::<BTreeMap<ParaId, CoreIndex>>();
|
||||
|
||||
if !IsSortedBy::is_sorted_by(backed_candidates, |x, y| {
|
||||
// Never panics, since we would have early returned on those in the above loop.
|
||||
scheduled_paras_to_core_idx[&x.descriptor().para_id]
|
||||
.cmp(&scheduled_paras_to_core_idx[&y.descriptor().para_id])
|
||||
}) {
|
||||
return Err(Error::<T>::UnsortedOrDuplicateBackedCandidates)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Derive entropy from babe provided per block randomness.
|
||||
///
|
||||
/// In the odd case none is available, uses the `parent_hash` and
|
||||
|
||||
@@ -111,16 +111,6 @@ mod enter {
|
||||
expected_para_inherent_data
|
||||
);
|
||||
|
||||
// The schedule is still empty prior to calling `enter`. (`create_inherent_inner` should not
|
||||
// alter storage, but just double checking for sanity).
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None);
|
||||
// Call enter with our 2 backed candidates
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
expected_para_inherent_data
|
||||
));
|
||||
assert_eq!(
|
||||
// The length of this vec is equal to the number of candidates, so we know our 2
|
||||
// backed candidates did not get filtered out
|
||||
@@ -286,12 +276,6 @@ mod enter {
|
||||
&expected_para_inherent_data.disputes[..2],
|
||||
);
|
||||
|
||||
// The schedule is still empty prior to calling `enter`. (`create_inherent_inner` should not
|
||||
// alter storage, but just double checking for sanity).
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None);
|
||||
// Call enter with our 2 disputes
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
multi_dispute_inherent_data,
|
||||
@@ -357,12 +341,6 @@ mod enter {
|
||||
assert_eq!(limit_inherent_data.disputes[0].session, 1);
|
||||
assert_eq!(limit_inherent_data.disputes[1].session, 2);
|
||||
|
||||
// The schedule is still empty prior to calling `enter`. (`create_inherent_inner` should not
|
||||
// alter storage, but just double checking for sanity).
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None);
|
||||
// Call enter with our 2 disputes
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
limit_inherent_data,
|
||||
@@ -382,51 +360,6 @@ mod enter {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that when dispute data establishes an over weight block that we abort
|
||||
// due to an over weight block
|
||||
fn limit_dispute_data_overweight() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// Create the inherent data for this block
|
||||
let dispute_statements = BTreeMap::new();
|
||||
// No backed and concluding cores, so all cores will be filled with disputes.
|
||||
let backed_and_concluding = BTreeMap::new();
|
||||
|
||||
let scenario = make_inherent_data(TestConfig {
|
||||
dispute_statements,
|
||||
dispute_sessions: vec![2, 2, 1], // 3 cores with disputes
|
||||
backed_and_concluding,
|
||||
num_validators_per_core: 6,
|
||||
code_upgrade: None,
|
||||
});
|
||||
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (6 validators per core, 3 disputes => 18 validators)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 18);
|
||||
// * 0 backed candidate per core
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 0);
|
||||
// * 3 disputes.
|
||||
assert_eq!(expected_para_inherent_data.disputes.len(), 3);
|
||||
let mut inherent_data = InherentData::new();
|
||||
inherent_data
|
||||
.put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data)
|
||||
.unwrap();
|
||||
|
||||
// The current schedule is empty prior to calling `create_inherent_enter`.
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_matches!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
expected_para_inherent_data,
|
||||
), Err(e) => { dbg!(e) });
|
||||
|
||||
// The block was not included, as such, `on_chain_votes` _must_ return `None`.
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None,);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that when a block is over weight due to disputes, but there is still sufficient
|
||||
// block weight to include a number of signed bitfields, the inherent data is filtered
|
||||
@@ -484,12 +417,6 @@ mod enter {
|
||||
// Ensure that all backed candidates are filtered out as either would make the block over weight
|
||||
assert_eq!(limit_inherent_data.backed_candidates.len(), 0);
|
||||
|
||||
// The schedule is still empty prior to calling `enter`. (`create_inherent_inner` should not
|
||||
// alter storage, but just double checking for sanity).
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None);
|
||||
// Call enter with our 2 disputes
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
limit_inherent_data,
|
||||
@@ -510,56 +437,6 @@ mod enter {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that we abort if we encounter an over weight block for disputes + bitfields
|
||||
fn limit_dispute_data_ignore_backed_candidates_overweight() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// Create the inherent data for this block
|
||||
let dispute_statements = BTreeMap::new();
|
||||
|
||||
let mut backed_and_concluding = BTreeMap::new();
|
||||
// 2 backed candidates shall be scheduled
|
||||
backed_and_concluding.insert(0, 2);
|
||||
backed_and_concluding.insert(1, 2);
|
||||
|
||||
let scenario = make_inherent_data(TestConfig {
|
||||
dispute_statements,
|
||||
dispute_sessions: vec![2, 2, 1], // 3 cores with disputes
|
||||
backed_and_concluding,
|
||||
num_validators_per_core: 4,
|
||||
code_upgrade: None,
|
||||
});
|
||||
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (4 validators per core, 2 backed candidates, 3 disputes => 4*5 = 20)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 20);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
// * 3 disputes.
|
||||
assert_eq!(expected_para_inherent_data.disputes.len(), 3);
|
||||
let mut inherent_data = InherentData::new();
|
||||
inherent_data
|
||||
.put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data)
|
||||
.unwrap();
|
||||
|
||||
// The current schedule is empty prior to calling `create_inherent_enter`.
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
// Ensure that calling enter with 3 disputes and 2 candidates is over weight
|
||||
assert_matches!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
expected_para_inherent_data,
|
||||
), Err(e) => {
|
||||
dbg!(e)
|
||||
});
|
||||
|
||||
// The block was not included, as such, `on_chain_votes` _must_ return `None`.
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None,);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure an overweight block with an excess amount of disputes and bitfields, the bitfields are
|
||||
// filtered to accommodate the block size and no backed candidates are included.
|
||||
@@ -621,12 +498,6 @@ mod enter {
|
||||
// Ensure that all backed candidates are filtered out as either would make the block over weight
|
||||
assert_eq!(limit_inherent_data.backed_candidates.len(), 0);
|
||||
|
||||
// The schedule is still empty prior to calling `enter`. (`create_inherent_inner` should not
|
||||
// alter storage, but just double checking for sanity).
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_eq!(Pallet::<Test>::on_chain_votes(), None);
|
||||
// Call enter with our 2 disputes
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
limit_inherent_data,
|
||||
@@ -648,7 +519,7 @@ mod enter {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that when a block is over weight due to disputes and bitfields, we abort
|
||||
// Ensure that when a block is over weight due to disputes and bitfields, we filter.
|
||||
fn limit_bitfields_overweight() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// Create the inherent data for this block
|
||||
@@ -686,18 +557,11 @@ mod enter {
|
||||
.put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data)
|
||||
.unwrap();
|
||||
|
||||
// The current schedule is empty prior to calling `create_inherent_enter`.
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_matches!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
expected_para_inherent_data,
|
||||
), Err(_e) => {
|
||||
/* TODO */
|
||||
});
|
||||
|
||||
// The block was not included, as such, `on_chain_votes` _must_ return `None`.
|
||||
assert_matches!(Pallet::<Test>::on_chain_votes(), None);
|
||||
let limit_inherent_data =
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
assert_eq!(limit_inherent_data.bitfields.len(), 20);
|
||||
assert_eq!(limit_inherent_data.disputes.len(), 2);
|
||||
assert_eq!(limit_inherent_data.backed_candidates.len(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -733,7 +597,7 @@ mod enter {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that when a block is over weight due to disputes and bitfields, we abort
|
||||
// Ensure that when a block is over weight due to disputes and bitfields, we filter.
|
||||
fn limit_candidates_over_weight_1() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// Create the inherent data for this block
|
||||
@@ -790,9 +654,6 @@ mod enter {
|
||||
// * 3 disputes.
|
||||
assert_eq!(limit_inherent_data.disputes.len(), 2);
|
||||
|
||||
// The current schedule is empty prior to calling `create_inherent_enter`.
|
||||
assert_eq!(<scheduler::Pallet<Test>>::scheduled(), vec![]);
|
||||
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
limit_inherent_data,
|
||||
@@ -812,51 +673,6 @@ mod enter {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Ensure that when a block is over weight due to disputes and bitfields, we abort
|
||||
fn limit_candidates_over_weight_0() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
// Create the inherent data for this block
|
||||
let mut dispute_statements = BTreeMap::new();
|
||||
// Control the number of statements per dispute to ensure we have enough space
|
||||
// in the block for some (but not all) bitfields
|
||||
dispute_statements.insert(2, 17);
|
||||
dispute_statements.insert(3, 17);
|
||||
dispute_statements.insert(4, 17);
|
||||
|
||||
let mut backed_and_concluding = BTreeMap::new();
|
||||
// 2 backed candidates shall be scheduled
|
||||
backed_and_concluding.insert(0, 16);
|
||||
backed_and_concluding.insert(1, 25);
|
||||
|
||||
let scenario = make_inherent_data(TestConfig {
|
||||
dispute_statements,
|
||||
dispute_sessions: vec![2, 2, 1], // 3 cores with disputes
|
||||
backed_and_concluding,
|
||||
num_validators_per_core: 5,
|
||||
code_upgrade: None,
|
||||
});
|
||||
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 5*5 = 25)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 25);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
// * 3 disputes.
|
||||
assert_eq!(expected_para_inherent_data.disputes.len(), 3);
|
||||
|
||||
assert_matches!(Pallet::<Test>::enter(
|
||||
frame_system::RawOrigin::None.into(),
|
||||
expected_para_inherent_data,
|
||||
), Err(e) => { dbg!(e) });
|
||||
|
||||
// The block was not included, as such, `on_chain_votes` _must_ return `None`.
|
||||
assert_matches!(Pallet::<Test>::on_chain_votes(), None);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn default_header() -> primitives::Header {
|
||||
@@ -921,7 +737,7 @@ mod sanitizers {
|
||||
}
|
||||
let validator_public = validator_pubkeys(&validators);
|
||||
|
||||
let unchecked_bitfields = [
|
||||
let checked_bitfields = [
|
||||
BitVec::<u8, Lsb0>::repeat(true, expected_bits),
|
||||
BitVec::<u8, Lsb0>::repeat(true, expected_bits),
|
||||
{
|
||||
@@ -943,9 +759,14 @@ mod sanitizers {
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.into_unchecked()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Vec<SignedAvailabilityBitfield>>();
|
||||
|
||||
let unchecked_bitfields = checked_bitfields
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|v| v.into_unchecked())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let disputed_bitfield = DisputedBitfield::zeros(expected_bits);
|
||||
|
||||
@@ -958,9 +779,8 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Skip,
|
||||
),
|
||||
unchecked_bitfields.clone()
|
||||
checked_bitfields.clone()
|
||||
);
|
||||
assert_eq!(
|
||||
sanitize_bitfields::<Test>(
|
||||
@@ -970,9 +790,8 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes
|
||||
),
|
||||
unchecked_bitfields.clone()
|
||||
checked_bitfields.clone()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -991,7 +810,6 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes
|
||||
)
|
||||
.len(),
|
||||
1
|
||||
@@ -1004,7 +822,6 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Skip
|
||||
)
|
||||
.len(),
|
||||
1
|
||||
@@ -1020,7 +837,6 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes
|
||||
)
|
||||
.is_empty());
|
||||
assert!(sanitize_bitfields::<Test>(
|
||||
@@ -1030,7 +846,6 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Skip
|
||||
)
|
||||
.is_empty());
|
||||
}
|
||||
@@ -1046,9 +861,8 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..shortened],
|
||||
FullCheck::Yes,
|
||||
)[..],
|
||||
&unchecked_bitfields[..shortened]
|
||||
&checked_bitfields[..shortened]
|
||||
);
|
||||
assert_eq!(
|
||||
&sanitize_bitfields::<Test>(
|
||||
@@ -1058,9 +872,8 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..shortened],
|
||||
FullCheck::Skip,
|
||||
)[..],
|
||||
&unchecked_bitfields[..shortened]
|
||||
&checked_bitfields[..shortened]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1069,30 +882,18 @@ mod sanitizers {
|
||||
let mut unchecked_bitfields = unchecked_bitfields.clone();
|
||||
let x = unchecked_bitfields.swap_remove(0);
|
||||
unchecked_bitfields.push(x);
|
||||
assert_eq!(
|
||||
&sanitize_bitfields::<Test>(
|
||||
unchecked_bitfields.clone(),
|
||||
disputed_bitfield.clone(),
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes
|
||||
)[..],
|
||||
&unchecked_bitfields[..(unchecked_bitfields.len() - 2)]
|
||||
);
|
||||
assert_eq!(
|
||||
&sanitize_bitfields::<Test>(
|
||||
unchecked_bitfields.clone(),
|
||||
disputed_bitfield.clone(),
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Skip
|
||||
)[..],
|
||||
&unchecked_bitfields[..(unchecked_bitfields.len() - 2)]
|
||||
);
|
||||
let result: UncheckedSignedAvailabilityBitfields = sanitize_bitfields::<Test>(
|
||||
unchecked_bitfields.clone(),
|
||||
disputed_bitfield.clone(),
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
)
|
||||
.into_iter()
|
||||
.map(|v| v.into_unchecked())
|
||||
.collect();
|
||||
assert_eq!(&result, &unchecked_bitfields[..(unchecked_bitfields.len() - 2)]);
|
||||
}
|
||||
|
||||
// check the validators signature
|
||||
@@ -1113,21 +914,30 @@ mod sanitizers {
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Yes
|
||||
)[..],
|
||||
&unchecked_bitfields[..last_bit_idx]
|
||||
&checked_bitfields[..last_bit_idx]
|
||||
);
|
||||
}
|
||||
// duplicate bitfields
|
||||
{
|
||||
let mut unchecked_bitfields = unchecked_bitfields.clone();
|
||||
|
||||
// insert a bad signature for the last bitfield
|
||||
let last_bit_idx = unchecked_bitfields.len() - 1;
|
||||
unchecked_bitfields
|
||||
.get_mut(last_bit_idx)
|
||||
.and_then(|u| Some(u.set_signature(UncheckedFrom::unchecked_from([1u8; 64]))))
|
||||
.expect("we are accessing a valid index");
|
||||
assert_eq!(
|
||||
&sanitize_bitfields::<Test>(
|
||||
unchecked_bitfields.clone(),
|
||||
unchecked_bitfields.clone().into_iter().chain(unchecked_bitfields).collect(),
|
||||
disputed_bitfield.clone(),
|
||||
expected_bits,
|
||||
parent_hash,
|
||||
session_index,
|
||||
&validator_public[..],
|
||||
FullCheck::Skip
|
||||
)[..],
|
||||
&unchecked_bitfields[..]
|
||||
&checked_bitfields[..last_bit_idx]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,24 +17,26 @@
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-06-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("polkadot-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// target/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=polkadot-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --chain=polkadot-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/polkadot/src/weights/runtime_parachains_paras_inherent.rs
|
||||
// --output=./runtime/polkadot/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -53,18 +55,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo Sessions (r:1 w:0)
|
||||
/// Proof Skipped: ParaSessionInfo Sessions (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes BackersOnDisputes (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Included (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -75,12 +79,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen)
|
||||
/// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
@@ -93,8 +97,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
@@ -114,11 +116,11 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `50915`
|
||||
// Estimated: `56855 + v * (23 ±0)`
|
||||
// Minimum execution time: 767_508_000 picoseconds.
|
||||
Weight::from_parts(298_394_077, 0)
|
||||
// Minimum execution time: 813_782_000 picoseconds.
|
||||
Weight::from_parts(342_553_675, 0)
|
||||
.saturating_add(Weight::from_parts(0, 56855))
|
||||
// Standard Error: 19_865
|
||||
.saturating_add(Weight::from_parts(48_079_769, 0).saturating_mul(v.into()))
|
||||
// Standard Error: 26_456
|
||||
.saturating_add(Weight::from_parts(48_553_593, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(28))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
.saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into()))
|
||||
@@ -129,20 +131,22 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -161,8 +165,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
@@ -187,8 +189,8 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42748`
|
||||
// Estimated: `48688`
|
||||
// Minimum execution time: 324_159_000 picoseconds.
|
||||
Weight::from_parts(331_096_000, 0)
|
||||
// Minimum execution time: 361_186_000 picoseconds.
|
||||
Weight::from_parts(371_834_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48688))
|
||||
.saturating_add(T::DbWeight::get().reads(26))
|
||||
.saturating_add(T::DbWeight::get().writes(16))
|
||||
@@ -199,20 +201,22 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -231,9 +235,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -262,12 +264,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42784`
|
||||
// Estimated: `48724`
|
||||
// Minimum execution time: 5_551_865_000 picoseconds.
|
||||
Weight::from_parts(784_879_818, 0)
|
||||
// Minimum execution time: 5_751_598_000 picoseconds.
|
||||
Weight::from_parts(994_531_629, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48724))
|
||||
// Standard Error: 37_120
|
||||
.saturating_add(Weight::from_parts(47_603_511, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(30))
|
||||
// Standard Error: 52_254
|
||||
.saturating_add(Weight::from_parts(48_035_531, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(29))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
/// Storage: ParaInherent Included (r:1 w:1)
|
||||
@@ -276,20 +278,22 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: Configuration ActiveConfig (r:1 w:0)
|
||||
/// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -308,9 +312,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -342,10 +344,10 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42811`
|
||||
// Estimated: `48751`
|
||||
// Minimum execution time: 32_605_022_000 picoseconds.
|
||||
Weight::from_parts(32_862_445_000, 0)
|
||||
// Minimum execution time: 33_397_333_000 picoseconds.
|
||||
Weight::from_parts(34_386_874_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48751))
|
||||
.saturating_add(T::DbWeight::get().reads(32))
|
||||
.saturating_add(T::DbWeight::get().reads(31))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,24 +17,26 @@
|
||||
//! Autogenerated weights for `runtime_parachains::paras_inherent`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
|
||||
//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! DATE: 2023-06-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz`
|
||||
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024
|
||||
|
||||
// Executed Command:
|
||||
// ./target/production/polkadot
|
||||
// target/production/polkadot
|
||||
// benchmark
|
||||
// pallet
|
||||
// --chain=westend-dev
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --extrinsic=*
|
||||
// --execution=wasm
|
||||
// --wasm-execution=compiled
|
||||
// --heap-pages=4096
|
||||
// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/polkadot/.git/.artifacts/bench.json
|
||||
// --pallet=runtime_parachains::paras_inherent
|
||||
// --chain=westend-dev
|
||||
// --header=./file_header.txt
|
||||
// --output=./runtime/westend/src/weights/runtime_parachains_paras_inherent.rs
|
||||
// --output=./runtime/westend/src/weights/
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
@@ -53,6 +55,10 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaSessionInfo Sessions (r:1 w:0)
|
||||
@@ -61,8 +67,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes BackersOnDisputes (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Included (r:1 w:1)
|
||||
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -73,12 +77,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen)
|
||||
/// Storage: Staking ErasRewardPoints (r:1 w:1)
|
||||
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
@@ -91,8 +95,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1)
|
||||
@@ -112,11 +114,11 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `50518`
|
||||
// Estimated: `56458 + v * (23 ±0)`
|
||||
// Minimum execution time: 755_127_000 picoseconds.
|
||||
Weight::from_parts(279_514_953, 0)
|
||||
// Minimum execution time: 787_742_000 picoseconds.
|
||||
Weight::from_parts(323_859_708, 0)
|
||||
.saturating_add(Weight::from_parts(0, 56458))
|
||||
// Standard Error: 27_909
|
||||
.saturating_add(Weight::from_parts(48_567_316, 0).saturating_mul(v.into()))
|
||||
// Standard Error: 23_358
|
||||
.saturating_add(Weight::from_parts(48_375_660, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(27))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
.saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into()))
|
||||
@@ -127,18 +129,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -157,8 +161,6 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
@@ -183,8 +185,8 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42352`
|
||||
// Estimated: `48292`
|
||||
// Minimum execution time: 316_856_000 picoseconds.
|
||||
Weight::from_parts(324_523_000, 0)
|
||||
// Minimum execution time: 356_545_000 picoseconds.
|
||||
Weight::from_parts(362_497_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48292))
|
||||
.saturating_add(T::DbWeight::get().reads(25))
|
||||
.saturating_add(T::DbWeight::get().writes(16))
|
||||
@@ -195,18 +197,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -225,9 +229,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -256,12 +258,12 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42387`
|
||||
// Estimated: `48327`
|
||||
// Minimum execution time: 5_544_322_000 picoseconds.
|
||||
Weight::from_parts(805_988_490, 0)
|
||||
// Minimum execution time: 5_733_399_000 picoseconds.
|
||||
Weight::from_parts(975_216_648, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48327))
|
||||
// Standard Error: 43_249
|
||||
.saturating_add(Weight::from_parts(47_856_057, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(29))
|
||||
// Standard Error: 56_805
|
||||
.saturating_add(Weight::from_parts(47_900_476, 0).saturating_mul(v.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(28))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
/// Storage: ParaInherent Included (r:1 w:1)
|
||||
@@ -270,18 +272,20 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
|
||||
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1)
|
||||
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0)
|
||||
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: Babe AuthorVrfRandomness (r:1 w:0)
|
||||
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Frozen (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailability (r:2 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras Parachains (r:1 w:0)
|
||||
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1)
|
||||
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0)
|
||||
@@ -300,9 +304,7 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: Paras FutureCodeUpgrades (r:1 w:0)
|
||||
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaInherent OnChainVotes (r:1 w:1)
|
||||
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured)
|
||||
/// Storage: ParasDisputes Disputes (r:2 w:0)
|
||||
/// Storage: ParasDisputes Disputes (r:1 w:0)
|
||||
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured)
|
||||
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0)
|
||||
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured)
|
||||
@@ -334,10 +336,10 @@ impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `42414`
|
||||
// Estimated: `48354`
|
||||
// Minimum execution time: 33_537_056_000 picoseconds.
|
||||
Weight::from_parts(33_702_104_000, 0)
|
||||
// Minimum execution time: 33_300_445_000 picoseconds.
|
||||
Weight::from_parts(33_593_061_000, 0)
|
||||
.saturating_add(Weight::from_parts(0, 48354))
|
||||
.saturating_add(T::DbWeight::get().reads(31))
|
||||
.saturating_add(T::DbWeight::get().reads(30))
|
||||
.saturating_add(T::DbWeight::get().writes(15))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user