Elastic scaling: runtime dependency tracking and enactment (#3479)

Changes needed to implement the runtime part of elastic scaling:
https://github.com/paritytech/polkadot-sdk/issues/3131,
https://github.com/paritytech/polkadot-sdk/issues/3132,
https://github.com/paritytech/polkadot-sdk/issues/3202

Also fixes https://github.com/paritytech/polkadot-sdk/issues/3675

TODOs:

- [x] storage migration
- [x] optimise process_candidates from O(N^2)
- [x] drop backable candidates which form cycles
- [x] fix unit tests
- [x] add more unit tests
- [x] check the runtime APIs which use the pending availability storage.
We need to expose all of them, see
https://github.com/paritytech/polkadot-sdk/issues/3576
- [x] optimise the candidate selection. we're currently picking randomly
until we satisfy the weight limit. we need to be smart about not
breaking candidate chains while being fair to all paras -
https://github.com/paritytech/polkadot-sdk/pull/3573

Relies on the changes made in
https://github.com/paritytech/polkadot-sdk/pull/3233 in terms of the
inclusion policy and the candidate ordering

---------

Signed-off-by: alindima <alin@parity.io>
Co-authored-by: command-bot <>
Co-authored-by: eskimor <eskimor@users.noreply.github.com>
This commit is contained in:
Alin Dima
2024-03-21 12:10:45 +02:00
committed by GitHub
parent 75074952a8
commit 4842faf65d
18 changed files with 4061 additions and 1734 deletions
@@ -147,15 +147,16 @@ All failed checks should lead to an unrecoverable error making the block invalid
// return a vector of cleaned-up core IDs. // return a vector of cleaned-up core IDs.
} }
``` ```
* `force_enact(ParaId)`: Forcibly enact the candidate with the given ID as though it had been deemed available by * `force_enact(ParaId)`: Forcibly enact the pending candidates of the given paraid as though they had been deemed
bitfields. Is a no-op if there is no candidate pending availability for this para-id. This should generally not be available by bitfields. Is a no-op if there is no candidate pending availability for this para-id.
used but it is useful during execution of Runtime APIs, where the changes to the state are expected to be discarded If there are multiple candidates pending availability for this para-id, it will enact all of
directly after. them. This should generally not be used but it is useful during execution of Runtime APIs,
where the changes to the state are expected to be discarded directly after.
* `candidate_pending_availability(ParaId) -> Option<CommittedCandidateReceipt>`: returns the `CommittedCandidateReceipt` * `candidate_pending_availability(ParaId) -> Option<CommittedCandidateReceipt>`: returns the `CommittedCandidateReceipt`
pending availability for the para provided, if any. pending availability for the para provided, if any.
* `pending_availability(ParaId) -> Option<CandidatePendingAvailability>`: returns the metadata around the candidate * `pending_availability(ParaId) -> Option<CandidatePendingAvailability>`: returns the metadata around the candidate
pending availability for the para, if any. pending availability for the para, if any.
* `collect_disputed(disputed: Vec<CandidateHash>) -> Vec<CoreIndex>`: Sweeps through all paras pending availability. If * `free_disputed(disputed: Vec<CandidateHash>) -> Vec<CoreIndex>`: Sweeps through all paras pending availability. If
the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and the candidate hash is one of the disputed candidates, then clean up the corresponding storage for that candidate and
the commitments. Return a vector of cleaned-up core IDs. the commitments. Return a vector of cleaned-up core IDs.
@@ -17,7 +17,7 @@ There are a couple of important notes to the operations in this inherent as they
this fork. this fork.
1. When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the 1. When disputes are initiated, we remove the block from pending availability. This allows us to roll back chains to the
block before blocks are included as opposed to backing. It's important to do this before processing bitfields. block before blocks are included as opposed to backing. It's important to do this before processing bitfields.
1. `Inclusion::collect_disputed` is kind of expensive so it's important to gate this on whether there are actually any 1. `Inclusion::free_disputed` is kind of expensive so it's important to gate this on whether there are actually any
new disputes. Which should be never. new disputes. Which should be never.
1. And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's 1. And we don't accept parablocks that have open disputes or disputes that have concluded against the candidate. It's
important to import dispute statements before backing, but this is already the case as disputes are imported before important to import dispute statements before backing, but this is already the case as disputes are imported before
@@ -285,7 +285,6 @@ No finalization routine runs for this module.
- This clears them from `Scheduled` and marks each corresponding `core` in the `AvailabilityCores` as occupied. - This clears them from `Scheduled` and marks each corresponding `core` in the `AvailabilityCores` as occupied.
- Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be - Since both the availability cores and the newly-occupied cores lists are sorted ascending, this method can be
implemented efficiently. implemented efficiently.
- `core_para(CoreIndex) -> ParaId`: return the currently-scheduled or occupied ParaId for the given core.
- `group_validators(GroupIndex) -> Option<Vec<ValidatorIndex>>`: return all validators in a given group, if the group - `group_validators(GroupIndex) -> Option<Vec<ValidatorIndex>>`: return all validators in a given group, if the group
index is valid for this session. index is valid for this session.
- `availability_timeout_predicate() -> Option<impl Fn(CoreIndex, BlockNumber) -> bool>`: returns an optional predicate - `availability_timeout_predicate() -> Option<impl Fn(CoreIndex, BlockNumber) -> bool>`: returns an optional predicate
+74 -47
View File
@@ -40,7 +40,7 @@ use sp_runtime::{
RuntimeAppPublic, RuntimeAppPublic,
}; };
use sp_std::{ use sp_std::{
collections::{btree_map::BTreeMap, vec_deque::VecDeque}, collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque},
prelude::Vec, prelude::Vec,
vec, vec,
}; };
@@ -104,6 +104,8 @@ pub(crate) struct BenchBuilder<T: paras_inherent::Config> {
code_upgrade: Option<u32>, code_upgrade: Option<u32>,
/// Specifies whether the claimqueue should be filled. /// Specifies whether the claimqueue should be filled.
fill_claimqueue: bool, fill_claimqueue: bool,
/// Cores which should not be available when being populated with pending candidates.
unavailable_cores: Vec<u32>,
_phantom: sp_std::marker::PhantomData<T>, _phantom: sp_std::marker::PhantomData<T>,
} }
@@ -133,6 +135,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
elastic_paras: Default::default(), elastic_paras: Default::default(),
code_upgrade: None, code_upgrade: None,
fill_claimqueue: true, fill_claimqueue: true,
unavailable_cores: vec![],
_phantom: sp_std::marker::PhantomData::<T>, _phantom: sp_std::marker::PhantomData::<T>,
} }
} }
@@ -149,6 +152,12 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
self self
} }
/// Set the cores which should not be available when being populated with pending candidates.
pub(crate) fn set_unavailable_cores(mut self, unavailable_cores: Vec<u32>) -> Self {
self.unavailable_cores = unavailable_cores;
self
}
/// Set a map from para id seed to number of validity votes. /// Set a map from para id seed to number of validity votes.
pub(crate) fn set_backed_and_concluding_paras( pub(crate) fn set_backed_and_concluding_paras(
mut self, mut self,
@@ -159,7 +168,6 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
} }
/// Set a map from para id seed to number of cores assigned to it. /// Set a map from para id seed to number of cores assigned to it.
#[cfg(feature = "runtime-benchmarks")]
pub(crate) fn set_elastic_paras(mut self, elastic_paras: BTreeMap<u32, u8>) -> Self { pub(crate) fn set_elastic_paras(mut self, elastic_paras: BTreeMap<u32, u8>) -> Self {
self.elastic_paras = elastic_paras; self.elastic_paras = elastic_paras;
self self
@@ -284,11 +292,13 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
core_idx: CoreIndex, core_idx: CoreIndex,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
availability_votes: BitVec<u8, BitOrderLsb0>, availability_votes: BitVec<u8, BitOrderLsb0>,
commitments: CandidateCommitments,
) -> inclusion::CandidatePendingAvailability<T::Hash, BlockNumberFor<T>> { ) -> inclusion::CandidatePendingAvailability<T::Hash, BlockNumberFor<T>> {
inclusion::CandidatePendingAvailability::<T::Hash, BlockNumberFor<T>>::new( inclusion::CandidatePendingAvailability::<T::Hash, BlockNumberFor<T>>::new(
core_idx, // core core_idx, // core
candidate_hash, // hash candidate_hash, // hash
Self::candidate_descriptor_mock(), // candidate descriptor Self::candidate_descriptor_mock(), // candidate descriptor
commitments, // commitments
availability_votes, // availability votes availability_votes, // availability votes
Default::default(), // backers Default::default(), // backers
Zero::zero(), // relay parent Zero::zero(), // relay parent
@@ -309,12 +319,6 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
availability_votes: BitVec<u8, BitOrderLsb0>, availability_votes: BitVec<u8, BitOrderLsb0>,
candidate_hash: CandidateHash, candidate_hash: CandidateHash,
) { ) {
let candidate_availability = Self::candidate_availability_mock(
group_idx,
core_idx,
candidate_hash,
availability_votes,
);
let commitments = CandidateCommitments::<u32> { let commitments = CandidateCommitments::<u32> {
upward_messages: Default::default(), upward_messages: Default::default(),
horizontal_messages: Default::default(), horizontal_messages: Default::default(),
@@ -323,16 +327,29 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
processed_downward_messages: 0, processed_downward_messages: 0,
hrmp_watermark: 0u32.into(), hrmp_watermark: 0u32.into(),
}; };
inclusion::PendingAvailability::<T>::insert(para_id, candidate_availability); let candidate_availability = Self::candidate_availability_mock(
inclusion::PendingAvailabilityCommitments::<T>::insert(&para_id, commitments); group_idx,
core_idx,
candidate_hash,
availability_votes,
commitments,
);
inclusion::PendingAvailability::<T>::mutate(para_id, |maybe_andidates| {
if let Some(candidates) = maybe_andidates {
candidates.push_back(candidate_availability);
} else {
*maybe_andidates =
Some([candidate_availability].into_iter().collect::<VecDeque<_>>());
}
});
} }
/// Create an `AvailabilityBitfield` where `concluding` is a map where each key is a core index /// Create an `AvailabilityBitfield` where `concluding` is a map where each key is a core index
/// that is concluding and `cores` is the total number of cores in the system. /// that is concluding and `cores` is the total number of cores in the system.
fn availability_bitvec(concluding: &BTreeMap<u32, u32>, cores: usize) -> AvailabilityBitfield { fn availability_bitvec(concluding_cores: &BTreeSet<u32>, cores: usize) -> AvailabilityBitfield {
let mut bitfields = bitvec::bitvec![u8, bitvec::order::Lsb0; 0; 0]; let mut bitfields = bitvec::bitvec![u8, bitvec::order::Lsb0; 0; 0];
for i in 0..cores { for i in 0..cores {
if concluding.get(&(i as u32)).is_some() { if concluding_cores.contains(&(i as u32)) {
bitfields.push(true); bitfields.push(true);
} else { } else {
bitfields.push(false) bitfields.push(false)
@@ -356,13 +373,13 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
} }
} }
/// Register `cores` count of parachains. /// Register `n_paras` count of parachains.
/// ///
/// Note that this must be called at least 2 sessions before the target session as there is a /// Note that this must be called at least 2 sessions before the target session as there is a
/// n+2 session delay for the scheduled actions to take effect. /// n+2 session delay for the scheduled actions to take effect.
fn setup_para_ids(cores: usize) { fn setup_para_ids(n_paras: usize) {
// make sure parachains exist prior to session change. // make sure parachains exist prior to session change.
for i in 0..cores { for i in 0..n_paras {
let para_id = ParaId::from(i as u32); let para_id = ParaId::from(i as u32);
let validation_code = mock_validation_code(); let validation_code = mock_validation_code();
@@ -472,7 +489,35 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
let validators = let validators =
self.validators.as_ref().expect("must have some validators prior to calling"); self.validators.as_ref().expect("must have some validators prior to calling");
let availability_bitvec = Self::availability_bitvec(concluding_paras, total_cores); let mut current_core_idx = 0u32;
let mut concluding_cores = BTreeSet::new();
for (seed, _) in concluding_paras.iter() {
// make sure the candidates that will be concluding are marked as pending availability.
let para_id = ParaId::from(*seed);
for _chain_idx in 0..elastic_paras.get(&seed).cloned().unwrap_or(1) {
let core_idx = CoreIndex::from(current_core_idx);
let group_idx =
scheduler::Pallet::<T>::group_assigned_to_core(core_idx, self.block_number)
.unwrap();
Self::add_availability(
para_id,
core_idx,
group_idx,
// No validators have made this candidate available yet.
bitvec::bitvec![u8, bitvec::order::Lsb0; 0; validators.len()],
CandidateHash(H256::from(byte32_slice_from(current_core_idx))),
);
if !self.unavailable_cores.contains(&current_core_idx) {
concluding_cores.insert(current_core_idx);
}
current_core_idx += 1;
}
}
let availability_bitvec = Self::availability_bitvec(&concluding_cores, total_cores);
let bitfields: Vec<UncheckedSigned<AvailabilityBitfield>> = validators let bitfields: Vec<UncheckedSigned<AvailabilityBitfield>> = validators
.iter() .iter()
@@ -489,29 +534,6 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
}) })
.collect(); .collect();
let mut current_core_idx = 0u32;
for (seed, _) in concluding_paras.iter() {
// make sure the candidates that will be concluding are marked as pending availability.
let para_id = ParaId::from(*seed);
for _chain_idx in 0..elastic_paras.get(&seed).cloned().unwrap_or(1) {
let core_idx = CoreIndex::from(current_core_idx);
let group_idx =
scheduler::Pallet::<T>::group_assigned_to_core(core_idx, self.block_number)
.unwrap();
Self::add_availability(
para_id,
core_idx,
group_idx,
Self::validator_availability_votes_yes(validators.len()),
CandidateHash(H256::from(byte32_slice_from(current_core_idx))),
);
current_core_idx += 1;
}
}
bitfields bitfields
} }
@@ -522,7 +544,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
/// validity votes. /// validity votes.
fn create_backed_candidates( fn create_backed_candidates(
&self, &self,
cores_with_backed_candidates: &BTreeMap<u32, u32>, paras_with_backed_candidates: &BTreeMap<u32, u32>,
elastic_paras: &BTreeMap<u32, u8>, elastic_paras: &BTreeMap<u32, u8>,
includes_code_upgrade: Option<u32>, includes_code_upgrade: Option<u32>,
) -> Vec<BackedCandidate<T::Hash>> { ) -> Vec<BackedCandidate<T::Hash>> {
@@ -531,7 +553,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
let config = configuration::Pallet::<T>::config(); let config = configuration::Pallet::<T>::config();
let mut current_core_idx = 0u32; let mut current_core_idx = 0u32;
cores_with_backed_candidates paras_with_backed_candidates
.iter() .iter()
.flat_map(|(seed, num_votes)| { .flat_map(|(seed, num_votes)| {
assert!(*num_votes <= validators.len() as u32); assert!(*num_votes <= validators.len() as u32);
@@ -760,7 +782,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
// NOTE: there is an n+2 session delay for these actions to take effect. // NOTE: there is an n+2 session delay for these actions to take effect.
// We are currently in Session 0, so these changes will take effect in Session 2. // We are currently in Session 0, so these changes will take effect in Session 2.
Self::setup_para_ids(used_cores); Self::setup_para_ids(used_cores - extra_cores);
configuration::ActiveConfig::<T>::mutate(|c| { configuration::ActiveConfig::<T>::mutate(|c| {
c.scheduler_params.num_cores = used_cores as u32; c.scheduler_params.num_cores = used_cores as u32;
}); });
@@ -782,11 +804,11 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
let disputes = builder.create_disputes( let disputes = builder.create_disputes(
builder.backed_and_concluding_paras.len() as u32, builder.backed_and_concluding_paras.len() as u32,
used_cores as u32, (used_cores - extra_cores) as u32,
builder.dispute_sessions.as_slice(), builder.dispute_sessions.as_slice(),
); );
let mut disputed_cores = (builder.backed_and_concluding_paras.len() as u32.. let mut disputed_cores = (builder.backed_and_concluding_paras.len() as u32..
used_cores as u32) ((used_cores - extra_cores) as u32))
.into_iter() .into_iter()
.map(|idx| (idx, 0)) .map(|idx| (idx, 0))
.collect::<BTreeMap<_, _>>(); .collect::<BTreeMap<_, _>>();
@@ -794,7 +816,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
let mut all_cores = builder.backed_and_concluding_paras.clone(); let mut all_cores = builder.backed_and_concluding_paras.clone();
all_cores.append(&mut disputed_cores); all_cores.append(&mut disputed_cores);
assert_eq!(inclusion::PendingAvailability::<T>::iter().count(), used_cores as usize,); assert_eq!(inclusion::PendingAvailability::<T>::iter().count(), used_cores - extra_cores);
// Mark all the used cores as occupied. We expect that there are // Mark all the used cores as occupied. We expect that there are
// `backed_and_concluding_paras` that are pending availability and that there are // `backed_and_concluding_paras` that are pending availability and that there are
@@ -831,7 +853,7 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
.keys() .keys()
.flat_map(|para_id| { .flat_map(|para_id| {
(0..elastic_paras.get(&para_id).cloned().unwrap_or(1)) (0..elastic_paras.get(&para_id).cloned().unwrap_or(1))
.map(|_para_local_core_idx| { .filter_map(|_para_local_core_idx| {
let ttl = configuration::Pallet::<T>::config().scheduler_params.ttl; let ttl = configuration::Pallet::<T>::config().scheduler_params.ttl;
// Load an assignment into provider so that one is present to pop // Load an assignment into provider so that one is present to pop
let assignment = let assignment =
@@ -844,8 +866,13 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
CoreIndex(core_idx), CoreIndex(core_idx),
[ParasEntry::new(assignment, now + ttl)].into(), [ParasEntry::new(assignment, now + ttl)].into(),
); );
let res = if builder.unavailable_cores.contains(&core_idx) {
None
} else {
Some(entry)
};
core_idx += 1; core_idx += 1;
entry res
}) })
.collect::<Vec<(CoreIndex, VecDeque<ParasEntry<_>>)>>() .collect::<Vec<(CoreIndex, VecDeque<ParasEntry<_>>)>>()
}) })
@@ -0,0 +1,317 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
pub use v1::MigrateToV1;
pub mod v0 {
use crate::inclusion::{Config, Pallet};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use frame_support::{storage_alias, Twox64Concat};
use frame_system::pallet_prelude::BlockNumberFor;
use parity_scale_codec::{Decode, Encode};
use primitives::{
AvailabilityBitfield, CandidateCommitments, CandidateDescriptor, CandidateHash, CoreIndex,
GroupIndex, Id as ParaId, ValidatorIndex,
};
use scale_info::TypeInfo;
#[derive(Encode, Decode, PartialEq, TypeInfo, Clone, Debug)]
pub struct CandidatePendingAvailability<H, N> {
pub core: CoreIndex,
pub hash: CandidateHash,
pub descriptor: CandidateDescriptor<H>,
pub availability_votes: BitVec<u8, BitOrderLsb0>,
pub backers: BitVec<u8, BitOrderLsb0>,
pub relay_parent_number: N,
pub backed_in_number: N,
pub backing_group: GroupIndex,
}
#[derive(Encode, Decode, TypeInfo, Debug, PartialEq)]
pub struct AvailabilityBitfieldRecord<N> {
pub bitfield: AvailabilityBitfield,
pub submitted_at: N,
}
#[storage_alias]
pub type PendingAvailability<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
ParaId,
CandidatePendingAvailability<<T as frame_system::Config>::Hash, BlockNumberFor<T>>,
>;
#[storage_alias]
pub type PendingAvailabilityCommitments<T: Config> =
StorageMap<Pallet<T>, Twox64Concat, ParaId, CandidateCommitments>;
#[storage_alias]
pub type AvailabilityBitfields<T: Config> = StorageMap<
Pallet<T>,
Twox64Concat,
ValidatorIndex,
AvailabilityBitfieldRecord<BlockNumberFor<T>>,
>;
}
mod v1 {
use super::v0::{
AvailabilityBitfields, PendingAvailability as V0PendingAvailability,
PendingAvailabilityCommitments as V0PendingAvailabilityCommitments,
};
use crate::inclusion::{
CandidatePendingAvailability as V1CandidatePendingAvailability, Config, Pallet,
PendingAvailability as V1PendingAvailability,
};
use frame_support::{traits::OnRuntimeUpgrade, weights::Weight};
use sp_core::Get;
use sp_std::{collections::vec_deque::VecDeque, vec::Vec};
#[cfg(feature = "try-runtime")]
use frame_support::{
ensure,
traits::{GetStorageVersion, StorageVersion},
};
#[cfg(feature = "try-runtime")]
use parity_scale_codec::{Decode, Encode};
pub struct VersionUncheckedMigrateToV1<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> OnRuntimeUpgrade for VersionUncheckedMigrateToV1<T> {
#[cfg(feature = "try-runtime")]
fn pre_upgrade() -> Result<Vec<u8>, sp_runtime::TryRuntimeError> {
log::trace!(target: crate::inclusion::LOG_TARGET, "Running pre_upgrade() for inclusion MigrateToV1");
let candidates_before_upgrade = V0PendingAvailability::<T>::iter().count();
let commitments_before_upgrade = V0PendingAvailabilityCommitments::<T>::iter().count();
if candidates_before_upgrade != commitments_before_upgrade {
log::warn!(
target: crate::inclusion::LOG_TARGET,
"Number of pending candidates differ from the number of pending commitments. {} vs {}",
candidates_before_upgrade,
commitments_before_upgrade
);
}
Ok((candidates_before_upgrade as u32).encode())
}
fn on_runtime_upgrade() -> Weight {
let mut weight: Weight = Weight::zero();
let v0_candidates: Vec<_> = V0PendingAvailability::<T>::drain().collect();
for (para_id, candidate) in v0_candidates {
let commitments = V0PendingAvailabilityCommitments::<T>::take(para_id);
// One write for each removal (one candidate and one commitment).
weight = weight.saturating_add(T::DbWeight::get().writes(2));
if let Some(commitments) = commitments {
let mut per_para = VecDeque::new();
per_para.push_back(V1CandidatePendingAvailability {
core: candidate.core,
hash: candidate.hash,
descriptor: candidate.descriptor,
availability_votes: candidate.availability_votes,
backers: candidate.backers,
relay_parent_number: candidate.relay_parent_number,
backed_in_number: candidate.backed_in_number,
backing_group: candidate.backing_group,
commitments,
});
V1PendingAvailability::<T>::insert(para_id, per_para);
weight = weight.saturating_add(T::DbWeight::get().writes(1));
}
}
// should've already been drained by the above for loop, but as a sanity check, in case
// there are more commitments than candidates.
// V0PendingAvailabilityCommitments should not contain too many keys so removing
// everything at once should be safe
let res = V0PendingAvailabilityCommitments::<T>::clear(u32::MAX, None);
weight = weight.saturating_add(
T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64),
);
// AvailabilityBitfields should not contain too many keys so removing everything at once
// should be safe.
let res = AvailabilityBitfields::<T>::clear(u32::MAX, None);
weight = weight.saturating_add(
T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64),
);
weight
}
#[cfg(feature = "try-runtime")]
fn post_upgrade(state: Vec<u8>) -> Result<(), sp_runtime::TryRuntimeError> {
log::trace!(target: crate::inclusion::LOG_TARGET, "Running post_upgrade() for inclusion MigrateToV1");
ensure!(
Pallet::<T>::on_chain_storage_version() >= StorageVersion::new(1),
"Storage version should be >= 1 after the migration"
);
let candidates_before_upgrade =
u32::decode(&mut &state[..]).expect("Was properly encoded") as usize;
let candidates_after_upgrade = V1PendingAvailability::<T>::iter().fold(
0usize,
|mut acc, (_paraid, para_candidates)| {
acc += para_candidates.len();
acc
},
);
ensure!(
candidates_before_upgrade == candidates_after_upgrade,
"Number of pending candidates should be the same as the one before the upgrade."
);
ensure!(
V0PendingAvailability::<T>::iter().next() == None,
"Pending availability candidates storage v0 should have been removed"
);
ensure!(
V0PendingAvailabilityCommitments::<T>::iter().next() == None,
"Pending availability commitments storage should have been removed"
);
ensure!(
AvailabilityBitfields::<T>::iter().next() == None,
"Availability bitfields storage should have been removed"
);
Ok(())
}
}
/// Migrate to v1 inclusion module storage.
/// - merges the `PendingAvailabilityCommitments` into the `CandidatePendingAvailability`
/// storage
/// - removes the `AvailabilityBitfields` storage, which was never read.
pub type MigrateToV1<T> = frame_support::migrations::VersionedMigration<
0,
1,
VersionUncheckedMigrateToV1<T>,
Pallet<T>,
<T as frame_system::Config>::DbWeight,
>;
}
#[cfg(test)]
mod tests {
use super::{v1::VersionUncheckedMigrateToV1, *};
use crate::{
inclusion::{
CandidatePendingAvailability as V1CandidatePendingAvailability,
PendingAvailability as V1PendingAvailability, *,
},
mock::{new_test_ext, MockGenesisConfig, Test},
};
use frame_support::traits::OnRuntimeUpgrade;
use primitives::{AvailabilityBitfield, Id as ParaId};
use test_helpers::{dummy_candidate_commitments, dummy_candidate_descriptor, dummy_hash};
#[test]
fn migrate_to_v1() {
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
// No data to migrate.
assert_eq!(
<VersionUncheckedMigrateToV1<Test> as OnRuntimeUpgrade>::on_runtime_upgrade(),
Weight::zero()
);
assert!(V1PendingAvailability::<Test>::iter().next().is_none());
let mut expected = vec![];
for i in 1..5 {
let descriptor = dummy_candidate_descriptor(dummy_hash());
v0::PendingAvailability::<Test>::insert(
ParaId::from(i),
v0::CandidatePendingAvailability {
core: CoreIndex(i),
descriptor: descriptor.clone(),
relay_parent_number: i,
hash: CandidateHash(dummy_hash()),
availability_votes: Default::default(),
backed_in_number: i,
backers: Default::default(),
backing_group: GroupIndex(i),
},
);
v0::PendingAvailabilityCommitments::<Test>::insert(
ParaId::from(i),
dummy_candidate_commitments(HeadData(vec![i as _])),
);
v0::AvailabilityBitfields::<Test>::insert(
ValidatorIndex(i),
v0::AvailabilityBitfieldRecord {
bitfield: AvailabilityBitfield(Default::default()),
submitted_at: i,
},
);
expected.push((
ParaId::from(i),
[V1CandidatePendingAvailability {
core: CoreIndex(i),
descriptor,
relay_parent_number: i,
hash: CandidateHash(dummy_hash()),
availability_votes: Default::default(),
backed_in_number: i,
backers: Default::default(),
backing_group: GroupIndex(i),
commitments: dummy_candidate_commitments(HeadData(vec![i as _])),
}]
.into_iter()
.collect::<VecDeque<_>>(),
));
}
// add some wrong data also, candidates without commitments or commitments without
// candidates.
v0::PendingAvailability::<Test>::insert(
ParaId::from(6),
v0::CandidatePendingAvailability {
core: CoreIndex(6),
descriptor: dummy_candidate_descriptor(dummy_hash()),
relay_parent_number: 6,
hash: CandidateHash(dummy_hash()),
availability_votes: Default::default(),
backed_in_number: 6,
backers: Default::default(),
backing_group: GroupIndex(6),
},
);
v0::PendingAvailabilityCommitments::<Test>::insert(
ParaId::from(7),
dummy_candidate_commitments(HeadData(vec![7 as _])),
);
// For tests, db weight is zero.
assert_eq!(
<VersionUncheckedMigrateToV1<Test> as OnRuntimeUpgrade>::on_runtime_upgrade(),
Weight::zero()
);
assert_eq!(v0::PendingAvailabilityCommitments::<Test>::iter().next(), None);
assert_eq!(v0::PendingAvailability::<Test>::iter().next(), None);
assert_eq!(v0::AvailabilityBitfields::<Test>::iter().next(), None);
let mut actual = V1PendingAvailability::<Test>::iter().collect::<Vec<_>>();
actual.sort_by(|(id1, _), (id2, _)| id1.cmp(id2));
expected.sort_by(|(id1, _), (id2, _)| id1.cmp(id2));
assert_eq!(actual, expected);
});
}
}
+342 -363
View File
@@ -23,31 +23,35 @@ use crate::{
configuration::{self, HostConfiguration}, configuration::{self, HostConfiguration},
disputes, dmp, hrmp, disputes, dmp, hrmp,
paras::{self, SetGoAhead}, paras::{self, SetGoAhead},
scheduler::{self, AvailabilityTimeoutStatus}, scheduler,
shared::{self, AllowedRelayParentsTracker}, shared::{self, AllowedRelayParentsTracker},
util::make_persisted_validation_data_with_parent,
}; };
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
use frame_support::{ use frame_support::{
defensive, defensive,
pallet_prelude::*, pallet_prelude::*,
traits::{Defensive, EnqueueMessage, Footprint, QueueFootprint}, traits::{EnqueueMessage, Footprint, QueueFootprint},
BoundedSlice, BoundedSlice,
}; };
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
use pallet_message_queue::OnQueueChanged; use pallet_message_queue::OnQueueChanged;
use parity_scale_codec::{Decode, Encode}; use parity_scale_codec::{Decode, Encode};
use primitives::{ use primitives::{
effective_minimum_backing_votes, supermajority_threshold, well_known_keys, effective_minimum_backing_votes, supermajority_threshold, well_known_keys, BackedCandidate,
AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor, CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt,
CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId,
HeadData, Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex,
ValidatorId, ValidatorIndex, ValidityAttestation, ValidityAttestation,
}; };
use scale_info::TypeInfo; use scale_info::TypeInfo;
use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use sp_std::fmt; use sp_std::fmt;
use sp_std::{collections::btree_set::BTreeSet, prelude::*}; use sp_std::{
collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque},
prelude::*,
};
pub use pallet::*; pub use pallet::*;
@@ -57,6 +61,8 @@ pub(crate) mod tests;
#[cfg(feature = "runtime-benchmarks")] #[cfg(feature = "runtime-benchmarks")]
mod benchmarking; mod benchmarking;
pub mod migration;
pub trait WeightInfo { pub trait WeightInfo {
fn receive_upward_messages(i: u32) -> Weight; fn receive_upward_messages(i: u32) -> Weight;
} }
@@ -80,20 +86,8 @@ impl WeightInfo for () {
/// `configuration` pallet to check these values before setting. /// `configuration` pallet to check these values before setting.
pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024; pub const MAX_UPWARD_MESSAGE_SIZE_BOUND: u32 = 128 * 1024;
/// A bitfield signed by a validator indicating that it is keeping its piece of the erasure-coding
/// for any backed candidates referred to by a `1` bit available.
///
/// The bitfield's signature should be checked at the point of submission. Afterwards it can be
/// dropped.
#[derive(Encode, Decode, TypeInfo)]
#[cfg_attr(test, derive(Debug))]
pub struct AvailabilityBitfieldRecord<N> {
bitfield: AvailabilityBitfield, // one bit per core.
submitted_at: N, // for accounting, as meaning of bits may change over time.
}
/// A backed candidate pending availability. /// A backed candidate pending availability.
#[derive(Encode, Decode, PartialEq, TypeInfo)] #[derive(Encode, Decode, PartialEq, TypeInfo, Clone)]
#[cfg_attr(test, derive(Debug))] #[cfg_attr(test, derive(Debug))]
pub struct CandidatePendingAvailability<H, N> { pub struct CandidatePendingAvailability<H, N> {
/// The availability core this is assigned to. /// The availability core this is assigned to.
@@ -102,6 +96,8 @@ pub struct CandidatePendingAvailability<H, N> {
hash: CandidateHash, hash: CandidateHash,
/// The candidate descriptor. /// The candidate descriptor.
descriptor: CandidateDescriptor<H>, descriptor: CandidateDescriptor<H>,
/// The candidate commitments.
commitments: CandidateCommitments,
/// The received availability votes. One bit per validator. /// The received availability votes. One bit per validator.
availability_votes: BitVec<u8, BitOrderLsb0>, availability_votes: BitVec<u8, BitOrderLsb0>,
/// The backers of the candidate pending availability. /// The backers of the candidate pending availability.
@@ -121,8 +117,11 @@ impl<H, N> CandidatePendingAvailability<H, N> {
} }
/// Get the relay-chain block number this was backed in. /// Get the relay-chain block number this was backed in.
pub(crate) fn backed_in_number(&self) -> &N { pub(crate) fn backed_in_number(&self) -> N
&self.backed_in_number where
N: Clone,
{
self.backed_in_number.clone()
} }
/// Get the core index. /// Get the core index.
@@ -140,6 +139,11 @@ impl<H, N> CandidatePendingAvailability<H, N> {
&self.descriptor &self.descriptor
} }
/// Get the candidate commitments.
pub(crate) fn candidate_commitments(&self) -> &CandidateCommitments {
&self.commitments
}
/// Get the candidate's relay parent's number. /// Get the candidate's relay parent's number.
pub(crate) fn relay_parent_number(&self) -> N pub(crate) fn relay_parent_number(&self) -> N
where where
@@ -148,11 +152,22 @@ impl<H, N> CandidatePendingAvailability<H, N> {
self.relay_parent_number.clone() self.relay_parent_number.clone()
} }
/// Get the candidate backing group.
pub(crate) fn backing_group(&self) -> GroupIndex {
self.backing_group
}
/// Get the candidate's backers.
pub(crate) fn backers(&self) -> &BitVec<u8, BitOrderLsb0> {
&self.backers
}
#[cfg(any(feature = "runtime-benchmarks", test))] #[cfg(any(feature = "runtime-benchmarks", test))]
pub(crate) fn new( pub(crate) fn new(
core: CoreIndex, core: CoreIndex,
hash: CandidateHash, hash: CandidateHash,
descriptor: CandidateDescriptor<H>, descriptor: CandidateDescriptor<H>,
commitments: CandidateCommitments,
availability_votes: BitVec<u8, BitOrderLsb0>, availability_votes: BitVec<u8, BitOrderLsb0>,
backers: BitVec<u8, BitOrderLsb0>, backers: BitVec<u8, BitOrderLsb0>,
relay_parent_number: N, relay_parent_number: N,
@@ -163,6 +178,7 @@ impl<H, N> CandidatePendingAvailability<H, N> {
core, core,
hash, hash,
descriptor, descriptor,
commitments,
availability_votes, availability_votes,
backers, backers,
relay_parent_number, relay_parent_number,
@@ -253,8 +269,10 @@ pub type MaxUmpMessageLenOf<T> =
pub mod pallet { pub mod pallet {
use super::*; use super::*;
const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
#[pallet::pallet] #[pallet::pallet]
#[pallet::without_storage_info] #[pallet::without_storage_info]
#[pallet::storage_version(STORAGE_VERSION)]
pub struct Pallet<T>(_); pub struct Pallet<T>(_);
#[pallet::config] #[pallet::config]
@@ -297,30 +315,10 @@ pub mod pallet {
#[pallet::error] #[pallet::error]
pub enum Error<T> { pub enum Error<T> {
/// Validator indices are out of order or contains duplicates.
UnsortedOrDuplicateValidatorIndices,
/// Dispute statement sets are out of order or contain duplicates.
UnsortedOrDuplicateDisputeStatementSet,
/// Backed candidates are out of order (core index) or contain duplicates.
UnsortedOrDuplicateBackedCandidates,
/// A different relay parent was provided compared to the on-chain stored one.
UnexpectedRelayParent,
/// Availability bitfield has unexpected size.
WrongBitfieldSize,
/// Bitfield consists of zeros only.
BitfieldAllZeros,
/// Multiple bitfields submitted by same validator or validators out of order by index.
BitfieldDuplicateOrUnordered,
/// Validator index out of bounds. /// Validator index out of bounds.
ValidatorIndexOutOfBounds, ValidatorIndexOutOfBounds,
/// Invalid signature
InvalidBitfieldSignature,
/// Candidate submitted but para not scheduled. /// Candidate submitted but para not scheduled.
UnscheduledCandidate, UnscheduledCandidate,
/// Candidate scheduled despite pending candidate already existing for the para.
CandidateScheduledBeforeParaFree,
/// Scheduled cores out of order.
ScheduledOutOfOrder,
/// Head data exceeds the configured maximum. /// Head data exceeds the configured maximum.
HeadDataTooLarge, HeadDataTooLarge,
/// Code upgrade prematurely. /// Code upgrade prematurely.
@@ -356,31 +354,22 @@ pub mod pallet {
/// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual /// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual
/// para head in the commitments. /// para head in the commitments.
ParaHeadMismatch, ParaHeadMismatch,
/// A bitfield that references a freed core,
/// either intentionally or as part of a concluded
/// invalid dispute.
BitfieldReferencesFreedCore,
} }
/// The latest bitfield for each validator, referred to by their index in the validator set. /// Candidates pending availability by `ParaId`. They form a chain starting from the latest
#[pallet::storage] /// included head of the para.
pub(crate) type AvailabilityBitfields<T: Config> = /// Use a different prefix post-migration to v1, since the v0 `PendingAvailability` storage
StorageMap<_, Twox64Concat, ValidatorIndex, AvailabilityBitfieldRecord<BlockNumberFor<T>>>; /// would otherwise have the exact same prefix which could cause undefined behaviour when doing
/// the migration.
/// Candidates pending availability by `ParaId`.
#[pallet::storage] #[pallet::storage]
#[pallet::storage_prefix = "V1"]
pub(crate) type PendingAvailability<T: Config> = StorageMap< pub(crate) type PendingAvailability<T: Config> = StorageMap<
_, _,
Twox64Concat, Twox64Concat,
ParaId, ParaId,
CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>, VecDeque<CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>>,
>; >;
/// The commitments of candidates pending availability, by `ParaId`.
#[pallet::storage]
pub(crate) type PendingAvailabilityCommitments<T: Config> =
StorageMap<_, Twox64Concat, ParaId, CandidateCommitments>;
#[pallet::call] #[pallet::call]
impl<T: Config> Pallet<T> {} impl<T: Config> Pallet<T> {}
} }
@@ -469,9 +458,7 @@ impl<T: Config> Pallet<T> {
) { ) {
// unlike most drain methods, drained elements are not cleared on `Drop` of the iterator // unlike most drain methods, drained elements are not cleared on `Drop` of the iterator
// and require consumption. // and require consumption.
for _ in <PendingAvailabilityCommitments<T>>::drain() {}
for _ in <PendingAvailability<T>>::drain() {} for _ in <PendingAvailability<T>>::drain() {}
for _ in <AvailabilityBitfields<T>>::drain() {}
Self::cleanup_outgoing_ump_dispatch_queues(outgoing_paras); Self::cleanup_outgoing_ump_dispatch_queues(outgoing_paras);
} }
@@ -490,27 +477,18 @@ impl<T: Config> Pallet<T> {
/// ///
/// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`! /// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`!
/// ///
/// Updates storage items `PendingAvailability` and `AvailabilityBitfields`. /// Updates storage items `PendingAvailability`.
/// ///
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became /// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became
/// available, and cores free. /// available, and cores free.
pub(crate) fn update_pending_availability_and_get_freed_cores<F>( pub(crate) fn update_pending_availability_and_get_freed_cores(
expected_bits: usize,
validators: &[ValidatorId], validators: &[ValidatorId],
signed_bitfields: SignedAvailabilityBitfields, signed_bitfields: SignedAvailabilityBitfields,
core_lookup: F, ) -> Vec<(CoreIndex, CandidateHash)> {
) -> Vec<(CoreIndex, CandidateHash)> let threshold = availability_threshold(validators.len());
where
F: Fn(CoreIndex) -> Option<ParaId>, let mut votes_per_core: BTreeMap<CoreIndex, BTreeSet<ValidatorIndex>> = BTreeMap::new();
{
let mut assigned_paras_record = (0..expected_bits)
.map(|bit_index| core_lookup(CoreIndex::from(bit_index as u32)))
.map(|opt_para_id| {
opt_para_id.map(|para_id| (para_id, PendingAvailability::<T>::get(&para_id)))
})
.collect::<Vec<_>>();
let now = <frame_system::Pallet<T>>::block_number();
for (checked_bitfield, validator_index) in for (checked_bitfield, validator_index) in
signed_bitfields.into_iter().map(|signed_bitfield| { signed_bitfields.into_iter().map(|signed_bitfield| {
let validator_idx = signed_bitfield.validator_index(); let validator_idx = signed_bitfield.validator_index();
@@ -518,204 +496,232 @@ impl<T: Config> Pallet<T> {
(checked_bitfield, validator_idx) (checked_bitfield, validator_idx)
}) { }) {
for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) { for (bit_idx, _) in checked_bitfield.0.iter().enumerate().filter(|(_, is_av)| **is_av) {
let pending_availability = if let Some((_, pending_availability)) = let core_index = CoreIndex(bit_idx as u32);
assigned_paras_record[bit_idx].as_mut() votes_per_core
{ .entry(core_index)
pending_availability .or_insert_with(|| BTreeSet::new())
} else { .insert(validator_index);
// For honest validators, this happens in case of unoccupied cores, }
// which in turn happens in case of a disputed candidate. }
// A malicious one might include arbitrary indices, but they are represented
// by `None` values and will be sorted out in the next if case.
continue
};
// defensive check - this is constructed by loading the availability bitfield let mut freed_cores = vec![];
// record, which is always `Some` if the core is occupied - that's why we're here.
let validator_index = validator_index.0 as usize; let pending_paraids: Vec<_> = <PendingAvailability<T>>::iter_keys().collect();
for paraid in pending_paraids {
<PendingAvailability<T>>::mutate(paraid, |candidates| {
if let Some(candidates) = candidates {
let mut last_enacted_index: Option<usize> = None;
for (candidate_index, candidate) in candidates.iter_mut().enumerate() {
if let Some(validator_indices) = votes_per_core.remove(&candidate.core) {
for validator_index in validator_indices.iter() {
// defensive check - this is constructed by loading the
// availability bitfield record, which is always `Some` if
// the core is occupied - that's why we're here.
if let Some(mut bit) = if let Some(mut bit) =
pending_availability.as_mut().and_then(|candidate_pending_availability| { candidate.availability_votes.get_mut(validator_index.0 as usize)
candidate_pending_availability.availability_votes.get_mut(validator_index) {
}) {
*bit = true; *bit = true;
} }
} }
let record =
AvailabilityBitfieldRecord { bitfield: checked_bitfield, submitted_at: now };
<AvailabilityBitfields<T>>::insert(&validator_index, record);
} }
let threshold = availability_threshold(validators.len()); // We check for the candidate's availability even if we didn't get any new
// bitfields for its core, as it may have already been available at a
let mut freed_cores = Vec::with_capacity(expected_bits); // previous block but wasn't enacted due to its predecessors not being
for (para_id, pending_availability) in assigned_paras_record // available.
.into_iter() if candidate.availability_votes.count_ones() >= threshold {
.flatten() // We can only enact a candidate if we've enacted all of its
.filter_map(|(id, p)| p.map(|p| (id, p))) // predecessors already.
{ let can_enact = if candidate_index == 0 {
if pending_availability.availability_votes.count_ones() >= threshold { last_enacted_index == None
<PendingAvailability<T>>::remove(&para_id); } else {
let commitments = match PendingAvailabilityCommitments::<T>::take(&para_id) { let prev_candidate_index = usize::try_from(candidate_index - 1)
Some(commitments) => commitments, .expect("Previous `if` would have caught a 0 candidate index.");
None => { matches!(last_enacted_index, Some(old_index) if old_index == prev_candidate_index)
log::warn!(
target: LOG_TARGET,
"Inclusion::process_bitfields: PendingAvailability and PendingAvailabilityCommitments
are out of sync, did someone mess with the storage?",
);
continue
},
}; };
if can_enact {
last_enacted_index = Some(candidate_index);
}
}
}
// Trim the pending availability candidates storage and enact candidates of this
// para now.
if let Some(last_enacted_index) = last_enacted_index {
let evicted_candidates = candidates.drain(0..=last_enacted_index);
for candidate in evicted_candidates {
freed_cores.push((candidate.core, candidate.hash));
let receipt = CommittedCandidateReceipt { let receipt = CommittedCandidateReceipt {
descriptor: pending_availability.descriptor, descriptor: candidate.descriptor,
commitments, commitments: candidate.commitments,
}; };
let _weight = Self::enact_candidate( let _weight = Self::enact_candidate(
pending_availability.relay_parent_number, candidate.relay_parent_number,
receipt, receipt,
pending_availability.backers, candidate.backers,
pending_availability.availability_votes, candidate.availability_votes,
pending_availability.core, candidate.core,
pending_availability.backing_group, candidate.backing_group,
); );
freed_cores.push((pending_availability.core, pending_availability.hash));
} else {
<PendingAvailability<T>>::insert(&para_id, &pending_availability);
} }
} }
}
});
}
freed_cores freed_cores
} }
/// Process candidates that have been backed. Provide the relay storage root, a set of /// Process candidates that have been backed. Provide a set of
/// candidates and scheduled cores. /// candidates along with their scheduled cores.
/// ///
/// Both should be sorted ascending by core index, and the candidates should be a subset of /// Candidates of the same paraid should be sorted according to their dependency order (they
/// scheduled cores. If these conditions are not met, the execution of the function fails. /// should form a chain). If this condition is not met, this function will return an error.
/// (This really should not happen here, if the candidates were properly sanitised in
/// paras_inherent).
pub(crate) fn process_candidates<GV>( pub(crate) fn process_candidates<GV>(
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
candidates: Vec<(BackedCandidate<T::Hash>, CoreIndex)>, candidates: &BTreeMap<ParaId, Vec<(BackedCandidate<T::Hash>, CoreIndex)>>,
group_validators: GV, group_validators: GV,
core_index_enabled: bool, core_index_enabled: bool,
) -> Result<ProcessedCandidates<T::Hash>, DispatchError> ) -> Result<ProcessedCandidates<T::Hash>, DispatchError>
where where
GV: Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>, GV: Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>,
{ {
let now = <frame_system::Pallet<T>>::block_number();
if candidates.is_empty() { if candidates.is_empty() {
return Ok(ProcessedCandidates::default()) return Ok(ProcessedCandidates::default())
} }
let minimum_backing_votes = configuration::Pallet::<T>::config().minimum_backing_votes; let now = <frame_system::Pallet<T>>::block_number();
let validators = shared::Pallet::<T>::active_validator_keys(); let validators = shared::Pallet::<T>::active_validator_keys();
// Collect candidate receipts with backers. // Collect candidate receipts with backers.
let mut candidate_receipt_with_backing_validator_indices = let mut candidate_receipt_with_backing_validator_indices =
Vec::with_capacity(candidates.len()); Vec::with_capacity(candidates.len());
let mut core_indices = Vec::with_capacity(candidates.len());
// Do all checks before writing storage. for (para_id, para_candidates) in candidates {
let core_indices_and_backers = { let mut latest_head_data = match Self::para_latest_head_data(para_id) {
let mut core_indices_and_backers = Vec::with_capacity(candidates.len()); None => {
let mut last_core = None; defensive!("Latest included head data for paraid {:?} is None", para_id);
continue
let mut check_assignment_in_order = |core_idx| -> DispatchResult {
ensure!(
last_core.map_or(true, |core| core_idx > core),
Error::<T>::ScheduledOutOfOrder,
);
last_core = Some(core_idx);
Ok(())
};
// We combine an outer loop over candidates with an inner loop over the scheduled,
// where each iteration of the outer loop picks up at the position
// in scheduled just after the past iteration left off.
//
// If the candidates appear in the same order as they appear in `scheduled`,
// then they should always be found. If the end of `scheduled` is reached,
// then the candidate was either not scheduled or out-of-order.
//
// In the meantime, we do certain sanity checks on the candidates and on the scheduled
// list.
for (candidate_idx, (backed_candidate, core_index)) in candidates.iter().enumerate() {
let relay_parent_hash = backed_candidate.descriptor().relay_parent;
let para_id = backed_candidate.descriptor().para_id;
let prev_context = <paras::Pallet<T>>::para_most_recent_context(para_id);
let check_ctx = CandidateCheckContext::<T>::new(prev_context);
let signing_context = SigningContext {
parent_hash: relay_parent_hash,
session_index: shared::Pallet::<T>::session_index(),
};
let relay_parent_number = match check_ctx.verify_backed_candidate(
&allowed_relay_parents,
candidate_idx,
backed_candidate.candidate(),
)? {
Err(FailedToCreatePVD) => {
log::debug!(
target: LOG_TARGET,
"Failed to create PVD for candidate {}",
candidate_idx,
);
// We don't want to error out here because it will
// brick the relay-chain. So we return early without
// doing anything.
return Ok(ProcessedCandidates::default())
}, },
Ok(rpn) => rpn, Some(latest_head_data) => latest_head_data,
}; };
let (validator_indices, _) = for (candidate, core) in para_candidates.iter() {
backed_candidate.validator_indices_and_core_index(core_index_enabled); let candidate_hash = candidate.candidate().hash();
log::debug!( let check_ctx = CandidateCheckContext::<T>::new(None);
target: LOG_TARGET, let relay_parent_number = check_ctx.verify_backed_candidate(
"Candidate {:?} on {:?}, &allowed_relay_parents,
core_index_enabled = {}", candidate.candidate(),
backed_candidate.hash(), latest_head_data.clone(),
core_index, )?;
core_index_enabled
);
check_assignment_in_order(core_index)?; // The candidate based upon relay parent `N` should be backed by a
// group assigned to core at block `N + 1`. Thus,
let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; // `relay_parent_number + 1` will always land in the current
// session.
ensure!(
<PendingAvailability<T>>::get(&para_id).is_none() &&
<PendingAvailabilityCommitments<T>>::get(&para_id).is_none(),
Error::<T>::CandidateScheduledBeforeParaFree,
);
// The candidate based upon relay parent `N` should be backed by a group
// assigned to core at block `N + 1`. Thus, `relay_parent_number + 1`
// will always land in the current session.
let group_idx = <scheduler::Pallet<T>>::group_assigned_to_core( let group_idx = <scheduler::Pallet<T>>::group_assigned_to_core(
*core_index, *core,
relay_parent_number + One::one(), relay_parent_number + One::one(),
) )
.ok_or_else(|| { .ok_or_else(|| {
log::warn!( log::warn!(
target: LOG_TARGET, target: LOG_TARGET,
"Failed to compute group index for candidate {}", "Failed to compute group index for candidate {:?}",
candidate_idx candidate_hash
); );
Error::<T>::InvalidAssignment Error::<T>::InvalidAssignment
})?; })?;
let group_vals = let group_vals =
group_validators(group_idx).ok_or_else(|| Error::<T>::InvalidGroupIndex)?; group_validators(group_idx).ok_or_else(|| Error::<T>::InvalidGroupIndex)?;
// Check backing vote count and validity.
let (backers, backer_idx_and_attestation) = Self::check_backing_votes(
candidate,
&validators,
group_vals,
core_index_enabled,
)?;
// Found a valid candidate.
latest_head_data = candidate.candidate().commitments.head_data.clone();
candidate_receipt_with_backing_validator_indices
.push((candidate.receipt(), backer_idx_and_attestation));
core_indices.push((*core, *para_id));
// Update storage now
<PendingAvailability<T>>::mutate(&para_id, |pending_availability| {
let new_candidate = CandidatePendingAvailability {
core: *core,
hash: candidate_hash,
descriptor: candidate.candidate().descriptor.clone(),
commitments: candidate.candidate().commitments.clone(),
// initialize all availability votes to 0.
availability_votes: bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()],
relay_parent_number,
backers: backers.to_bitvec(),
backed_in_number: now,
backing_group: group_idx,
};
if let Some(pending_availability) = pending_availability {
pending_availability.push_back(new_candidate);
} else {
*pending_availability =
Some([new_candidate].into_iter().collect::<VecDeque<_>>())
}
});
// Deposit backed event.
Self::deposit_event(Event::<T>::CandidateBacked(
candidate.candidate().to_plain(),
candidate.candidate().commitments.head_data.clone(),
*core,
group_idx,
));
}
}
Ok(ProcessedCandidates::<T::Hash> {
core_indices,
candidate_receipt_with_backing_validator_indices,
})
}
// Get the latest backed output head data of this para.
pub(crate) fn para_latest_head_data(para_id: &ParaId) -> Option<HeadData> {
match <PendingAvailability<T>>::get(para_id).and_then(|pending_candidates| {
pending_candidates.back().map(|x| x.commitments.head_data.clone())
}) {
Some(head_data) => Some(head_data),
None => <paras::Pallet<T>>::para_head(para_id),
}
}
fn check_backing_votes(
backed_candidate: &BackedCandidate<T::Hash>,
validators: &[ValidatorId],
group_vals: Vec<ValidatorIndex>,
core_index_enabled: bool,
) -> Result<(BitVec<u8, BitOrderLsb0>, Vec<(ValidatorIndex, ValidityAttestation)>), Error<T>> {
let minimum_backing_votes = configuration::Pallet::<T>::config().minimum_backing_votes;
let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()];
let signing_context = SigningContext {
parent_hash: backed_candidate.descriptor().relay_parent,
session_index: shared::Pallet::<T>::session_index(),
};
let (validator_indices, _) =
backed_candidate.validator_indices_and_core_index(core_index_enabled);
// check the signatures in the backing and that it is a majority. // check the signatures in the backing and that it is a majority.
{
let maybe_amount_validated = primitives::check_candidate_backing( let maybe_amount_validated = primitives::check_candidate_backing(
backed_candidate.candidate().hash(), backed_candidate.candidate().hash(),
backed_candidate.validity_votes(), backed_candidate.validity_votes(),
@@ -733,10 +739,7 @@ impl<T: Config> Pallet<T> {
match maybe_amount_validated { match maybe_amount_validated {
Ok(amount_validated) => ensure!( Ok(amount_validated) => ensure!(
amount_validated >= amount_validated >=
effective_minimum_backing_votes( effective_minimum_backing_votes(group_vals.len(), minimum_backing_votes),
group_vals.len(),
minimum_backing_votes
),
Error::<T>::InsufficientBacking, Error::<T>::InsufficientBacking,
), ),
Err(()) => { Err(()) => {
@@ -748,7 +751,6 @@ impl<T: Config> Pallet<T> {
Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity( Vec::<(ValidatorIndex, ValidityAttestation)>::with_capacity(
validator_indices.count_ones(), validator_indices.count_ones(),
); );
let candidate_receipt = backed_candidate.receipt();
for ((bit_idx, _), attestation) in validator_indices for ((bit_idx, _), attestation) in validator_indices
.iter() .iter()
@@ -756,72 +758,13 @@ impl<T: Config> Pallet<T> {
.filter(|(_, signed)| **signed) .filter(|(_, signed)| **signed)
.zip(backed_candidate.validity_votes().iter().cloned()) .zip(backed_candidate.validity_votes().iter().cloned())
{ {
let val_idx = let val_idx = group_vals.get(bit_idx).expect("this query succeeded above; qed");
group_vals.get(bit_idx).expect("this query succeeded above; qed");
backer_idx_and_attestation.push((*val_idx, attestation)); backer_idx_and_attestation.push((*val_idx, attestation));
backers.set(val_idx.0 as _, true); backers.set(val_idx.0 as _, true);
} }
candidate_receipt_with_backing_validator_indices
.push((candidate_receipt, backer_idx_and_attestation));
}
core_indices_and_backers.push(( Ok((backers, backer_idx_and_attestation))
(*core_index, para_id),
backers,
group_idx,
relay_parent_number,
));
}
core_indices_and_backers
};
// one more sweep for actually writing to storage.
let core_indices = core_indices_and_backers.iter().map(|(c, ..)| *c).collect();
for ((candidate, _), (core, backers, group, relay_parent_number)) in
candidates.into_iter().zip(core_indices_and_backers)
{
let para_id = candidate.descriptor().para_id;
// initialize all availability votes to 0.
let availability_votes: BitVec<u8, BitOrderLsb0> =
bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()];
Self::deposit_event(Event::<T>::CandidateBacked(
candidate.candidate().to_plain(),
candidate.candidate().commitments.head_data.clone(),
core.0,
group,
));
let candidate_hash = candidate.candidate().hash();
let (descriptor, commitments) = (
candidate.candidate().descriptor.clone(),
candidate.candidate().commitments.clone(),
);
<PendingAvailability<T>>::insert(
&para_id,
CandidatePendingAvailability {
core: core.0,
hash: candidate_hash,
descriptor,
availability_votes,
relay_parent_number,
backers: backers.to_bitvec(),
backed_in_number: now,
backing_group: group,
},
);
<PendingAvailabilityCommitments<T>>::insert(&para_id, commitments);
}
Ok(ProcessedCandidates::<T::Hash> {
core_indices,
candidate_receipt_with_backing_validator_indices,
})
} }
/// Run the acceptance criteria checks on the given candidate commitments. /// Run the acceptance criteria checks on the given candidate commitments.
@@ -1028,110 +971,155 @@ impl<T: Config> Pallet<T> {
weight weight
} }
/// Cleans up all paras pending availability that the predicate returns true for. /// Cleans up all timed out candidates as well as their descendant candidates.
///
/// The predicate accepts the index of the core and the block number the core has been occupied
/// since (i.e. the block number the candidate was backed at in this fork of the relay chain).
/// ///
/// Returns a vector of cleaned-up core IDs. /// Returns a vector of cleaned-up core IDs.
pub(crate) fn collect_pending( pub(crate) fn free_timedout() -> Vec<CoreIndex> {
pred: impl Fn(BlockNumberFor<T>) -> AvailabilityTimeoutStatus<BlockNumberFor<T>>, let timeout_pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
) -> Vec<CoreIndex> {
let mut cleaned_up_ids = Vec::new();
let mut cleaned_up_cores = Vec::new();
for (para_id, pending_record) in <PendingAvailability<T>>::iter() { let timed_out: Vec<_> = Self::free_failed_cores(
if pred(pending_record.backed_in_number).timed_out { |candidate| timeout_pred(candidate.backed_in_number).timed_out,
cleaned_up_ids.push(para_id); None,
cleaned_up_cores.push(pending_record.core); )
} .collect();
}
for para_id in cleaned_up_ids { let mut timed_out_cores = Vec::with_capacity(timed_out.len());
let pending = <PendingAvailability<T>>::take(&para_id); for candidate in timed_out.iter() {
let commitments = <PendingAvailabilityCommitments<T>>::take(&para_id); timed_out_cores.push(candidate.core);
if let (Some(pending), Some(commitments)) = (pending, commitments) { let receipt = CandidateReceipt {
// defensive: this should always be true. descriptor: candidate.descriptor.clone(),
let candidate = CandidateReceipt { commitments_hash: candidate.commitments.hash(),
descriptor: pending.descriptor,
commitments_hash: commitments.hash(),
}; };
Self::deposit_event(Event::<T>::CandidateTimedOut( Self::deposit_event(Event::<T>::CandidateTimedOut(
candidate, receipt,
commitments.head_data, candidate.commitments.head_data.clone(),
pending.core, candidate.core,
)); ));
} }
timed_out_cores
} }
cleaned_up_cores /// Cleans up all cores pending availability occupied by one of the disputed candidates or which
} /// are descendants of a disputed candidate.
/// Cleans up all paras pending availability that are in the given list of disputed candidates.
/// ///
/// Returns a vector of cleaned-up core IDs. /// Returns a vector of cleaned-up core IDs, along with the evicted candidate hashes.
pub(crate) fn collect_disputed(disputed: &BTreeSet<CandidateHash>) -> Vec<CoreIndex> { pub(crate) fn free_disputed(
let mut cleaned_up_ids = Vec::new(); disputed: &BTreeSet<CandidateHash>,
let mut cleaned_up_cores = Vec::new(); ) -> Vec<(CoreIndex, CandidateHash)> {
Self::free_failed_cores(
|candidate| disputed.contains(&candidate.hash),
Some(disputed.len()),
)
.map(|candidate| (candidate.core, candidate.hash))
.collect()
}
for (para_id, pending_record) in <PendingAvailability<T>>::iter() { // Clean up cores whose candidates are deemed as failed by the predicate. `pred` returns true if
if disputed.contains(&pending_record.hash) { // a candidate is considered failed.
cleaned_up_ids.push(para_id); // A failed candidate also frees all subsequent cores which hold descendants of said candidate.
cleaned_up_cores.push(pending_record.core); fn free_failed_cores<
P: Fn(&CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>) -> bool,
>(
pred: P,
capacity_hint: Option<usize>,
) -> impl Iterator<Item = CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>> {
let mut earliest_dropped_indices: BTreeMap<ParaId, usize> = BTreeMap::new();
for (para_id, pending_candidates) in <PendingAvailability<T>>::iter() {
// We assume that pending candidates are stored in dependency order. So we need to store
// the earliest dropped candidate. All others that follow will get freed as well.
let mut earliest_dropped_idx = None;
for (index, candidate) in pending_candidates.iter().enumerate() {
if pred(candidate) {
earliest_dropped_idx = Some(index);
// Since we're looping the candidates in dependency order, we've found the
// earliest failed index for this paraid.
break;
} }
} }
for para_id in cleaned_up_ids { if let Some(earliest_dropped_idx) = earliest_dropped_idx {
let _ = <PendingAvailability<T>>::take(&para_id); earliest_dropped_indices.insert(para_id, earliest_dropped_idx);
let _ = <PendingAvailabilityCommitments<T>>::take(&para_id); }
} }
cleaned_up_cores let mut cleaned_up_cores =
if let Some(capacity) = capacity_hint { Vec::with_capacity(capacity) } else { vec![] };
for (para_id, earliest_dropped_idx) in earliest_dropped_indices {
// Do cleanups and record the cleaned up cores
<PendingAvailability<T>>::mutate(&para_id, |record| {
if let Some(record) = record {
let cleaned_up = record.drain(earliest_dropped_idx..);
cleaned_up_cores.extend(cleaned_up);
}
});
} }
/// Forcibly enact the candidate with the given ID as though it had been deemed available cleaned_up_cores.into_iter()
/// by bitfields. }
/// Forcibly enact the pending candidates of the given paraid as though they had been deemed
/// available by bitfields.
/// ///
/// Is a no-op if there is no candidate pending availability for this para-id. /// Is a no-op if there is no candidate pending availability for this para-id.
/// This should generally not be used but it is useful during execution of Runtime APIs, /// If there are multiple candidates pending availability for this para-id, it will enact all of
/// them. This should generally not be used but it is useful during execution of Runtime APIs,
/// where the changes to the state are expected to be discarded directly after. /// where the changes to the state are expected to be discarded directly after.
pub(crate) fn force_enact(para: ParaId) { pub(crate) fn force_enact(para: ParaId) {
let pending = <PendingAvailability<T>>::take(&para); <PendingAvailability<T>>::mutate(&para, |candidates| {
let commitments = <PendingAvailabilityCommitments<T>>::take(&para); if let Some(candidates) = candidates {
for candidate in candidates.drain(..) {
if let (Some(pending), Some(commitments)) = (pending, commitments) { let receipt = CommittedCandidateReceipt {
let candidate = descriptor: candidate.descriptor,
CommittedCandidateReceipt { descriptor: pending.descriptor, commitments }; commitments: candidate.commitments,
};
Self::enact_candidate( Self::enact_candidate(
pending.relay_parent_number, candidate.relay_parent_number,
candidate, receipt,
pending.backers, candidate.backers,
pending.availability_votes, candidate.availability_votes,
pending.core, candidate.core,
pending.backing_group, candidate.backing_group,
); );
} }
} }
});
}
/// Returns the `CommittedCandidateReceipt` pending availability for the para provided, if any. /// Returns the first `CommittedCandidateReceipt` pending availability for the para provided, if
/// any.
pub(crate) fn candidate_pending_availability( pub(crate) fn candidate_pending_availability(
para: ParaId, para: ParaId,
) -> Option<CommittedCandidateReceipt<T::Hash>> { ) -> Option<CommittedCandidateReceipt<T::Hash>> {
<PendingAvailability<T>>::get(&para) <PendingAvailability<T>>::get(&para).and_then(|p| {
.map(|p| p.descriptor) p.get(0).map(|p| CommittedCandidateReceipt {
.and_then(|d| <PendingAvailabilityCommitments<T>>::get(&para).map(move |c| (d, c))) descriptor: p.descriptor.clone(),
.map(|(d, c)| CommittedCandidateReceipt { descriptor: d, commitments: c }) commitments: p.commitments.clone(),
})
})
} }
/// Returns the metadata around the candidate pending availability for the /// Returns the metadata around the first candidate pending availability for the
/// para provided, if any. /// para provided, if any.
pub(crate) fn pending_availability( pub(crate) fn pending_availability(
para: ParaId, para: ParaId,
) -> Option<CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>> {
<PendingAvailability<T>>::get(&para).and_then(|p| p.get(0).cloned())
}
/// Returns the metadata around the candidate pending availability occupying the supplied core,
/// if any.
pub(crate) fn pending_availability_with_core(
para: ParaId,
core: CoreIndex,
) -> Option<CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>> { ) -> Option<CandidatePendingAvailability<T::Hash, BlockNumberFor<T>>> {
<PendingAvailability<T>>::get(&para) <PendingAvailability<T>>::get(&para)
.and_then(|p| p.iter().find(|c| c.core == core).cloned())
} }
} }
@@ -1182,10 +1170,6 @@ pub(crate) struct CandidateCheckContext<T: Config> {
prev_context: Option<BlockNumberFor<T>>, prev_context: Option<BlockNumberFor<T>>,
} }
/// An error indicating that creating Persisted Validation Data failed
/// while checking a candidate's validity.
pub(crate) struct FailedToCreatePVD;
impl<T: Config> CandidateCheckContext<T> { impl<T: Config> CandidateCheckContext<T> {
pub(crate) fn new(prev_context: Option<BlockNumberFor<T>>) -> Self { pub(crate) fn new(prev_context: Option<BlockNumberFor<T>>) -> Self {
Self { config: <configuration::Pallet<T>>::config(), prev_context } Self { config: <configuration::Pallet<T>>::config(), prev_context }
@@ -1203,9 +1187,9 @@ impl<T: Config> CandidateCheckContext<T> {
pub(crate) fn verify_backed_candidate( pub(crate) fn verify_backed_candidate(
&self, &self,
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
candidate_idx: usize,
backed_candidate_receipt: &CommittedCandidateReceipt<<T as frame_system::Config>::Hash>, backed_candidate_receipt: &CommittedCandidateReceipt<<T as frame_system::Config>::Hash>,
) -> Result<Result<BlockNumberFor<T>, FailedToCreatePVD>, Error<T>> { parent_head_data: HeadData,
) -> Result<BlockNumberFor<T>, Error<T>> {
let para_id = backed_candidate_receipt.descriptor().para_id; let para_id = backed_candidate_receipt.descriptor().para_id;
let relay_parent = backed_candidate_receipt.descriptor().relay_parent; let relay_parent = backed_candidate_receipt.descriptor().relay_parent;
@@ -1218,16 +1202,11 @@ impl<T: Config> CandidateCheckContext<T> {
}; };
{ {
let persisted_validation_data = match crate::util::make_persisted_validation_data::<T>( let persisted_validation_data = make_persisted_validation_data_with_parent::<T>(
para_id,
relay_parent_number, relay_parent_number,
relay_parent_storage_root, relay_parent_storage_root,
) parent_head_data,
.defensive_proof("the para is registered") );
{
Some(l) => l,
None => return Ok(Err(FailedToCreatePVD)),
};
let expected = persisted_validation_data.hash(); let expected = persisted_validation_data.hash();
@@ -1268,13 +1247,13 @@ impl<T: Config> CandidateCheckContext<T> {
) { ) {
log::debug!( log::debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Validation outputs checking during inclusion of a candidate {} for parachain `{}` failed", "Validation outputs checking during inclusion of a candidate {:?} for parachain `{}` failed",
candidate_idx, backed_candidate_receipt.hash(),
u32::from(para_id), u32::from(para_id),
); );
Err(err.strip_into_dispatch_err::<T>())?; Err(err.strip_into_dispatch_err::<T>())?;
}; };
Ok(Ok(relay_parent_number)) Ok(relay_parent_number)
} }
/// Check the given outputs after candidate validation on whether it passes the acceptance /// Check the given outputs after candidate validation on whether it passes the acceptance
File diff suppressed because it is too large Load Diff
@@ -145,10 +145,6 @@ benchmarks! {
assert_eq!(backing_validators.1.len(), votes); assert_eq!(backing_validators.1.len(), votes);
} }
assert_eq!(
inclusion::PendingAvailabilityCommitments::<T>::iter().count(),
cores_with_backed.len()
);
assert_eq!( assert_eq!(
inclusion::PendingAvailability::<T>::iter().count(), inclusion::PendingAvailability::<T>::iter().count(),
cores_with_backed.len() cores_with_backed.len()
@@ -209,10 +205,6 @@ benchmarks! {
); );
} }
assert_eq!(
inclusion::PendingAvailabilityCommitments::<T>::iter().count(),
cores_with_backed.len()
);
assert_eq!( assert_eq!(
inclusion::PendingAvailability::<T>::iter().count(), inclusion::PendingAvailability::<T>::iter().count(),
cores_with_backed.len() cores_with_backed.len()
@@ -24,8 +24,7 @@
use crate::{ use crate::{
configuration, configuration,
disputes::DisputesHandler, disputes::DisputesHandler,
inclusion, inclusion::{self, CandidateCheckContext},
inclusion::CandidateCheckContext,
initializer, initializer,
metrics::METRICS, metrics::METRICS,
paras, paras,
@@ -35,6 +34,7 @@ use crate::{
}; };
use bitvec::prelude::BitVec; use bitvec::prelude::BitVec;
use frame_support::{ use frame_support::{
defensive,
dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo},
inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}, inherent::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent},
pallet_prelude::*, pallet_prelude::*,
@@ -45,7 +45,7 @@ use pallet_babe::{self, ParentBlockRandomness};
use primitives::{ use primitives::{
effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate, effective_minimum_backing_votes, vstaging::node_features::FeatureIndex, BackedCandidate,
CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CandidateHash, CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet,
CoreIndex, DisputeStatementSet, InherentData as ParachainsInherentData, CoreIndex, DisputeStatementSet, HeadData, InherentData as ParachainsInherentData,
MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields,
SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields,
ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER,
@@ -134,18 +134,11 @@ pub mod pallet {
/// The hash of the submitted parent header doesn't correspond to the saved block hash of /// The hash of the submitted parent header doesn't correspond to the saved block hash of
/// the parent. /// the parent.
InvalidParentHeader, InvalidParentHeader,
/// Disputed candidate that was concluded invalid.
CandidateConcludedInvalid,
/// The data given to the inherent will result in an overweight block. /// The data given to the inherent will result in an overweight block.
InherentOverweight, InherentOverweight,
/// The ordering of dispute statements was invalid. /// A candidate was filtered during inherent execution. This should have only been done
DisputeStatementsUnsortedOrDuplicates, /// during creation.
/// A dispute statement was invalid. CandidatesFilteredDuringExecution,
DisputeInvalid,
/// A candidate was backed by a disabled validator
BackedByDisabled,
/// A candidate was backed even though the paraid was not scheduled.
BackedOnUnscheduledCore,
/// Too many candidates supplied. /// Too many candidates supplied.
UnscheduledCandidate, UnscheduledCandidate,
} }
@@ -235,35 +228,6 @@ pub mod pallet {
} }
} }
/// Collect all freed cores based on storage data. (i.e. append cores freed from timeouts to
/// the given `freed_concluded`).
///
/// The parameter `freed_concluded` contains all core indicies that became
/// free due to candidate that became available.
pub(crate) fn collect_all_freed_cores<T, I>(
freed_concluded: I,
) -> BTreeMap<CoreIndex, FreedReason>
where
I: core::iter::IntoIterator<Item = (CoreIndex, CandidateHash)>,
T: Config,
{
// Handle timeouts for any availability core work.
let freed_timeout = if <scheduler::Pallet<T>>::availability_timeout_check_required() {
let pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
<inclusion::Pallet<T>>::collect_pending(pred)
} else {
Vec::new()
};
// Schedule paras again, given freed cores, and reasons for freeing.
let freed = freed_concluded
.into_iter()
.map(|(c, _hash)| (c, FreedReason::Concluded))
.chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut)))
.collect::<BTreeMap<CoreIndex, FreedReason>>();
freed
}
#[pallet::call] #[pallet::call]
impl<T: Config> Pallet<T> { impl<T: Config> Pallet<T> {
/// Enter the paras inherent. This will process bitfields and backed candidates. /// Enter the paras inherent. This will process bitfields and backed candidates.
@@ -319,7 +283,7 @@ impl<T: Config> Pallet<T> {
/// Process inherent data. /// Process inherent data.
/// ///
/// The given inherent data is processed and state is altered accordingly. If any data could /// The given inherent data is processed and state is altered accordingly. If any data could
/// not be applied (inconsitencies, weight limit, ...) it is removed. /// not be applied (inconsistencies, weight limit, ...) it is removed.
/// ///
/// When called from `create_inherent` the `context` must be set to /// When called from `create_inherent` the `context` must be set to
/// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent
@@ -526,7 +490,7 @@ impl<T: Config> Pallet<T> {
// Contains the disputes that are concluded in the current session only, // Contains the disputes that are concluded in the current session only,
// since these are the only ones that are relevant for the occupied cores // since these are the only ones that are relevant for the occupied cores
// and lightens the load on `collect_disputed` significantly. // and lightens the load on `free_disputed` significantly.
// Cores can't be occupied with candidates of the previous sessions, and only // 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 // things with new votes can have just concluded. We only need to collect
// cores with disputes that conclude just now, because disputes that // cores with disputes that conclude just now, because disputes that
@@ -542,21 +506,17 @@ impl<T: Config> Pallet<T> {
.map(|(_session, candidate)| candidate) .map(|(_session, candidate)| candidate)
.collect::<BTreeSet<CandidateHash>>(); .collect::<BTreeSet<CandidateHash>>();
let freed_disputed: BTreeMap<CoreIndex, FreedReason> = // Get the cores freed as a result of concluded invalid candidates.
<inclusion::Pallet<T>>::collect_disputed(&current_concluded_invalid_disputes) let (freed_disputed, concluded_invalid_hashes): (Vec<CoreIndex>, BTreeSet<CandidateHash>) =
<inclusion::Pallet<T>>::free_disputed(&current_concluded_invalid_disputes)
.into_iter() .into_iter()
.map(|core| (core, FreedReason::Concluded)) .unzip();
.collect();
// Create a bit index from the set of core indices where each index corresponds to // 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. // 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. // 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.keys()); let disputed_bitfield = create_disputed_bitfield(expected_bits, freed_disputed.iter());
if !freed_disputed.is_empty() {
<scheduler::Pallet<T>>::free_cores_and_fill_claimqueue(freed_disputed.clone(), now);
}
let bitfields = sanitize_bitfields::<T>( let bitfields = sanitize_bitfields::<T>(
bitfields, bitfields,
@@ -571,11 +531,9 @@ impl<T: Config> Pallet<T> {
// Process new availability bitfields, yielding any availability cores whose // Process new availability bitfields, yielding any availability cores whose
// work has now concluded. // work has now concluded.
let freed_concluded = let freed_concluded =
<inclusion::Pallet<T>>::update_pending_availability_and_get_freed_cores::<_>( <inclusion::Pallet<T>>::update_pending_availability_and_get_freed_cores(
expected_bits,
&validator_public[..], &validator_public[..],
bitfields.clone(), bitfields.clone(),
<scheduler::Pallet<T>>::core_para,
); );
// Inform the disputes module of all included candidates. // Inform the disputes module of all included candidates.
@@ -585,8 +543,24 @@ impl<T: Config> Pallet<T> {
METRICS.on_candidates_included(freed_concluded.len() as u64); METRICS.on_candidates_included(freed_concluded.len() as u64);
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned()); // Get the timed out candidates
let freed_timeout = if <scheduler::Pallet<T>>::availability_timeout_check_required() {
<inclusion::Pallet<T>>::free_timedout()
} else {
Vec::new()
};
if !freed_timeout.is_empty() {
log::debug!(target: LOG_TARGET, "Evicted timed out cores: {:?}", freed_timeout);
}
// We'll schedule paras again, given freed cores, and reasons for freeing.
let freed = freed_concluded
.into_iter()
.map(|(c, _hash)| (c, FreedReason::Concluded))
.chain(freed_disputed.into_iter().map(|core| (core, FreedReason::Concluded)))
.chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut)))
.collect::<BTreeMap<CoreIndex, FreedReason>>();
<scheduler::Pallet<T>>::free_cores_and_fill_claimqueue(freed, now); <scheduler::Pallet<T>>::free_cores_and_fill_claimqueue(freed, now);
METRICS.on_candidates_processed_total(backed_candidates.len() as u64); METRICS.on_candidates_processed_total(backed_candidates.len() as u64);
@@ -605,55 +579,28 @@ impl<T: Config> Pallet<T> {
scheduled.entry(para_id).or_default().insert(core_idx); scheduled.entry(para_id).or_default().insert(core_idx);
} }
let SanitizedBackedCandidates { let initial_candidate_count = backed_candidates.len();
backed_candidates_with_core, let backed_candidates_with_core = sanitize_backed_candidates::<T>(
votes_from_disabled_were_dropped,
dropped_unscheduled_candidates,
} = sanitize_backed_candidates::<T, _>(
backed_candidates, backed_candidates,
&allowed_relay_parents, &allowed_relay_parents,
|candidate_idx: usize, concluded_invalid_hashes,
backed_candidate: &BackedCandidate<<T as frame_system::Config>::Hash>|
-> bool {
let para_id = backed_candidate.descriptor().para_id;
let prev_context = <paras::Pallet<T>>::para_most_recent_context(para_id);
let check_ctx = CandidateCheckContext::<T>::new(prev_context);
// 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.
//
// NOTE: this is the only place where we check the relay-parent.
check_ctx
.verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate.candidate())
.is_err()
},
scheduled, scheduled,
core_index_enabled, core_index_enabled,
); );
let count = count_backed_candidates(&backed_candidates_with_core);
ensure!(count <= total_scheduled_cores, Error::<T>::UnscheduledCandidate);
METRICS.on_candidates_sanitized(count as u64);
// In `Enter` context (invoked during execution) no more candidates should be filtered,
// because they have already been filtered during `ProvideInherent` context. Abort in such
// cases.
if context == ProcessInherentDataContext::Enter {
ensure!( ensure!(
backed_candidates_with_core.len() <= total_scheduled_cores, initial_candidate_count == count,
Error::<T>::UnscheduledCandidate Error::<T>::CandidatesFilteredDuringExecution
); );
METRICS.on_candidates_sanitized(backed_candidates_with_core.len() as u64);
// In `Enter` context (invoked during execution) there should be no backing votes from
// disabled validators because they should have been filtered out during inherent data
// preparation (`ProvideInherent` context). Abort in such cases.
if context == ProcessInherentDataContext::Enter {
ensure!(!votes_from_disabled_were_dropped, Error::<T>::BackedByDisabled);
}
// In `Enter` context (invoked during execution) we shouldn't have filtered any candidates
// due to a para not being scheduled. They have been filtered during inherent data
// preparation (`ProvideInherent` context). Abort in such cases.
if context == ProcessInherentDataContext::Enter {
ensure!(!dropped_unscheduled_candidates, Error::<T>::BackedOnUnscheduledCore);
} }
// Process backed candidates according to scheduled cores. // Process backed candidates according to scheduled cores.
@@ -662,7 +609,7 @@ impl<T: Config> Pallet<T> {
candidate_receipt_with_backing_validator_indices, candidate_receipt_with_backing_validator_indices,
} = <inclusion::Pallet<T>>::process_candidates( } = <inclusion::Pallet<T>>::process_candidates(
&allowed_relay_parents, &allowed_relay_parents,
backed_candidates_with_core.clone(), &backed_candidates_with_core,
<scheduler::Pallet<T>>::group_validators, <scheduler::Pallet<T>>::group_validators,
core_index_enabled, core_index_enabled,
)?; )?;
@@ -683,10 +630,13 @@ impl<T: Config> Pallet<T> {
let processed = ParachainsInherentData { let processed = ParachainsInherentData {
bitfields, bitfields,
backed_candidates: backed_candidates_with_core backed_candidates: backed_candidates_with_core.into_iter().fold(
.into_iter() Vec::with_capacity(count),
.map(|(candidate, _)| candidate) |mut acc, (_id, candidates)| {
.collect(), acc.extend(candidates.into_iter().map(|(c, _)| c));
acc
},
),
disputes, disputes,
parent_header, parent_header,
}; };
@@ -986,83 +936,86 @@ pub(crate) fn sanitize_bitfields<T: crate::inclusion::Config>(
bitfields bitfields
} }
// Result from `sanitize_backed_candidates` /// Performs various filtering on the backed candidates inherent data.
#[derive(Debug, PartialEq)] /// Must maintain the invariant that the returned candidate collection contains the candidates
struct SanitizedBackedCandidates<Hash> { /// sorted in dependency order for each para. When doing any filtering, we must therefore drop any
// Sanitized backed candidates along with the assigned core. The `Vec` is sorted according to /// subsequent candidates after the filtered one.
// the occupied core index. ///
backed_candidates_with_core: Vec<(BackedCandidate<Hash>, CoreIndex)>,
// Set to true if any votes from disabled validators were dropped from the input.
votes_from_disabled_were_dropped: bool,
// Set to true if any candidates were dropped due to filtering done in
// `map_candidates_to_cores`
dropped_unscheduled_candidates: bool,
}
/// Filter out: /// Filter out:
/// 1. any candidates that have a concluded invalid dispute /// 1. any candidates which don't form a chain with the other candidates of the paraid (even if they
/// 2. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned /// do form a chain but are not in the right order).
/// 2. any candidates that have a concluded invalid dispute or who are descendants of a concluded
/// invalid candidate.
/// 3. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned
/// but have no injected core index. /// but have no injected core index.
/// 3. all backing votes from disabled validators /// 4. all backing votes from disabled validators
/// 4. any candidates that end up with less than `effective_minimum_backing_votes` backing votes /// 5. any candidates that end up with less than `effective_minimum_backing_votes` backing votes
/// ///
/// `scheduled` follows the same naming scheme as provided in the /// Returns the scheduled
/// guide: Currently `free` but might become `occupied`. /// backed candidates which passed filtering, mapped by para id and in the right dependency order.
/// For the filtering here the relevant part is only the current `free` fn sanitize_backed_candidates<T: crate::inclusion::Config>(
/// state. backed_candidates: Vec<BackedCandidate<T::Hash>>,
///
/// `candidate_has_concluded_invalid_dispute` must return `true` if the candidate
/// is disputed, false otherwise. The passed `usize` is the candidate index.
///
/// Returns struct `SanitizedBackedCandidates` where `backed_candidates` are sorted according to the
/// occupied core index.
fn sanitize_backed_candidates<
T: crate::inclusion::Config,
F: FnMut(usize, &BackedCandidate<T::Hash>) -> bool,
>(
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
mut candidate_has_concluded_invalid_dispute_or_is_invalid: F, concluded_invalid_with_descendants: BTreeSet<CandidateHash>,
scheduled: BTreeMap<ParaId, BTreeSet<CoreIndex>>, scheduled: BTreeMap<ParaId, BTreeSet<CoreIndex>>,
core_index_enabled: bool, core_index_enabled: bool,
) -> SanitizedBackedCandidates<T::Hash> { ) -> BTreeMap<ParaId, Vec<(BackedCandidate<T::Hash>, CoreIndex)>> {
// Remove any candidates that were concluded invalid. // Map the candidates to the right paraids, while making sure that the order between candidates
// This does not assume sorting. // of the same para is preserved.
backed_candidates.indexed_retain(move |candidate_idx, backed_candidate| { let mut candidates_per_para: BTreeMap<ParaId, Vec<_>> = BTreeMap::new();
!candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate) for candidate in backed_candidates {
candidates_per_para
.entry(candidate.descriptor().para_id)
.or_default()
.push(candidate);
}
// Check that candidates pertaining to the same para form a chain. Drop the ones that
// don't, along with the rest of candidates which follow them in the input vector.
filter_unchained_candidates::<T>(&mut candidates_per_para, allowed_relay_parents);
// Remove any candidates that were concluded invalid or who are descendants of concluded invalid
// candidates (along with their descendants).
retain_candidates::<T, _, _>(&mut candidates_per_para, |_, candidate| {
let keep = !concluded_invalid_with_descendants.contains(&candidate.candidate().hash());
if !keep {
log::debug!(
target: LOG_TARGET,
"Found backed candidate {:?} which was concluded invalid or is a descendant of a concluded invalid candidate, for paraid {:?}.",
candidate.candidate().hash(),
candidate.descriptor().para_id
);
}
keep
}); });
let initial_candidate_count = backed_candidates.len(); // Map candidates to scheduled cores. Filter out any unscheduled candidates along with their
// Map candidates to scheduled cores. Filter out any unscheduled candidates. // descendants.
let mut backed_candidates_with_core = map_candidates_to_cores::<T>( let mut backed_candidates_with_core = map_candidates_to_cores::<T>(
&allowed_relay_parents, &allowed_relay_parents,
scheduled, scheduled,
core_index_enabled, core_index_enabled,
backed_candidates, candidates_per_para,
); );
let dropped_unscheduled_candidates = // Filter out backing statements from disabled validators. If by that we render a candidate with
initial_candidate_count != backed_candidates_with_core.len(); // less backing votes than required, filter that candidate also. As all the other filtering
// operations above, we drop the descendants of the dropped candidates also.
// Filter out backing statements from disabled validators filter_backed_statements_from_disabled_validators::<T>(
let votes_from_disabled_were_dropped = filter_backed_statements_from_disabled_validators::<T>(
&mut backed_candidates_with_core, &mut backed_candidates_with_core,
&allowed_relay_parents, &allowed_relay_parents,
core_index_enabled, core_index_enabled,
); );
// Sort the `Vec` last, once there is a guarantee that these backed_candidates_with_core
// `BackedCandidates` references the expected relay chain parent,
// but more importantly are scheduled for a free core.
// This both avoids extra work for obviously invalid candidates,
// but also allows this to be done in place.
backed_candidates_with_core.sort_by(|(_x, core_x), (_y, core_y)| core_x.cmp(&core_y));
SanitizedBackedCandidates {
dropped_unscheduled_candidates,
votes_from_disabled_were_dropped,
backed_candidates_with_core,
} }
fn count_backed_candidates<B>(backed_candidates: &BTreeMap<ParaId, Vec<B>>) -> usize {
backed_candidates.iter().fold(0, |mut count, (_id, candidates)| {
count += candidates.len();
count
})
} }
/// Derive entropy from babe provided per block randomness. /// Derive entropy from babe provided per block randomness.
@@ -1146,48 +1099,82 @@ fn limit_and_sanitize_disputes<
} }
} }
// Filters statements from disabled validators in `BackedCandidate`, non-scheduled candidates and // Helper function for filtering candidates which don't pass the given predicate. When/if the first
// few more sanity checks. Returns `true` if at least one statement is removed and `false` // candidate which failes the predicate is found, all the other candidates that follow are dropped.
// otherwise. fn retain_candidates<
fn filter_backed_statements_from_disabled_validators<T: shared::Config + scheduler::Config>( T: inclusion::Config + paras::Config + inclusion::Config,
backed_candidates_with_core: &mut Vec<( F: FnMut(ParaId, &mut C) -> bool,
BackedCandidate<<T as frame_system::Config>::Hash>, C,
CoreIndex, >(
)>, candidates_per_para: &mut BTreeMap<ParaId, Vec<C>>,
mut pred: F,
) {
for (para_id, candidates) in candidates_per_para.iter_mut() {
let mut latest_valid_idx = None;
for (idx, candidate) in candidates.iter_mut().enumerate() {
if pred(*para_id, candidate) {
// Found a valid candidate.
latest_valid_idx = Some(idx);
} else {
break
}
}
if let Some(latest_valid_idx) = latest_valid_idx {
candidates.truncate(latest_valid_idx + 1);
} else {
candidates.clear();
}
}
candidates_per_para.retain(|_, c| !c.is_empty());
}
// Filters statements from disabled validators in `BackedCandidate` and does a few more sanity
// checks.
fn filter_backed_statements_from_disabled_validators<
T: shared::Config + scheduler::Config + inclusion::Config,
>(
backed_candidates_with_core: &mut BTreeMap<
ParaId,
Vec<(BackedCandidate<<T as frame_system::Config>::Hash>, CoreIndex)>,
>,
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
core_index_enabled: bool, core_index_enabled: bool,
) -> bool { ) {
let disabled_validators = let disabled_validators =
BTreeSet::<_>::from_iter(shared::Pallet::<T>::disabled_validators().into_iter()); BTreeSet::<_>::from_iter(shared::Pallet::<T>::disabled_validators().into_iter());
if disabled_validators.is_empty() { if disabled_validators.is_empty() {
// No disabled validators - nothing to do // No disabled validators - nothing to do
return false return
} }
let backed_len_before = backed_candidates_with_core.len();
// Flag which will be returned. Set to `true` if at least one vote is filtered.
let mut filtered = false;
let minimum_backing_votes = configuration::Pallet::<T>::config().minimum_backing_votes; let minimum_backing_votes = configuration::Pallet::<T>::config().minimum_backing_votes;
// Process all backed candidates. `validator_indices` in `BackedCandidates` are indices within // Process all backed candidates. `validator_indices` in `BackedCandidates` are indices within
// the validator group assigned to the parachain. To obtain this group we need: // the validator group assigned to the parachain. To obtain this group we need:
// 1. Core index assigned to the parachain which has produced the candidate // 1. Core index assigned to the parachain which has produced the candidate
// 2. The relay chain block number of the candidate // 2. The relay chain block number of the candidate
backed_candidates_with_core.retain_mut(|(bc, core_idx)| { retain_candidates::<T, _, _>(backed_candidates_with_core, |para_id, (bc, core_idx)| {
let (validator_indices, maybe_core_index) = bc.validator_indices_and_core_index(core_index_enabled); let (validator_indices, maybe_core_index) =
bc.validator_indices_and_core_index(core_index_enabled);
let mut validator_indices = BitVec::<_>::from(validator_indices); let mut validator_indices = BitVec::<_>::from(validator_indices);
// Get relay parent block number of the candidate. We need this to get the group index assigned to this core at this block number // Get relay parent block number of the candidate. We need this to get the group index
let relay_parent_block_number = match allowed_relay_parents // assigned to this core at this block number
.acquire_info(bc.descriptor().relay_parent, None) { let relay_parent_block_number =
match allowed_relay_parents.acquire_info(bc.descriptor().relay_parent, None) {
Some((_, block_num)) => block_num, Some((_, block_num)) => block_num,
None => { None => {
log::debug!(target: LOG_TARGET, "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", bc.descriptor().relay_parent); log::debug!(
target: LOG_TARGET,
"Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.",
bc.descriptor().relay_parent
);
return false return false
} },
}; };
// Get the group index for the core // Get the group index for the core
@@ -1208,12 +1195,15 @@ fn filter_backed_statements_from_disabled_validators<T: shared::Config + schedul
None => { None => {
log::debug!(target: LOG_TARGET, "Can't get the validators from group {:?}. Dropping the candidate.", group_idx); log::debug!(target: LOG_TARGET, "Can't get the validators from group {:?}. Dropping the candidate.", group_idx);
return false return false
} },
}; };
// Bitmask with the disabled indices within the validator group // Bitmask with the disabled indices within the validator group
let disabled_indices = BitVec::<u8, bitvec::order::Lsb0>::from_iter(validator_group.iter().map(|idx| disabled_validators.contains(idx))); let disabled_indices = BitVec::<u8, bitvec::order::Lsb0>::from_iter(
// The indices of statements from disabled validators in `BackedCandidate`. We have to drop these. validator_group.iter().map(|idx| disabled_validators.contains(idx)),
);
// The indices of statements from disabled validators in `BackedCandidate`. We have to drop
// these.
let indices_to_drop = disabled_indices.clone() & &validator_indices; let indices_to_drop = disabled_indices.clone() & &validator_indices;
// Apply the bitmask to drop the disabled validator from `validator_indices` // Apply the bitmask to drop the disabled validator from `validator_indices`
validator_indices &= !disabled_indices; validator_indices &= !disabled_indices;
@@ -1225,62 +1215,218 @@ fn filter_backed_statements_from_disabled_validators<T: shared::Config + schedul
bc.validity_votes_mut().remove(idx); bc.validity_votes_mut().remove(idx);
} }
// If at least one statement was dropped we need to return `true`
if indices_to_drop.count_ones() > 0 {
filtered = true;
}
// By filtering votes we might render the candidate invalid and cause a failure in // By filtering votes we might render the candidate invalid and cause a failure in
// [`process_candidates`]. To avoid this we have to perform a sanity check here. If there // [`process_candidates`]. To avoid this we have to perform a sanity check here. If there
// are not enough backing votes after filtering we will remove the whole candidate. // are not enough backing votes after filtering we will remove the whole candidate.
if bc.validity_votes().len() < effective_minimum_backing_votes( if bc.validity_votes().len() <
validator_group.len(), effective_minimum_backing_votes(validator_group.len(), minimum_backing_votes)
minimum_backing_votes {
) { log::debug!(
target: LOG_TARGET,
"Dropping candidate {:?} of paraid {:?} because it was left with too few backing votes after votes from disabled validators were filtered.",
bc.candidate().hash(),
para_id
);
return false return false
} }
true true
}); });
}
// Also return `true` if a whole candidate was dropped from the set // Check that candidates pertaining to the same para form a chain. Drop the ones that
filtered || backed_len_before != backed_candidates_with_core.len() // don't, along with the rest of candidates which follow them in the input vector.
// In the process, duplicated candidates will also be dropped (even if they form a valid cycle;
// cycles are not allowed if they entail backing duplicated candidates).
fn filter_unchained_candidates<T: inclusion::Config + paras::Config + inclusion::Config>(
candidates: &mut BTreeMap<ParaId, Vec<BackedCandidate<T::Hash>>>,
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
) {
let mut para_latest_head_data: BTreeMap<ParaId, HeadData> = BTreeMap::new();
for para_id in candidates.keys() {
let latest_head_data = match <inclusion::Pallet<T>>::para_latest_head_data(&para_id) {
None => {
defensive!("Latest included head data for paraid {:?} is None", para_id);
continue
},
Some(latest_head_data) => latest_head_data,
};
para_latest_head_data.insert(*para_id, latest_head_data);
}
let mut para_visited_candidates: BTreeMap<ParaId, BTreeSet<CandidateHash>> = BTreeMap::new();
retain_candidates::<T, _, _>(candidates, |para_id, candidate| {
let Some(latest_head_data) = para_latest_head_data.get(&para_id) else { return false };
let candidate_hash = candidate.candidate().hash();
let visited_candidates =
para_visited_candidates.entry(para_id).or_insert_with(|| BTreeSet::new());
if visited_candidates.contains(&candidate_hash) {
log::debug!(
target: LOG_TARGET,
"Found duplicate candidates for paraid {:?}. Dropping the candidates with hash {:?}",
para_id,
candidate_hash
);
// If we got a duplicate candidate, stop.
return false
} else {
visited_candidates.insert(candidate_hash);
}
let prev_context = <paras::Pallet<T>>::para_most_recent_context(para_id);
let check_ctx = CandidateCheckContext::<T>::new(prev_context);
let res = match check_ctx.verify_backed_candidate(
&allowed_relay_parents,
candidate.candidate(),
latest_head_data.clone(),
) {
Ok(_) => true,
Err(err) => {
log::debug!(
target: LOG_TARGET,
"Backed candidate verification for candidate {:?} of paraid {:?} failed with {:?}",
candidate_hash,
para_id,
err
);
false
},
};
if res {
para_latest_head_data
.insert(para_id, candidate.candidate().commitments.head_data.clone());
}
res
});
} }
/// Map candidates to scheduled cores. /// Map candidates to scheduled cores.
/// If the para only has one scheduled core and no `CoreIndex` is injected, map the candidate to the /// If the para only has one scheduled core and one candidate supplied, map the candidate to the
/// single core. If the para has multiple cores scheduled, only map the candidates which have a /// single core. If the para has multiple cores scheduled, only map the candidates which have a
/// proper core injected. Filter out the rest. /// proper core injected. Filter out the rest.
/// Also returns whether or not we dropped any candidates. /// Also returns whether or not we dropped any candidates.
/// When dropping a candidate of a para, we must drop all subsequent candidates from that para
/// (because they form a chain).
fn map_candidates_to_cores<T: configuration::Config + scheduler::Config + inclusion::Config>( fn map_candidates_to_cores<T: configuration::Config + scheduler::Config + inclusion::Config>(
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
mut scheduled: BTreeMap<ParaId, BTreeSet<CoreIndex>>, mut scheduled: BTreeMap<ParaId, BTreeSet<CoreIndex>>,
core_index_enabled: bool, core_index_enabled: bool,
candidates: Vec<BackedCandidate<T::Hash>>, candidates: BTreeMap<ParaId, Vec<BackedCandidate<T::Hash>>>,
) -> Vec<(BackedCandidate<T::Hash>, CoreIndex)> { ) -> BTreeMap<ParaId, Vec<(BackedCandidate<T::Hash>, CoreIndex)>> {
let mut backed_candidates_with_core = Vec::with_capacity(candidates.len()); let mut backed_candidates_with_core = BTreeMap::new();
// We keep a candidate if the parachain has only one core assigned or if for (para_id, backed_candidates) in candidates.into_iter() {
// a core index is provided by block author and it's indeed scheduled. if backed_candidates.len() == 0 {
for backed_candidate in candidates { defensive!("Backed candidates for paraid {} is empty.", para_id);
let maybe_injected_core_index = get_injected_core_index::<T>( continue
allowed_relay_parents, }
&backed_candidate,
core_index_enabled, let scheduled_cores = scheduled.get_mut(&para_id);
// ParaIds without scheduled cores are silently filtered out.
if let Some(scheduled_cores) = scheduled_cores {
if scheduled_cores.len() == 0 {
log::debug!(
target: LOG_TARGET,
"Paraid: {:?} has no scheduled cores but {} candidates were supplied.",
para_id,
backed_candidates.len()
); );
let scheduled_cores = scheduled.get_mut(&backed_candidate.descriptor().para_id); // Non-elastic scaling case. One core per para.
// Candidates without scheduled cores are silently filtered out. } else if scheduled_cores.len() == 1 && !core_index_enabled {
if let Some(scheduled_cores) = scheduled_cores { backed_candidates_with_core.insert(
if let Some(core_idx) = maybe_injected_core_index { para_id,
if scheduled_cores.contains(&core_idx) { vec![(
scheduled_cores.remove(&core_idx); // We need the first one here, as we assume candidates of a para are in
backed_candidates_with_core.push((backed_candidate, core_idx)); // dependency order.
backed_candidates.into_iter().next().expect("Length is at least 1"),
scheduled_cores.pop_first().expect("Length is 1"),
)],
);
continue;
// Elastic scaling case. We only allow candidates which have the right core
// indices injected.
} else if scheduled_cores.len() >= 1 && core_index_enabled {
// We must preserve the dependency order given in the input.
let mut temp_backed_candidates = Vec::with_capacity(scheduled_cores.len());
for candidate in backed_candidates {
if scheduled_cores.len() == 0 {
// We've got candidates for all of this para's assigned cores. Move on to
// the next para.
log::debug!(
target: LOG_TARGET,
"Found enough candidates for paraid: {:?}.",
candidate.descriptor().para_id
);
break;
} }
} else if scheduled_cores.len() == 1 { let maybe_injected_core_index: Option<CoreIndex> =
get_injected_core_index::<T>(allowed_relay_parents, &candidate);
if let Some(core_index) = maybe_injected_core_index {
if scheduled_cores.remove(&core_index) {
temp_backed_candidates.push((candidate, core_index));
} else {
// if we got a candidate for a core index which is not scheduled, stop
// the work for this para. the already processed candidate chain in
// temp_backed_candidates is still fine though.
log::debug!(
target: LOG_TARGET,
"Found a backed candidate {:?} with injected core index {}, which is not scheduled for paraid {:?}.",
candidate.candidate().hash(),
core_index.0,
candidate.descriptor().para_id
);
break;
}
} else {
// if we got a candidate which does not contain its core index, stop the
// work for this para. the already processed candidate chain in
// temp_backed_candidates is still fine though.
log::debug!(
target: LOG_TARGET,
"Found a backed candidate {:?} with no injected core index, for paraid {:?} which has multiple scheduled cores.",
candidate.candidate().hash(),
candidate.descriptor().para_id
);
break;
}
}
if !temp_backed_candidates.is_empty() {
backed_candidates_with_core backed_candidates_with_core
.push((backed_candidate, scheduled_cores.pop_first().expect("Length is 1"))); .entry(para_id)
.or_insert_with(|| vec![])
.extend(temp_backed_candidates);
} }
} else {
log::warn!(
target: LOG_TARGET,
"Found a paraid {:?} which has multiple scheduled cores but ElasticScalingMVP feature is not enabled: {:?}",
para_id,
scheduled_cores
);
}
} else {
log::debug!(
target: LOG_TARGET,
"Paraid: {:?} has no scheduled cores but {} candidates were supplied.",
para_id,
backed_candidates.len()
);
} }
} }
@@ -1290,13 +1436,11 @@ fn map_candidates_to_cores<T: configuration::Config + scheduler::Config + inclus
fn get_injected_core_index<T: configuration::Config + scheduler::Config + inclusion::Config>( fn get_injected_core_index<T: configuration::Config + scheduler::Config + inclusion::Config>(
allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>, allowed_relay_parents: &AllowedRelayParentsTracker<T::Hash, BlockNumberFor<T>>,
candidate: &BackedCandidate<T::Hash>, candidate: &BackedCandidate<T::Hash>,
core_index_enabled: bool,
) -> Option<CoreIndex> { ) -> Option<CoreIndex> {
// After stripping the 8 bit extensions, the `validator_indices` field length is expected // After stripping the 8 bit extensions, the `validator_indices` field length is expected
// to be equal to backing group size. If these don't match, the `CoreIndex` is badly encoded, // to be equal to backing group size. If these don't match, the `CoreIndex` is badly encoded,
// or not supported. // or not supported.
let (validator_indices, maybe_core_idx) = let (validator_indices, maybe_core_idx) = candidate.validator_indices_and_core_index(true);
candidate.validator_indices_and_core_index(core_index_enabled);
let Some(core_idx) = maybe_core_idx else { return None }; let Some(core_idx) = maybe_core_idx else { return None };
@@ -1306,7 +1450,7 @@ fn get_injected_core_index<T: configuration::Config + scheduler::Config + inclus
None => { None => {
log::debug!( log::debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Relay parent {:?} for candidate {:?} is not in the allowed relay parents. Dropping the candidate.", "Relay parent {:?} for candidate {:?} is not in the allowed relay parents.",
candidate.descriptor().relay_parent, candidate.descriptor().relay_parent,
candidate.candidate().hash(), candidate.candidate().hash(),
); );
@@ -1323,9 +1467,8 @@ fn get_injected_core_index<T: configuration::Config + scheduler::Config + inclus
None => { None => {
log::debug!( log::debug!(
target: LOG_TARGET, target: LOG_TARGET,
"Can't get the group index for core idx {:?}. Dropping the candidate {:?}.", "Can't get the group index for core idx {:?}.",
core_idx, core_idx,
candidate.candidate().hash(),
); );
return None return None
}, },
@@ -1339,6 +1482,14 @@ fn get_injected_core_index<T: configuration::Config + scheduler::Config + inclus
if group_validators.len() == validator_indices.len() { if group_validators.len() == validator_indices.len() {
Some(core_idx) Some(core_idx)
} else { } else {
log::debug!(
target: LOG_TARGET,
"Expected validator_indices count different than the real one: {}, {} for candidate {:?}",
group_validators.len(),
validator_indices.len(),
candidate.candidate().hash()
);
None None
} }
} }
File diff suppressed because it is too large Load Diff
@@ -22,6 +22,7 @@ use crate::{
scheduler::{self, CoreOccupied}, scheduler::{self, CoreOccupied},
session_info, shared, session_info, shared,
}; };
use frame_support::traits::{GetStorageVersion, StorageVersion};
use frame_system::pallet_prelude::*; use frame_system::pallet_prelude::*;
use primitives::{ use primitives::{
async_backing::{ async_backing::{
@@ -92,16 +93,41 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, Bl
.enumerate() .enumerate()
.map(|(i, core)| match core { .map(|(i, core)| match core {
CoreOccupied::Paras(entry) => { CoreOccupied::Paras(entry) => {
let pending_availability = // Due to https://github.com/paritytech/polkadot-sdk/issues/64, using the new storage types would cause
<inclusion::Pallet<T>>::pending_availability(entry.para_id()) // this runtime API to panic. We explicitly handle the storage for version 0 to
// prevent that. When removing the inclusion v0 -> v1 migration, this bit of code
// can also be removed.
let pending_availability = if <inclusion::Pallet<T>>::on_chain_storage_version() ==
StorageVersion::new(0)
{
inclusion::migration::v0::PendingAvailability::<T>::get(entry.para_id())
.expect("Occupied core always has pending availability; qed")
} else {
let candidate = <inclusion::Pallet<T>>::pending_availability_with_core(
entry.para_id(),
CoreIndex(i as u32),
)
.expect("Occupied core always has pending availability; qed"); .expect("Occupied core always has pending availability; qed");
let backed_in_number = *pending_availability.backed_in_number(); // Translate to the old candidate format, as we don't need the commitments now.
inclusion::migration::v0::CandidatePendingAvailability {
core: candidate.core_occupied(),
hash: candidate.candidate_hash(),
descriptor: candidate.candidate_descriptor().clone(),
availability_votes: candidate.availability_votes().clone(),
backers: candidate.backers().clone(),
relay_parent_number: candidate.relay_parent_number(),
backed_in_number: candidate.backed_in_number(),
backing_group: candidate.backing_group(),
}
};
let backed_in_number = pending_availability.backed_in_number;
// Use the same block number for determining the responsible group as what the // Use the same block number for determining the responsible group as what the
// backing subsystem would use when it calls validator_groups api. // backing subsystem would use when it calls validator_groups api.
let backing_group_allocation_time = let backing_group_allocation_time =
pending_availability.relay_parent_number() + One::one(); pending_availability.relay_parent_number + One::one();
CoreState::Occupied(OccupiedCore { CoreState::Occupied(OccupiedCore {
next_up_on_available: <scheduler::Pallet<T>>::next_up_on_available(CoreIndex( next_up_on_available: <scheduler::Pallet<T>>::next_up_on_available(CoreIndex(
i as u32, i as u32,
@@ -111,13 +137,13 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, Bl
next_up_on_time_out: <scheduler::Pallet<T>>::next_up_on_time_out(CoreIndex( next_up_on_time_out: <scheduler::Pallet<T>>::next_up_on_time_out(CoreIndex(
i as u32, i as u32,
)), )),
availability: pending_availability.availability_votes().clone(), availability: pending_availability.availability_votes.clone(),
group_responsible: group_responsible_for( group_responsible: group_responsible_for(
backing_group_allocation_time, backing_group_allocation_time,
pending_availability.core_occupied(), pending_availability.core,
), ),
candidate_hash: pending_availability.candidate_hash(), candidate_hash: pending_availability.hash,
candidate_descriptor: pending_availability.candidate_descriptor().clone(), candidate_descriptor: pending_availability.descriptor,
}) })
}, },
CoreOccupied::Free => { CoreOccupied::Free => {
@@ -200,8 +226,8 @@ pub fn assumed_validation_data<T: initializer::Config>(
}; };
let persisted_validation_data = make_validation_data().or_else(|| { let persisted_validation_data = make_validation_data().or_else(|| {
// Try again with force enacting the core. This check only makes sense if // Try again with force enacting the pending candidates. This check only makes sense if
// the core is occupied. // there are any pending candidates.
<inclusion::Pallet<T>>::pending_availability(para_id).and_then(|_| { <inclusion::Pallet<T>>::pending_availability(para_id).and_then(|_| {
<inclusion::Pallet<T>>::force_enact(para_id); <inclusion::Pallet<T>>::force_enact(para_id);
make_validation_data() make_validation_data()
@@ -465,27 +491,23 @@ pub fn backing_state<T: initializer::Config>(
}; };
let pending_availability = { let pending_availability = {
// Note: the API deals with a `Vec` as it is future-proof for cases
// where there may be multiple candidates pending availability at a time.
// But at the moment only one candidate can be pending availability per
// parachain.
crate::inclusion::PendingAvailability::<T>::get(&para_id) crate::inclusion::PendingAvailability::<T>::get(&para_id)
.and_then(|pending| { .map(|pending_candidates| {
let commitments = pending_candidates
crate::inclusion::PendingAvailabilityCommitments::<T>::get(&para_id); .into_iter()
commitments.map(move |c| (pending, c)) .map(|candidate| {
})
.map(|(pending, commitments)| {
CandidatePendingAvailability { CandidatePendingAvailability {
candidate_hash: pending.candidate_hash(), candidate_hash: candidate.candidate_hash(),
descriptor: pending.candidate_descriptor().clone(), descriptor: candidate.candidate_descriptor().clone(),
commitments, commitments: candidate.candidate_commitments().clone(),
relay_parent_number: pending.relay_parent_number(), relay_parent_number: candidate.relay_parent_number(),
max_pov_size: constraints.max_pov_size, // assume always same in session. max_pov_size: constraints.max_pov_size, /* assume always same in
* session. */
} }
}) })
.into_iter()
.collect() .collect()
})
.unwrap_or_else(|| vec![])
}; };
Some(BackingState { constraints, pending_availability }) Some(BackingState { constraints, pending_availability })
@@ -398,16 +398,6 @@ impl<T: Config> Pallet<T> {
}); });
} }
/// Get the para (chain or thread) ID assigned to a particular core or index, if any. Core
/// indices out of bounds will return `None`, as will indices of unassigned cores.
pub(crate) fn core_para(core_index: CoreIndex) -> Option<ParaId> {
let cores = AvailabilityCores::<T>::get();
match cores.get(core_index.0 as usize) {
None | Some(CoreOccupied::Free) => None,
Some(CoreOccupied::Paras(entry)) => Some(entry.para_id()),
}
}
/// Get the validators in the given group, if the group index is valid for this session. /// Get the validators in the given group, if the group index is valid for this session.
pub(crate) fn group_validators(group_index: GroupIndex) -> Option<Vec<ValidatorIndex>> { pub(crate) fn group_validators(group_index: GroupIndex) -> Option<Vec<ValidatorIndex>> {
ValidatorGroups::<T>::get().get(group_index.0 as usize).map(|g| g.clone()) ValidatorGroups::<T>::get().get(group_index.0 as usize).map(|g| g.clone())
+18 -1
View File
@@ -18,7 +18,7 @@
//! on all modules. //! on all modules.
use frame_system::pallet_prelude::BlockNumberFor; use frame_system::pallet_prelude::BlockNumberFor;
use primitives::{Id as ParaId, PersistedValidationData, ValidatorIndex}; use primitives::{HeadData, Id as ParaId, PersistedValidationData, ValidatorIndex};
use sp_std::{collections::btree_set::BTreeSet, vec::Vec}; use sp_std::{collections::btree_set::BTreeSet, vec::Vec};
use crate::{configuration, hrmp, paras}; use crate::{configuration, hrmp, paras};
@@ -42,6 +42,23 @@ pub fn make_persisted_validation_data<T: paras::Config + hrmp::Config>(
}) })
} }
/// Make the persisted validation data for a particular parachain, a specified relay-parent, its
/// storage root and parent head data.
pub fn make_persisted_validation_data_with_parent<T: configuration::Config>(
relay_parent_number: BlockNumberFor<T>,
relay_parent_storage_root: T::Hash,
parent_head: HeadData,
) -> PersistedValidationData<T::Hash, BlockNumberFor<T>> {
let config = <configuration::Pallet<T>>::config();
PersistedValidationData {
parent_head,
relay_parent_number,
relay_parent_storage_root,
max_pov_size: config.max_pov_size,
}
}
/// Take an active subset of a set containing all validators. /// Take an active subset of a set containing all validators.
/// ///
/// First item in pair will be all items in set have indices found in the `active` indices set (in /// First item in pair will be all items in set have indices found in the `active` indices set (in
+2
View File
@@ -1663,6 +1663,8 @@ pub mod migrations {
// permanent // permanent
pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>, pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,
parachains_inclusion::migration::MigrateToV1<Runtime>,
); );
} }
@@ -13,161 +13,322 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. // along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Autogenerated weights for `runtime_parachains::paras_inherent` //! Autogenerated weights for `runtime_parachains::paras_inherent`
//! //!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2021-11-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 128 //! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024
// Executed Command: // Executed Command:
// target/release/polkadot // target/production/polkadot
// benchmark // benchmark
// --chain=rococo-dev // pallet
// --steps=50 // --steps=50
// --repeat=20 // --repeat=20
// --pallet=runtime_parachains::paras_inherent
// --extrinsic=* // --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled // --wasm-execution=compiled
// --heap-pages=4096 // --heap-pages=4096
// --output=./runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
// --header=./file_header.txt // --pallet=runtime_parachains::paras_inherent
// --chain=rococo-dev
// --header=./polkadot/file_header.txt
// --output=./polkadot/runtime/rococo/src/weights/
#![cfg_attr(rustfmt, rustfmt_skip)] #![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)] #![allow(unused_parens)]
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(missing_docs)]
use frame_support::{traits::Get, weights::Weight}; use frame_support::{traits::Get, weights::Weight};
use sp_std::marker::PhantomData; use core::marker::PhantomData;
/// Weight functions for `runtime_parachains::paras_inherent`. /// Weight functions for `runtime_parachains::paras_inherent`.
pub struct WeightInfo<T>(PhantomData<T>); pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> { impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
// Storage: System ParentHash (r:1 w:0) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `System::ParentHash` (r:1 w:0)
// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
// Storage: Configuration ActiveConfig (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
// Storage: ParaSessionInfo Sessions (r:1 w:0) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParasDisputes Disputes (r:1 w:1) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
// Storage: ParasDisputes Included (r:1 w:1) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParasDisputes SpamSlots (r:1 w:1) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
// Storage: ParasDisputes Frozen (r:1 w:0) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras Parachains (r:1 w:0) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0)
// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `ParasDisputes::Disputes` (r:1 w:1)
// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1)
// Storage: ParaScheduler Scheduled (r:1 w:1) /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Storage: `ParasDisputes::Included` (r:1 w:1)
// Storage: Ump NeedsDispatch (r:1 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
// Storage: ParaInherent OnChainVotes (r:0 w:1) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
// Storage: Paras Heads (r:0 w:1) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaInclusion::V1` (r:2 w:1)
/// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
/// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
/// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::Paras` (r:1 w:0)
/// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::Heads` (r:0 w:1)
/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `v` is `[10, 200]`.
fn enter_variable_disputes(v: u32, ) -> Weight { fn enter_variable_disputes(v: u32, ) -> Weight {
Weight::from_parts(352_590_000 as u64, 0) // Proof Size summary in bytes:
// Standard Error: 13_000 // Measured: `67785`
.saturating_add(Weight::from_parts(49_254_000 as u64, 0).saturating_mul(v as u64)) // Estimated: `73725 + v * (23 ±0)`
.saturating_add(T::DbWeight::get().reads(24 as u64)) // Minimum execution time: 949_716_000 picoseconds.
.saturating_add(T::DbWeight::get().writes(16 as u64)) Weight::from_parts(482_361_515, 0)
.saturating_add(Weight::from_parts(0, 73725))
// Standard Error: 17_471
.saturating_add(Weight::from_parts(50_100_764, 0).saturating_mul(v.into()))
.saturating_add(T::DbWeight::get().reads(25))
.saturating_add(T::DbWeight::get().writes(15))
.saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into()))
} }
// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
// Storage: System ParentHash (r:1 w:0) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `System::ParentHash` (r:1 w:0)
// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
// Storage: Configuration ActiveConfig (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
// Storage: ParasDisputes Frozen (r:1 w:0) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
// Storage: Paras Parachains (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
// Storage: ParasDisputes Disputes (r:1 w:0) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Ump NeedsDispatch (r:1 w:1) /// Storage: `ParaInclusion::V1` (r:2 w:1)
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
// Storage: ParaInherent OnChainVotes (r:0 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Paras Heads (r:0 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::Paras` (r:1 w:0)
/// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::Heads` (r:0 w:1)
/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn enter_bitfields() -> Weight { fn enter_bitfields() -> Weight {
Weight::from_parts(299_878_000 as u64, 0) // Proof Size summary in bytes:
.saturating_add(T::DbWeight::get().reads(21 as u64)) // Measured: `42757`
.saturating_add(T::DbWeight::get().writes(15 as u64)) // Estimated: `48697`
// Minimum execution time: 437_627_000 picoseconds.
Weight::from_parts(460_975_000, 0)
.saturating_add(Weight::from_parts(0, 48697))
.saturating_add(T::DbWeight::get().reads(23))
.saturating_add(T::DbWeight::get().writes(15))
} }
// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
// Storage: System ParentHash (r:1 w:0) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `System::ParentHash` (r:1 w:0)
// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
// Storage: Configuration ActiveConfig (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
// Storage: ParasDisputes Frozen (r:1 w:0) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
// Storage: Paras Parachains (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
// Storage: ParasDisputes Disputes (r:2 w:0) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras PastCodeMeta (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
// Storage: Paras CurrentCodeHash (r:1 w:0) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Ump RelayDispatchQueueSize (r:1 w:0) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
// Storage: Ump NeedsDispatch (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
// Storage: ParaInherent OnChainVotes (r:0 w:1) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Paras Heads (r:0 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
fn enter_backed_candidates_variable(_v: u32) -> Weight { /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
Weight::from_parts(442_472_000 as u64, 0) /// Storage: `Registrar::Paras` (r:1 w:0)
.saturating_add(T::DbWeight::get().reads(25 as u64)) /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`)
.saturating_add(T::DbWeight::get().writes(14 as u64)) /// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::CurrentCodeHash` (r:1 w:0)
/// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::ParaLifecycles` (r:1 w:0)
/// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:0)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`)
/// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::Heads` (r:0 w:1)
/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `v` is `[101, 200]`.
fn enter_backed_candidates_variable(v: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `42829`
// Estimated: `48769`
// Minimum execution time: 1_305_254_000 picoseconds.
Weight::from_parts(1_347_160_667, 0)
.saturating_add(Weight::from_parts(0, 48769))
// Standard Error: 22_128
.saturating_add(Weight::from_parts(57_229, 0).saturating_mul(v.into()))
.saturating_add(T::DbWeight::get().reads(26))
.saturating_add(T::DbWeight::get().writes(15))
} }
// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
// Storage: System ParentHash (r:1 w:0) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `System::ParentHash` (r:1 w:0)
// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
// Storage: Configuration ActiveConfig (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
// Storage: ParasDisputes Frozen (r:1 w:0) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
// Storage: Paras Parachains (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
// Storage: ParasDisputes Disputes (r:2 w:0) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
// Storage: Paras PastCodeMeta (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
// Storage: Paras CurrentCodeHash (r:1 w:0) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Ump RelayDispatchQueueSize (r:1 w:0) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
// Storage: Ump NeedsDispatch (r:1 w:1) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Ump NextDispatchRoundStartWith (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
// Storage: ParaInherent OnChainVotes (r:0 w:1) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
// Storage: Paras Heads (r:0 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Registrar::Paras` (r:1 w:0)
/// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::CurrentCodeHash` (r:1 w:0)
/// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::FutureCodeHash` (r:1 w:0)
/// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:0)
/// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::ParaLifecycles` (r:1 w:0)
/// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `MessageQueue::BookStateFor` (r:1 w:0)
/// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`)
/// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::Heads` (r:0 w:1)
/// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn enter_backed_candidate_code_upgrade() -> Weight { fn enter_backed_candidate_code_upgrade() -> Weight {
Weight::from_parts(36_903_411_000 as u64, 0) // Proof Size summary in bytes:
.saturating_add(T::DbWeight::get().reads(25 as u64)) // Measured: `42842`
.saturating_add(T::DbWeight::get().writes(14 as u64)) // Estimated: `48782`
// Minimum execution time: 38_637_547_000 picoseconds.
Weight::from_parts(41_447_412_000, 0)
.saturating_add(Weight::from_parts(0, 48782))
.saturating_add(T::DbWeight::get().reads(28))
.saturating_add(T::DbWeight::get().writes(15))
} }
} }
+1
View File
@@ -1781,6 +1781,7 @@ pub mod migrations {
crate::xcm_config::XcmRouter, crate::xcm_config::XcmRouter,
GetLegacyLeaseImpl, GetLegacyLeaseImpl,
>, >,
parachains_inclusion::migration::MigrateToV1<Runtime>,
); );
} }
@@ -16,11 +16,11 @@
//! Autogenerated weights for `runtime_parachains::paras_inherent` //! Autogenerated weights for `runtime_parachains::paras_inherent`
//! //!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
//! DATE: 2023-06-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000` //! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
// Executed Command: // Executed Command:
// target/production/polkadot // target/production/polkadot
@@ -29,14 +29,13 @@
// --steps=50 // --steps=50
// --repeat=20 // --repeat=20
// --extrinsic=* // --extrinsic=*
// --execution=wasm
// --wasm-execution=compiled // --wasm-execution=compiled
// --heap-pages=4096 // --heap-pages=4096
// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
// --pallet=runtime_parachains::paras_inherent // --pallet=runtime_parachains::paras_inherent
// --chain=westend-dev // --chain=westend-dev
// --header=./file_header.txt // --header=./polkadot/file_header.txt
// --output=./runtime/westend/src/weights/ // --output=./polkadot/runtime/westend/src/weights/
#![cfg_attr(rustfmt, rustfmt_skip)] #![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)] #![allow(unused_parens)]
@@ -49,297 +48,311 @@ use core::marker::PhantomData;
/// Weight functions for `runtime_parachains::paras_inherent`. /// Weight functions for `runtime_parachains::paras_inherent`.
pub struct WeightInfo<T>(PhantomData<T>); pub struct WeightInfo<T>(PhantomData<T>);
impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> { impl<T: frame_system::Config> runtime_parachains::paras_inherent::WeightInfo for WeightInfo<T> {
/// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
/// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: System ParentHash (r:1 w:0) /// Storage: `System::ParentHash` (r:1 w:0)
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Babe AuthorVrfRandomness (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaSessionInfo Sessions (r:1 w:0) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
/// Proof Skipped: ParaSessionInfo Sessions (max_values: None, max_size: None, mode: Measured) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
/// Storage: ParasDisputes Disputes (r:1 w:1) /// Storage: `ParaSessionInfo::Sessions` (r:1 w:0)
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaSessionInfo::Sessions` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes BackersOnDisputes (r:1 w:1) /// Storage: `ParasDisputes::Disputes` (r:1 w:1)
/// Proof Skipped: ParasDisputes BackersOnDisputes (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Included (r:1 w:1) /// Storage: `ParasDisputes::BackersOnDisputes` (r:1 w:1)
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::BackersOnDisputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0) /// Storage: `ParasDisputes::Included` (r:1 w:1)
/// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Session Validators (r:1 w:0) /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0)
/// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Staking ActiveEra (r:1 w:0) /// Storage: `Session::Validators` (r:1 w:0)
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Staking ErasRewardPoints (r:1 w:1) /// Storage: `Staking::ActiveEra` (r:1 w:0)
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`)
/// Storage: ParaInherent OnChainVotes (r:1 w:1) /// Storage: `Staking::ErasRewardPoints` (r:1 w:1)
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Frozen (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Paras Parachains (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DeliveryFeeFactor (r:1 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Paras Heads (r:0 w:1) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) /// Storage: `Paras::Heads` (r:0 w:1)
/// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `v` is `[10, 200]`. /// The range of component `v` is `[10, 200]`.
fn enter_variable_disputes(v: u32, ) -> Weight { fn enter_variable_disputes(v: u32, ) -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `50518` // Measured: `67518`
// Estimated: `56458 + v * (23 ±0)` // Estimated: `73458 + v * (23 ±0)`
// Minimum execution time: 998_338_000 picoseconds. // Minimum execution time: 844_022_000 picoseconds.
Weight::from_parts(468_412_001, 0) Weight::from_parts(456_682_337, 0)
.saturating_add(Weight::from_parts(0, 56458)) .saturating_add(Weight::from_parts(0, 73458))
// Standard Error: 20_559 // Standard Error: 16_403
.saturating_add(Weight::from_parts(56_965_025, 0).saturating_mul(v.into())) .saturating_add(Weight::from_parts(41_871_245, 0).saturating_mul(v.into()))
.saturating_add(T::DbWeight::get().reads(27)) .saturating_add(T::DbWeight::get().reads(28))
.saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes(16))
.saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into()))
} }
/// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
/// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: System ParentHash (r:1 w:0) /// Storage: `System::ParentHash` (r:1 w:0)
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Babe AuthorVrfRandomness (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInherent OnChainVotes (r:1 w:1) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
/// Storage: ParasDisputes Frozen (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Paras Parachains (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0) /// Storage: `Session::Validators` (r:1 w:0)
/// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Session Validators (r:1 w:0) /// Storage: `Staking::ActiveEra` (r:1 w:0)
/// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`)
/// Storage: Staking ActiveEra (r:1 w:0) /// Storage: `Staking::ErasRewardPoints` (r:1 w:1)
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Staking ErasRewardPoints (r:1 w:1) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DeliveryFeeFactor (r:1 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Disputes (r:1 w:0) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion AvailabilityBitfields (r:0 w:1) /// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof Skipped: ParaInclusion AvailabilityBitfields (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras Heads (r:0 w:1) /// Storage: `Paras::Heads` (r:0 w:1)
/// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn enter_bitfields() -> Weight { fn enter_bitfields() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `42352` // Measured: `43196`
// Estimated: `48292` // Estimated: `49136`
// Minimum execution time: 457_404_000 picoseconds. // Minimum execution time: 438_637_000 picoseconds.
Weight::from_parts(485_416_000, 0) Weight::from_parts(458_342_000, 0)
.saturating_add(Weight::from_parts(0, 48292)) .saturating_add(Weight::from_parts(0, 49136))
.saturating_add(T::DbWeight::get().reads(25)) .saturating_add(T::DbWeight::get().reads(26))
.saturating_add(T::DbWeight::get().writes(16)) .saturating_add(T::DbWeight::get().writes(16))
} }
/// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
/// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: System ParentHash (r:1 w:0) /// Storage: `System::ParentHash` (r:1 w:0)
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Babe AuthorVrfRandomness (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInherent OnChainVotes (r:1 w:1) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
/// Storage: ParasDisputes Frozen (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Paras Parachains (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0) /// Storage: `Session::Validators` (r:1 w:0)
/// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Session Validators (r:1 w:0) /// Storage: `Staking::ActiveEra` (r:1 w:0)
/// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`)
/// Storage: Staking ActiveEra (r:1 w:0) /// Storage: `Staking::ErasRewardPoints` (r:1 w:1)
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Staking ErasRewardPoints (r:1 w:1) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DeliveryFeeFactor (r:1 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Disputes (r:1 w:0) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0)
/// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras CurrentCodeHash (r:1 w:0) /// Storage: `Paras::ParaLifecycles` (r:1 w:0)
/// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras ParaLifecycles (r:1 w:0) /// Storage: `MessageQueue::BookStateFor` (r:1 w:0)
/// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`)
/// Storage: MessageQueue BookStateFor (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras Heads (r:0 w:1) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) /// Storage: `Paras::Heads` (r:0 w:1)
/// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// The range of component `v` is `[101, 200]`. /// The range of component `v` is `[101, 200]`.
fn enter_backed_candidates_variable(v: u32, ) -> Weight { fn enter_backed_candidates_variable(v: u32, ) -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `42387` // Measured: `43269`
// Estimated: `48327` // Estimated: `49209`
// Minimum execution time: 6_864_029_000 picoseconds. // Minimum execution time: 5_955_361_000 picoseconds.
Weight::from_parts(1_237_704_892, 0) Weight::from_parts(1_285_398_956, 0)
.saturating_add(Weight::from_parts(0, 48327)) .saturating_add(Weight::from_parts(0, 49209))
// Standard Error: 33_413 // Standard Error: 57_369
.saturating_add(Weight::from_parts(56_199_819, 0).saturating_mul(v.into())) .saturating_add(Weight::from_parts(47_073_853, 0).saturating_mul(v.into()))
.saturating_add(T::DbWeight::get().reads(28)) .saturating_add(T::DbWeight::get().reads(29))
.saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes(16))
} }
/// Storage: ParaInherent Included (r:1 w:1) /// Storage: `ParaInherent::Included` (r:1 w:1)
/// Proof Skipped: ParaInherent Included (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: System ParentHash (r:1 w:0) /// Storage: `System::ParentHash` (r:1 w:0)
/// Proof: System ParentHash (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// Storage: ParasShared CurrentSessionIndex (r:1 w:0) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1)
/// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler AvailabilityCores (r:1 w:1) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
/// Proof Skipped: ParaScheduler AvailabilityCores (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1)
/// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Babe AuthorVrfRandomness (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0)
/// Proof: Babe AuthorVrfRandomness (max_values: Some(1), max_size: Some(33), added: 528, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInherent OnChainVotes (r:1 w:1) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0)
/// Proof Skipped: ParaInherent OnChainVotes (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`)
/// Storage: ParasDisputes Frozen (r:1 w:0) /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1)
/// Proof Skipped: ParasDisputes Frozen (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailability (r:2 w:1) /// Storage: `ParasDisputes::Frozen` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailability (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Paras Parachains (r:1 w:0) /// Storage: `ParaInclusion::V1` (r:2 w:1)
/// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaInclusion PendingAvailabilityCommitments (r:1 w:1) /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0)
/// Proof Skipped: ParaInclusion PendingAvailabilityCommitments (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaSessionInfo AccountKeys (r:1 w:0) /// Storage: `Session::Validators` (r:1 w:0)
/// Proof Skipped: ParaSessionInfo AccountKeys (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Session Validators (r:1 w:0) /// Storage: `Staking::ActiveEra` (r:1 w:0)
/// Proof Skipped: Session Validators (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`)
/// Storage: Staking ActiveEra (r:1 w:0) /// Storage: `Staking::ErasRewardPoints` (r:1 w:1)
/// Proof: Staking ActiveEra (max_values: Some(1), max_size: Some(13), added: 508, mode: MaxEncodedLen) /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Staking ErasRewardPoints (r:1 w:1) /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1)
/// Proof Skipped: Staking ErasRewardPoints (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DownwardMessageQueues (r:1 w:1) /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1)
/// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Dmp DeliveryFeeFactor (r:1 w:1) /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1)
/// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpChannelDigests (r:1 w:1) /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0)
/// Proof Skipped: Hrmp HrmpChannelDigests (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras FutureCodeUpgrades (r:1 w:0) /// Storage: `ParasDisputes::Disputes` (r:1 w:0)
/// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Disputes (r:1 w:0) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0)
/// Proof Skipped: ParasDisputes Disputes (max_values: None, max_size: None, mode: Measured) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler SessionStartBlock (r:1 w:0) /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0)
/// Proof Skipped: ParaScheduler SessionStartBlock (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ParathreadQueue (r:1 w:1) /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1)
/// Proof Skipped: ParaScheduler ParathreadQueue (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler Scheduled (r:1 w:1) /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
/// Proof Skipped: ParaScheduler Scheduled (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: ParaScheduler ValidatorGroups (r:1 w:0) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0)
/// Proof Skipped: ParaScheduler ValidatorGroups (max_values: Some(1), max_size: None, mode: Measured) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras CurrentCodeHash (r:1 w:0) /// Storage: `Paras::FutureCodeHash` (r:1 w:0)
/// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras FutureCodeHash (r:1 w:0) /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:0)
/// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras UpgradeRestrictionSignal (r:1 w:0) /// Storage: `Paras::ParaLifecycles` (r:1 w:0)
/// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras ParaLifecycles (r:1 w:0) /// Storage: `MessageQueue::BookStateFor` (r:1 w:0)
/// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`)
/// Storage: MessageQueue BookStateFor (r:1 w:0) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0)
/// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: ParasDisputes Included (r:0 w:1) /// Storage: `Session::DisabledValidators` (r:1 w:0)
/// Proof Skipped: ParasDisputes Included (max_values: None, max_size: None, mode: Measured) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
/// Storage: Hrmp HrmpWatermarks (r:0 w:1) /// Storage: `ParasDisputes::Included` (r:0 w:1)
/// Proof Skipped: Hrmp HrmpWatermarks (max_values: None, max_size: None, mode: Measured) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras Heads (r:0 w:1) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1)
/// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) /// Storage: `Paras::Heads` (r:0 w:1)
/// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1)
/// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `Paras::MostRecentContext` (r:0 w:1)
/// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn enter_backed_candidate_code_upgrade() -> Weight { fn enter_backed_candidate_code_upgrade() -> Weight {
// Proof Size summary in bytes: // Proof Size summary in bytes:
// Measured: `42414` // Measured: `43282`
// Estimated: `48354` // Estimated: `49222`
// Minimum execution time: 43_320_529_000 picoseconds. // Minimum execution time: 42_128_606_000 picoseconds.
Weight::from_parts(45_622_613_000, 0) Weight::from_parts(42_822_806_000, 0)
.saturating_add(Weight::from_parts(0, 48354)) .saturating_add(Weight::from_parts(0, 49222))
.saturating_add(T::DbWeight::get().reads(30)) .saturating_add(T::DbWeight::get().reads(31))
.saturating_add(T::DbWeight::get().writes(15)) .saturating_add(T::DbWeight::get().writes(16))
} }
} }
+8
View File
@@ -0,0 +1,8 @@
title: "Elastic scaling: runtime dependency tracking and enactment"
doc:
- audience: Node Dev
description: |
Adds support in the inclusion and paras_inherent runtime modules for backing and including multiple candidates of the same para if they form a chain.
crates: [ ]