mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 09:51:02 +00:00
Fix nothing scheduled on session boundary (#1403)
* Fix scheduled state at session boundaries. * Cleanup + better docs. * More cleanup and fixes. * Remove 12s hack. * Add dep. * Make clippy happy --------- Co-authored-by: eskimor <eskimor@no-such-url.com>
This commit is contained in:
Generated
+1
@@ -12792,6 +12792,7 @@ dependencies = [
|
|||||||
"pallet-timestamp",
|
"pallet-timestamp",
|
||||||
"pallet-vesting",
|
"pallet-vesting",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
|
"polkadot-core-primitives",
|
||||||
"polkadot-parachain-primitives",
|
"polkadot-parachain-primitives",
|
||||||
"polkadot-primitives",
|
"polkadot-primitives",
|
||||||
"polkadot-primitives-test-helpers",
|
"polkadot-primitives-test-helpers",
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ pub use v5::{
|
|||||||
BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, CandidateCommitments,
|
BackedCandidate, Balance, BlakeTwo256, Block, BlockId, BlockNumber, CandidateCommitments,
|
||||||
CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt,
|
CandidateDescriptor, CandidateEvent, CandidateHash, CandidateIndex, CandidateReceipt,
|
||||||
CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, CollatorSignature,
|
CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CollatorId, CollatorSignature,
|
||||||
CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, CoreOccupied, CoreState,
|
CommittedCandidateReceipt, CompactStatement, ConsensusLog, CoreIndex, CoreState, DisputeState,
|
||||||
DisputeState, DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, ExecutorParam,
|
DisputeStatement, DisputeStatementSet, DownwardMessage, EncodeAs, ExecutorParam,
|
||||||
ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo,
|
ExecutorParams, ExecutorParamsHash, ExplicitDisputeStatement, GroupIndex, GroupRotationInfo,
|
||||||
Hash, HashT, HeadData, Header, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage,
|
Hash, HashT, HeadData, Header, HrmpChannelId, Id, InboundDownwardMessage, InboundHrmpMessage,
|
||||||
IndexedVec, InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce,
|
IndexedVec, InherentData, InvalidDisputeStatementKind, Moment, MultiDisputeStatementSet, Nonce,
|
||||||
|
|||||||
@@ -830,60 +830,6 @@ pub struct ParathreadEntry {
|
|||||||
pub retries: u32,
|
pub retries: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An assignment for a parachain scheduled to be backed and included in a relay chain block.
|
|
||||||
#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebug)]
|
|
||||||
pub struct Assignment {
|
|
||||||
/// Assignment's ParaId
|
|
||||||
pub para_id: Id,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Assignment {
|
|
||||||
/// Create a new `Assignment`.
|
|
||||||
pub fn new(para_id: Id) -> Self {
|
|
||||||
Self { para_id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An entry tracking a paras
|
|
||||||
#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
|
|
||||||
pub struct ParasEntry<N = BlockNumber> {
|
|
||||||
/// The `Assignment`
|
|
||||||
pub assignment: Assignment,
|
|
||||||
/// The number of times the entry has timed out in availability.
|
|
||||||
pub availability_timeouts: u32,
|
|
||||||
/// The block height where this entry becomes invalid.
|
|
||||||
pub ttl: N,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N> ParasEntry<N> {
|
|
||||||
/// Return `Id` from the underlying `Assignment`.
|
|
||||||
pub fn para_id(&self) -> Id {
|
|
||||||
self.assignment.para_id
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new `ParasEntry`.
|
|
||||||
pub fn new(assignment: Assignment, now: N) -> Self {
|
|
||||||
ParasEntry { assignment, availability_timeouts: 0, ttl: now }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// What is occupying a specific availability core.
|
|
||||||
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
|
|
||||||
#[cfg_attr(feature = "std", derive(PartialEq))]
|
|
||||||
pub enum CoreOccupied<N> {
|
|
||||||
/// The core is not occupied.
|
|
||||||
Free,
|
|
||||||
/// A paras.
|
|
||||||
Paras(ParasEntry<N>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N> CoreOccupied<N> {
|
|
||||||
/// Is core free?
|
|
||||||
pub fn is_free(&self) -> bool {
|
|
||||||
matches!(self, Self::Free)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper data-type for tracking validator-group rotations.
|
/// A helper data-type for tracking validator-group rotations.
|
||||||
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
|
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
|
||||||
#[cfg_attr(feature = "std", derive(PartialEq))]
|
#[cfg_attr(feature = "std", derive(PartialEq))]
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ rand_chacha = { version = "0.3.1", default-features = false }
|
|||||||
static_assertions = { version = "1.1.0", optional = true }
|
static_assertions = { version = "1.1.0", optional = true }
|
||||||
polkadot-parachain-primitives = { path = "../../parachain", default-features = false }
|
polkadot-parachain-primitives = { path = "../../parachain", default-features = false }
|
||||||
polkadot-runtime-metrics = { path = "../metrics", default-features = false}
|
polkadot-runtime-metrics = { path = "../metrics", default-features = false}
|
||||||
|
polkadot-core-primitives = { path = "../../core-primitives", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
//! The Polkadot multiplexing assignment provider.
|
//! The Polkadot multiplexing assignment provider.
|
||||||
//! Provides blockspace assignments for both bulk and on demand parachains.
|
//! Provides blockspace assignments for both bulk and on demand parachains.
|
||||||
use frame_system::pallet_prelude::BlockNumberFor;
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
use primitives::{v5::Assignment, CoreIndex, Id as ParaId};
|
use primitives::{CoreIndex, Id as ParaId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration, paras,
|
configuration, paras,
|
||||||
scheduler::common::{AssignmentProvider, AssignmentProviderConfig},
|
scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ mod tests;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration, paras,
|
configuration, paras,
|
||||||
scheduler::common::{AssignmentProvider, AssignmentProviderConfig},
|
scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig},
|
||||||
};
|
};
|
||||||
|
|
||||||
use frame_support::{
|
use frame_support::{
|
||||||
@@ -46,7 +46,7 @@ use frame_support::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
use primitives::{v5::Assignment, CoreIndex, Id as ParaId};
|
use primitives::{CoreIndex, Id as ParaId};
|
||||||
use sp_runtime::{
|
use sp_runtime::{
|
||||||
traits::{One, SaturatedConversion},
|
traits::{One, SaturatedConversion},
|
||||||
FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating,
|
FixedPointNumber, FixedPointOperand, FixedU128, Perbill, Saturating,
|
||||||
@@ -606,7 +606,6 @@ impl<T: Config> AssignmentProvider<BlockNumberFor<T>> for Pallet<T> {
|
|||||||
fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumberFor<T>> {
|
fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumberFor<T>> {
|
||||||
let config = <configuration::Pallet<T>>::config();
|
let config = <configuration::Pallet<T>>::config();
|
||||||
AssignmentProviderConfig {
|
AssignmentProviderConfig {
|
||||||
availability_period: config.paras_availability_period,
|
|
||||||
max_availability_timeouts: config.on_demand_retries,
|
max_availability_timeouts: config.on_demand_retries,
|
||||||
ttl: config.on_demand_ttl,
|
ttl: config.on_demand_ttl,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,11 @@ use crate::{
|
|||||||
System, Test,
|
System, Test,
|
||||||
},
|
},
|
||||||
paras::{ParaGenesisArgs, ParaKind},
|
paras::{ParaGenesisArgs, ParaKind},
|
||||||
|
scheduler::common::Assignment,
|
||||||
};
|
};
|
||||||
use frame_support::{assert_noop, assert_ok, error::BadOrigin};
|
use frame_support::{assert_noop, assert_ok, error::BadOrigin};
|
||||||
use pallet_balances::Error as BalancesError;
|
use pallet_balances::Error as BalancesError;
|
||||||
use primitives::{
|
use primitives::{v5::ValidationCode, BlockNumber, SessionIndex};
|
||||||
v5::{Assignment, ValidationCode},
|
|
||||||
BlockNumber, SessionIndex,
|
|
||||||
};
|
|
||||||
use sp_std::collections::btree_map::BTreeMap;
|
use sp_std::collections::btree_map::BTreeMap;
|
||||||
|
|
||||||
fn schedule_blank_para(id: ParaId, parakind: ParaKind) {
|
fn schedule_blank_para(id: ParaId, parakind: ParaKind) {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration, paras,
|
configuration, paras,
|
||||||
scheduler::common::{AssignmentProvider, AssignmentProviderConfig},
|
scheduler::common::{Assignment, AssignmentProvider, AssignmentProviderConfig},
|
||||||
};
|
};
|
||||||
use frame_system::pallet_prelude::BlockNumberFor;
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
use primitives::{v5::Assignment, CoreIndex, Id as ParaId};
|
use primitives::{CoreIndex, Id as ParaId};
|
||||||
|
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
@@ -57,9 +57,7 @@ impl<T: Config> AssignmentProvider<BlockNumberFor<T>> for Pallet<T> {
|
|||||||
fn push_assignment_for_core(_: CoreIndex, _: Assignment) {}
|
fn push_assignment_for_core(_: CoreIndex, _: Assignment) {}
|
||||||
|
|
||||||
fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumberFor<T>> {
|
fn get_provider_config(_core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumberFor<T>> {
|
||||||
let config = <configuration::Pallet<T>>::config();
|
|
||||||
AssignmentProviderConfig {
|
AssignmentProviderConfig {
|
||||||
availability_period: config.paras_availability_period,
|
|
||||||
// The next assignment already goes to the same [`ParaId`], no timeout tracking needed.
|
// The next assignment already goes to the same [`ParaId`], no timeout tracking needed.
|
||||||
max_availability_timeouts: 0,
|
max_availability_timeouts: 0,
|
||||||
// The next assignment already goes to the same [`ParaId`], this can be any number
|
// The next assignment already goes to the same [`ParaId`], this can be any number
|
||||||
|
|||||||
@@ -18,18 +18,20 @@ use crate::{
|
|||||||
configuration, inclusion, initializer, paras,
|
configuration, inclusion, initializer, paras,
|
||||||
paras::ParaKind,
|
paras::ParaKind,
|
||||||
paras_inherent,
|
paras_inherent,
|
||||||
scheduler::{self, common::AssignmentProviderConfig},
|
scheduler::{
|
||||||
|
self,
|
||||||
|
common::{Assignment, AssignmentProviderConfig},
|
||||||
|
CoreOccupied, ParasEntry,
|
||||||
|
},
|
||||||
session_info, shared,
|
session_info, shared,
|
||||||
};
|
};
|
||||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::pallet_prelude::*;
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
use primitives::{
|
use primitives::{
|
||||||
collator_signature_payload,
|
collator_signature_payload, AvailabilityBitfield, BackedCandidate, CandidateCommitments,
|
||||||
v5::{Assignment, ParasEntry},
|
CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt,
|
||||||
AvailabilityBitfield, BackedCandidate, CandidateCommitments, CandidateDescriptor,
|
CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData,
|
||||||
CandidateHash, CollatorId, CollatorSignature, CommittedCandidateReceipt, CompactStatement,
|
|
||||||
CoreIndex, CoreOccupied, DisputeStatement, DisputeStatementSet, GroupIndex, HeadData,
|
|
||||||
Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind,
|
Id as ParaId, IndexedVec, InherentData as ParachainsInherentData, InvalidDisputeStatementKind,
|
||||||
PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned,
|
PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned,
|
||||||
ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation,
|
ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation,
|
||||||
|
|||||||
@@ -190,11 +190,20 @@ pub struct HostConfiguration<BlockNumber> {
|
|||||||
///
|
///
|
||||||
/// Must be non-zero.
|
/// Must be non-zero.
|
||||||
pub group_rotation_frequency: BlockNumber,
|
pub group_rotation_frequency: BlockNumber,
|
||||||
/// The availability period, in blocks. This is the amount of blocks
|
/// The minimum availability period, in blocks.
|
||||||
/// after inclusion that validators have to make the block available and signal its
|
|
||||||
/// availability to the chain.
|
|
||||||
///
|
///
|
||||||
/// Must be at least 1.
|
/// This is the minimum amount of blocks after a core became occupied that validators have time
|
||||||
|
/// to make the block available.
|
||||||
|
///
|
||||||
|
/// This value only has effect on group rotations. If backers backed something at the end of
|
||||||
|
/// their rotation, the occupied core affects the backing group that comes afterwards. We limit
|
||||||
|
/// the effect one backing group can have on the next to `paras_availability_period` blocks.
|
||||||
|
///
|
||||||
|
/// Within a group rotation there is no timeout as backers are only affecting themselves.
|
||||||
|
///
|
||||||
|
/// Must be at least 1. With a value of 1, the previous group will not be able to negatively
|
||||||
|
/// affect the following group at the expense of a tight availability timeline at group
|
||||||
|
/// rotation boundaries.
|
||||||
pub paras_availability_period: BlockNumber,
|
pub paras_availability_period: BlockNumber,
|
||||||
/// The amount of blocks ahead to schedule paras.
|
/// The amount of blocks ahead to schedule paras.
|
||||||
pub scheduling_lookahead: u32,
|
pub scheduling_lookahead: u32,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
configuration::{self, HostConfiguration},
|
configuration::{self, HostConfiguration},
|
||||||
disputes, dmp, hrmp, paras,
|
disputes, dmp, hrmp, paras,
|
||||||
scheduler::{self, common::CoreAssignment},
|
scheduler::{self, AvailabilityTimeoutStatus},
|
||||||
shared::{self, AllowedRelayParentsTracker},
|
shared::{self, AllowedRelayParentsTracker},
|
||||||
};
|
};
|
||||||
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
|
||||||
@@ -46,7 +46,10 @@ 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},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
@@ -597,7 +600,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
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>>,
|
candidates: Vec<BackedCandidate<T::Hash>>,
|
||||||
scheduled: Vec<CoreAssignment<BlockNumberFor<T>>>,
|
scheduled: &BTreeMap<ParaId, CoreIndex>,
|
||||||
group_validators: GV,
|
group_validators: GV,
|
||||||
) -> Result<ProcessedCandidates<T::Hash>, DispatchError>
|
) -> Result<ProcessedCandidates<T::Hash>, DispatchError>
|
||||||
where
|
where
|
||||||
@@ -620,18 +623,16 @@ impl<T: Config> Pallet<T> {
|
|||||||
|
|
||||||
// Do all checks before writing storage.
|
// Do all checks before writing storage.
|
||||||
let core_indices_and_backers = {
|
let core_indices_and_backers = {
|
||||||
let mut skip = 0;
|
|
||||||
let mut core_indices_and_backers = Vec::with_capacity(candidates.len());
|
let mut core_indices_and_backers = Vec::with_capacity(candidates.len());
|
||||||
let mut last_core = None;
|
let mut last_core = None;
|
||||||
|
|
||||||
let mut check_assignment_in_order =
|
let mut check_assignment_in_order = |core_idx| -> DispatchResult {
|
||||||
|assignment: &CoreAssignment<BlockNumberFor<T>>| -> DispatchResult {
|
|
||||||
ensure!(
|
ensure!(
|
||||||
last_core.map_or(true, |core| assignment.core > core),
|
last_core.map_or(true, |core| core_idx > core),
|
||||||
Error::<T>::ScheduledOutOfOrder,
|
Error::<T>::ScheduledOutOfOrder,
|
||||||
);
|
);
|
||||||
|
|
||||||
last_core = Some(assignment.core);
|
last_core = Some(core_idx);
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -645,9 +646,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
//
|
//
|
||||||
// In the meantime, we do certain sanity checks on the candidates and on the scheduled
|
// In the meantime, we do certain sanity checks on the candidates and on the scheduled
|
||||||
// list.
|
// list.
|
||||||
'next_backed_candidate: for (candidate_idx, backed_candidate) in
|
for (candidate_idx, backed_candidate) in candidates.iter().enumerate() {
|
||||||
candidates.iter().enumerate()
|
|
||||||
{
|
|
||||||
let relay_parent_hash = backed_candidate.descriptor().relay_parent;
|
let relay_parent_hash = backed_candidate.descriptor().relay_parent;
|
||||||
let para_id = backed_candidate.descriptor().para_id;
|
let para_id = backed_candidate.descriptor().para_id;
|
||||||
|
|
||||||
@@ -681,24 +680,19 @@ impl<T: Config> Pallet<T> {
|
|||||||
let para_id = backed_candidate.descriptor().para_id;
|
let para_id = backed_candidate.descriptor().para_id;
|
||||||
let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()];
|
let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()];
|
||||||
|
|
||||||
for (i, core_assignment) in scheduled[skip..].iter().enumerate() {
|
let core_idx = *scheduled.get(¶_id).ok_or(Error::<T>::UnscheduledCandidate)?;
|
||||||
check_assignment_in_order(core_assignment)?;
|
check_assignment_in_order(core_idx)?;
|
||||||
|
|
||||||
if para_id == core_assignment.paras_entry.para_id() {
|
|
||||||
ensure!(
|
ensure!(
|
||||||
<PendingAvailability<T>>::get(¶_id).is_none() &&
|
<PendingAvailability<T>>::get(¶_id).is_none() &&
|
||||||
<PendingAvailabilityCommitments<T>>::get(¶_id).is_none(),
|
<PendingAvailabilityCommitments<T>>::get(¶_id).is_none(),
|
||||||
Error::<T>::CandidateScheduledBeforeParaFree,
|
Error::<T>::CandidateScheduledBeforeParaFree,
|
||||||
);
|
);
|
||||||
|
|
||||||
// account for already skipped, and then skip this one.
|
|
||||||
skip = i + skip + 1;
|
|
||||||
|
|
||||||
// The candidate based upon relay parent `N` should be backed by a group
|
// 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`
|
// assigned to core at block `N + 1`. Thus, `relay_parent_number + 1`
|
||||||
// will always land in the current session.
|
// 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_assignment.core,
|
core_idx,
|
||||||
relay_parent_number + One::one(),
|
relay_parent_number + One::one(),
|
||||||
)
|
)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
@@ -709,8 +703,8 @@ impl<T: Config> Pallet<T> {
|
|||||||
);
|
);
|
||||||
Error::<T>::InvalidAssignment
|
Error::<T>::InvalidAssignment
|
||||||
})?;
|
})?;
|
||||||
let group_vals = group_validators(group_idx)
|
let group_vals =
|
||||||
.ok_or_else(|| Error::<T>::InvalidGroupIndex)?;
|
group_validators(group_idx).ok_or_else(|| Error::<T>::InvalidGroupIndex)?;
|
||||||
|
|
||||||
// check the signatures in the backing and that it is a majority.
|
// check the signatures in the backing and that it is a majority.
|
||||||
{
|
{
|
||||||
@@ -753,9 +747,8 @@ 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 = group_vals
|
let val_idx =
|
||||||
.get(bit_idx)
|
group_vals.get(bit_idx).expect("this query succeeded above; qed");
|
||||||
.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);
|
||||||
@@ -765,24 +758,11 @@ impl<T: Config> Pallet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
core_indices_and_backers.push((
|
core_indices_and_backers.push((
|
||||||
(core_assignment.core, core_assignment.paras_entry.para_id()),
|
(core_idx, para_id),
|
||||||
backers,
|
backers,
|
||||||
group_idx,
|
group_idx,
|
||||||
relay_parent_number,
|
relay_parent_number,
|
||||||
));
|
));
|
||||||
continue 'next_backed_candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// end of loop reached means that the candidate didn't appear in the non-traversed
|
|
||||||
// section of the `scheduled` slice. either it was not scheduled or didn't appear in
|
|
||||||
// `candidates` in the correct order.
|
|
||||||
ensure!(false, Error::<T>::UnscheduledCandidate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check remainder of scheduled cores, if any.
|
|
||||||
for assignment in scheduled[skip..].iter() {
|
|
||||||
check_assignment_in_order(assignment)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
core_indices_and_backers
|
core_indices_and_backers
|
||||||
@@ -1043,13 +1023,13 @@ impl<T: Config> Pallet<T> {
|
|||||||
///
|
///
|
||||||
/// Returns a vector of cleaned-up core IDs.
|
/// Returns a vector of cleaned-up core IDs.
|
||||||
pub(crate) fn collect_pending(
|
pub(crate) fn collect_pending(
|
||||||
pred: impl Fn(CoreIndex, BlockNumberFor<T>) -> bool,
|
pred: impl Fn(BlockNumberFor<T>) -> AvailabilityTimeoutStatus<BlockNumberFor<T>>,
|
||||||
) -> Vec<CoreIndex> {
|
) -> Vec<CoreIndex> {
|
||||||
let mut cleaned_up_ids = Vec::new();
|
let mut cleaned_up_ids = Vec::new();
|
||||||
let mut cleaned_up_cores = Vec::new();
|
let mut cleaned_up_cores = Vec::new();
|
||||||
|
|
||||||
for (para_id, pending_record) in <PendingAvailability<T>>::iter() {
|
for (para_id, pending_record) in <PendingAvailability<T>>::iter() {
|
||||||
if pred(pending_record.core, pending_record.backed_in_number) {
|
if pred(pending_record.backed_in_number).timed_out {
|
||||||
cleaned_up_ids.push(para_id);
|
cleaned_up_ids.push(para_id);
|
||||||
cleaned_up_cores.push(pending_record.core);
|
cleaned_up_cores.push(pending_record.core);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ use frame_support::assert_noop;
|
|||||||
use keyring::Sr25519Keyring;
|
use keyring::Sr25519Keyring;
|
||||||
use parity_scale_codec::DecodeAll;
|
use parity_scale_codec::DecodeAll;
|
||||||
use primitives::{
|
use primitives::{
|
||||||
v5::{Assignment, ParasEntry},
|
|
||||||
BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId,
|
BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId,
|
||||||
CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement,
|
CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement,
|
||||||
ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID,
|
ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID,
|
||||||
@@ -380,7 +379,9 @@ fn collect_pending_cleans_up_pending() {
|
|||||||
(chain_b, ParaKind::Parachain),
|
(chain_b, ParaKind::Parachain),
|
||||||
(thread_a, ParaKind::Parathread),
|
(thread_a, ParaKind::Parathread),
|
||||||
];
|
];
|
||||||
new_test_ext(genesis_config(paras)).execute_with(|| {
|
let mut config = genesis_config(paras);
|
||||||
|
config.configuration.config.group_rotation_frequency = 3;
|
||||||
|
new_test_ext(config).execute_with(|| {
|
||||||
let default_candidate = TestCandidateBuilder::default().build();
|
let default_candidate = TestCandidateBuilder::default().build();
|
||||||
<PendingAvailability<Test>>::insert(
|
<PendingAvailability<Test>>::insert(
|
||||||
chain_a,
|
chain_a,
|
||||||
@@ -408,7 +409,7 @@ fn collect_pending_cleans_up_pending() {
|
|||||||
descriptor: default_candidate.descriptor,
|
descriptor: default_candidate.descriptor,
|
||||||
availability_votes: default_availability_votes(),
|
availability_votes: default_availability_votes(),
|
||||||
relay_parent_number: 0,
|
relay_parent_number: 0,
|
||||||
backed_in_number: 0,
|
backed_in_number: 5,
|
||||||
backers: default_backing_bitfield(),
|
backers: default_backing_bitfield(),
|
||||||
backing_group: GroupIndex::from(1),
|
backing_group: GroupIndex::from(1),
|
||||||
},
|
},
|
||||||
@@ -422,7 +423,7 @@ fn collect_pending_cleans_up_pending() {
|
|||||||
assert!(<PendingAvailabilityCommitments<Test>>::get(&chain_a).is_some());
|
assert!(<PendingAvailabilityCommitments<Test>>::get(&chain_a).is_some());
|
||||||
assert!(<PendingAvailabilityCommitments<Test>>::get(&chain_b).is_some());
|
assert!(<PendingAvailabilityCommitments<Test>>::get(&chain_b).is_some());
|
||||||
|
|
||||||
ParaInclusion::collect_pending(|core, _since| core == CoreIndex::from(0));
|
ParaInclusion::collect_pending(Scheduler::availability_timeout_predicate());
|
||||||
|
|
||||||
assert!(<PendingAvailability<Test>>::get(&chain_a).is_none());
|
assert!(<PendingAvailability<Test>>::get(&chain_a).is_none());
|
||||||
assert!(<PendingAvailability<Test>>::get(&chain_b).is_some());
|
assert!(<PendingAvailability<Test>>::get(&chain_b).is_some());
|
||||||
@@ -910,23 +911,12 @@ fn candidate_checks() {
|
|||||||
];
|
];
|
||||||
Scheduler::set_validator_groups(validator_groups);
|
Scheduler::set_validator_groups(validator_groups);
|
||||||
|
|
||||||
let entry_ttl = 10_000;
|
|
||||||
let thread_collator: CollatorId = Sr25519Keyring::Two.public().into();
|
let thread_collator: CollatorId = Sr25519Keyring::Two.public().into();
|
||||||
let chain_a_assignment = CoreAssignment {
|
let chain_a_assignment = (chain_a, CoreIndex::from(0));
|
||||||
core: CoreIndex::from(0),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let chain_b_assignment = CoreAssignment {
|
let chain_b_assignment = (chain_b, CoreIndex::from(1));
|
||||||
core: CoreIndex::from(1),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let thread_a_assignment = CoreAssignment {
|
|
||||||
core: CoreIndex::from(2),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let thread_a_assignment = (thread_a, CoreIndex::from(2));
|
||||||
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
||||||
|
|
||||||
// unscheduled candidate.
|
// unscheduled candidate.
|
||||||
@@ -955,7 +945,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_b_assignment.clone()],
|
&[chain_b_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::UnscheduledCandidate
|
Error::<Test>::UnscheduledCandidate
|
||||||
@@ -1010,10 +1000,10 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed_b, backed_a],
|
vec![backed_b, backed_a],
|
||||||
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
&[chain_a_assignment, chain_b_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::UnscheduledCandidate
|
Error::<Test>::ScheduledOutOfOrder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +1033,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::InsufficientBacking
|
Error::<Test>::InsufficientBacking
|
||||||
@@ -1100,7 +1090,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed_b, backed_a],
|
vec![backed_b, backed_a],
|
||||||
vec![chain_a_assignment.clone(), chain_b_assignment.clone()],
|
&[chain_a_assignment, chain_b_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::DisallowedRelayParent
|
Error::<Test>::DisallowedRelayParent
|
||||||
@@ -1138,7 +1128,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![thread_a_assignment.clone()],
|
&[thread_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::NotCollatorSigned
|
Error::<Test>::NotCollatorSigned
|
||||||
@@ -1188,7 +1178,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::CandidateScheduledBeforeParaFree
|
Error::<Test>::CandidateScheduledBeforeParaFree
|
||||||
@@ -1228,7 +1218,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::CandidateScheduledBeforeParaFree
|
Error::<Test>::CandidateScheduledBeforeParaFree
|
||||||
@@ -1272,7 +1262,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::PrematureCodeUpgrade
|
Error::<Test>::PrematureCodeUpgrade
|
||||||
@@ -1306,7 +1296,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Err(Error::<Test>::ValidationDataHashMismatch.into()),
|
Err(Error::<Test>::ValidationDataHashMismatch.into()),
|
||||||
@@ -1341,7 +1331,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::InvalidValidationCodeHash
|
Error::<Test>::InvalidValidationCodeHash
|
||||||
@@ -1376,7 +1366,7 @@ fn candidate_checks() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed],
|
vec![backed],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
),
|
),
|
||||||
Error::<Test>::ParaHeadMismatch
|
Error::<Test>::ParaHeadMismatch
|
||||||
@@ -1446,21 +1436,9 @@ fn backing_works() {
|
|||||||
|
|
||||||
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
||||||
|
|
||||||
let entry_ttl = 10_000;
|
let chain_a_assignment = (chain_a, CoreIndex::from(0));
|
||||||
let chain_a_assignment = CoreAssignment {
|
let chain_b_assignment = (chain_b, CoreIndex::from(1));
|
||||||
core: CoreIndex::from(0),
|
let thread_a_assignment = (thread_a, CoreIndex::from(2));
|
||||||
paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let chain_b_assignment = CoreAssignment {
|
|
||||||
core: CoreIndex::from(1),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(chain_b), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let thread_a_assignment = CoreAssignment {
|
|
||||||
core: CoreIndex::from(2),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(thread_a), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut candidate_a = TestCandidateBuilder {
|
let mut candidate_a = TestCandidateBuilder {
|
||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
@@ -1548,11 +1526,9 @@ fn backing_works() {
|
|||||||
} = ParaInclusion::process_candidates(
|
} = ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
backed_candidates.clone(),
|
backed_candidates.clone(),
|
||||||
vec![
|
&[chain_a_assignment, chain_b_assignment, thread_a_assignment]
|
||||||
chain_a_assignment.clone(),
|
.into_iter()
|
||||||
chain_b_assignment.clone(),
|
.collect(),
|
||||||
thread_a_assignment.clone(),
|
|
||||||
],
|
|
||||||
&group_validators,
|
&group_validators,
|
||||||
)
|
)
|
||||||
.expect("candidates scheduled, in order, and backed");
|
.expect("candidates scheduled, in order, and backed");
|
||||||
@@ -1738,12 +1714,7 @@ fn can_include_candidate_with_ok_code_upgrade() {
|
|||||||
Scheduler::set_validator_groups(validator_groups);
|
Scheduler::set_validator_groups(validator_groups);
|
||||||
|
|
||||||
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
||||||
let entry_ttl = 10_000;
|
let chain_a_assignment = (chain_a, CoreIndex::from(0));
|
||||||
let chain_a_assignment = CoreAssignment {
|
|
||||||
core: CoreIndex::from(0),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(chain_a), entry_ttl),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut candidate_a = TestCandidateBuilder {
|
let mut candidate_a = TestCandidateBuilder {
|
||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
@@ -1769,7 +1740,7 @@ fn can_include_candidate_with_ok_code_upgrade() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed_a],
|
vec![backed_a],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
)
|
)
|
||||||
.expect("candidates scheduled, in order, and backed");
|
.expect("candidates scheduled, in order, and backed");
|
||||||
@@ -1895,28 +1866,10 @@ fn check_allowed_relay_parents() {
|
|||||||
max_ancestry_len,
|
max_ancestry_len,
|
||||||
);
|
);
|
||||||
|
|
||||||
let chain_a_assignment = CoreAssignment {
|
let chain_a_assignment = (chain_a, CoreIndex::from(0));
|
||||||
core: CoreIndex::from(0),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_a },
|
|
||||||
availability_timeouts: 0,
|
|
||||||
ttl: 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let chain_b_assignment = CoreAssignment {
|
let chain_b_assignment = (chain_b, CoreIndex::from(1));
|
||||||
core: CoreIndex::from(1),
|
let thread_a_assignment = (thread_a, CoreIndex::from(2));
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_b },
|
|
||||||
availability_timeouts: 0,
|
|
||||||
ttl: 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let thread_a_assignment = CoreAssignment {
|
|
||||||
core: CoreIndex::from(2),
|
|
||||||
paras_entry: ParasEntry::new(Assignment::new(thread_a), 5),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut candidate_a = TestCandidateBuilder {
|
let mut candidate_a = TestCandidateBuilder {
|
||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
@@ -1998,11 +1951,9 @@ fn check_allowed_relay_parents() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
backed_candidates.clone(),
|
backed_candidates.clone(),
|
||||||
vec![
|
&[chain_a_assignment, chain_b_assignment, thread_a_assignment]
|
||||||
chain_a_assignment.clone(),
|
.into_iter()
|
||||||
chain_b_assignment.clone(),
|
.collect(),
|
||||||
thread_a_assignment.clone(),
|
|
||||||
],
|
|
||||||
&group_validators,
|
&group_validators,
|
||||||
)
|
)
|
||||||
.expect("candidates scheduled, in order, and backed");
|
.expect("candidates scheduled, in order, and backed");
|
||||||
@@ -2212,15 +2163,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() {
|
|||||||
|
|
||||||
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
let allowed_relay_parents = default_allowed_relay_parent_tracker();
|
||||||
|
|
||||||
let chain_a_assignment = CoreAssignment {
|
let chain_a_assignment = (chain_a, CoreIndex::from(0));
|
||||||
core: CoreIndex::from(0),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_a },
|
|
||||||
availability_timeouts: 0,
|
|
||||||
ttl: 5,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut candidate_a = TestCandidateBuilder {
|
let mut candidate_a = TestCandidateBuilder {
|
||||||
para_id: chain_a,
|
para_id: chain_a,
|
||||||
relay_parent: System::parent_hash(),
|
relay_parent: System::parent_hash(),
|
||||||
@@ -2246,7 +2189,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() {
|
|||||||
ParaInclusion::process_candidates(
|
ParaInclusion::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
vec![backed_a],
|
vec![backed_a],
|
||||||
vec![chain_a_assignment.clone()],
|
&[chain_a_assignment].into_iter().collect(),
|
||||||
&group_validators,
|
&group_validators,
|
||||||
)
|
)
|
||||||
.expect("candidates scheduled, in order, and backed");
|
.expect("candidates scheduled, in order, and backed");
|
||||||
|
|||||||
@@ -29,10 +29,7 @@ use crate::{
|
|||||||
initializer,
|
initializer,
|
||||||
metrics::METRICS,
|
metrics::METRICS,
|
||||||
paras,
|
paras,
|
||||||
scheduler::{
|
scheduler::{self, FreedReason},
|
||||||
self,
|
|
||||||
common::{CoreAssignment, FreedReason},
|
|
||||||
},
|
|
||||||
shared, ParaId,
|
shared, ParaId,
|
||||||
};
|
};
|
||||||
use bitvec::prelude::BitVec;
|
use bitvec::prelude::BitVec;
|
||||||
@@ -245,8 +242,8 @@ pub mod pallet {
|
|||||||
T: Config,
|
T: Config,
|
||||||
{
|
{
|
||||||
// Handle timeouts for any availability core work.
|
// Handle timeouts for any availability core work.
|
||||||
let availability_pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
|
let freed_timeout = if <scheduler::Pallet<T>>::availability_timeout_check_required() {
|
||||||
let freed_timeout = if let Some(pred) = availability_pred {
|
let pred = <scheduler::Pallet<T>>::availability_timeout_predicate();
|
||||||
<inclusion::Pallet<T>>::collect_pending(pred)
|
<inclusion::Pallet<T>>::collect_pending(pred)
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
@@ -583,7 +580,10 @@ impl<T: Config> Pallet<T> {
|
|||||||
|
|
||||||
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned());
|
let freed = collect_all_freed_cores::<T, _>(freed_concluded.iter().cloned());
|
||||||
|
|
||||||
let scheduled = <scheduler::Pallet<T>>::update_claimqueue(freed, now);
|
<scheduler::Pallet<T>>::update_claimqueue(freed, now);
|
||||||
|
let scheduled = <scheduler::Pallet<T>>::scheduled_paras()
|
||||||
|
.map(|(core_idx, para_id)| (para_id, core_idx))
|
||||||
|
.collect();
|
||||||
|
|
||||||
METRICS.on_candidates_processed_total(backed_candidates.len() as u64);
|
METRICS.on_candidates_processed_total(backed_candidates.len() as u64);
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
.verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate)
|
.verify_backed_candidate(&allowed_relay_parents, candidate_idx, backed_candidate)
|
||||||
.is_err()
|
.is_err()
|
||||||
},
|
},
|
||||||
&scheduled[..],
|
&scheduled,
|
||||||
);
|
);
|
||||||
|
|
||||||
METRICS.on_candidates_sanitized(backed_candidates.len() as u64);
|
METRICS.on_candidates_sanitized(backed_candidates.len() as u64);
|
||||||
@@ -620,7 +620,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
} = <inclusion::Pallet<T>>::process_candidates(
|
} = <inclusion::Pallet<T>>::process_candidates(
|
||||||
&allowed_relay_parents,
|
&allowed_relay_parents,
|
||||||
backed_candidates.clone(),
|
backed_candidates.clone(),
|
||||||
scheduled,
|
&scheduled,
|
||||||
<scheduler::Pallet<T>>::group_validators,
|
<scheduler::Pallet<T>>::group_validators,
|
||||||
)?;
|
)?;
|
||||||
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
// Note which of the scheduled cores were actually occupied by a backed candidate.
|
||||||
@@ -917,7 +917,7 @@ fn sanitize_backed_candidates<
|
|||||||
>(
|
>(
|
||||||
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
mut backed_candidates: Vec<BackedCandidate<T::Hash>>,
|
||||||
mut candidate_has_concluded_invalid_dispute_or_is_invalid: F,
|
mut candidate_has_concluded_invalid_dispute_or_is_invalid: F,
|
||||||
scheduled: &[CoreAssignment<BlockNumberFor<T>>],
|
scheduled: &BTreeMap<ParaId, CoreIndex>,
|
||||||
) -> Vec<BackedCandidate<T::Hash>> {
|
) -> Vec<BackedCandidate<T::Hash>> {
|
||||||
// Remove any candidates that were concluded invalid.
|
// Remove any candidates that were concluded invalid.
|
||||||
// This does not assume sorting.
|
// This does not assume sorting.
|
||||||
@@ -925,11 +925,6 @@ fn sanitize_backed_candidates<
|
|||||||
!candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate)
|
!candidate_has_concluded_invalid_dispute_or_is_invalid(candidate_idx, backed_candidate)
|
||||||
});
|
});
|
||||||
|
|
||||||
let scheduled_paras_to_core_idx = scheduled
|
|
||||||
.into_iter()
|
|
||||||
.map(|core_assignment| (core_assignment.paras_entry.para_id(), core_assignment.core))
|
|
||||||
.collect::<BTreeMap<ParaId, CoreIndex>>();
|
|
||||||
|
|
||||||
// Assure the backed candidate's `ParaId`'s core is free.
|
// Assure the backed candidate's `ParaId`'s core is free.
|
||||||
// This holds under the assumption that `Scheduler::schedule` is called _before_.
|
// This holds under the assumption that `Scheduler::schedule` is called _before_.
|
||||||
// We don't check the relay-parent because this is done in the closure when
|
// We don't check the relay-parent because this is done in the closure when
|
||||||
@@ -938,7 +933,7 @@ fn sanitize_backed_candidates<
|
|||||||
backed_candidates.retain(|backed_candidate| {
|
backed_candidates.retain(|backed_candidate| {
|
||||||
let desc = backed_candidate.descriptor();
|
let desc = backed_candidate.descriptor();
|
||||||
|
|
||||||
scheduled_paras_to_core_idx.get(&desc.para_id).is_some()
|
scheduled.get(&desc.para_id).is_some()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort the `Vec` last, once there is a guarantee that these
|
// Sort the `Vec` last, once there is a guarantee that these
|
||||||
@@ -948,8 +943,7 @@ fn sanitize_backed_candidates<
|
|||||||
// but also allows this to be done in place.
|
// but also allows this to be done in place.
|
||||||
backed_candidates.sort_by(|x, y| {
|
backed_candidates.sort_by(|x, y| {
|
||||||
// Never panics, since we filtered all panic arguments out in the previous `fn retain`.
|
// Never panics, since we filtered all panic arguments out in the previous `fn retain`.
|
||||||
scheduled_paras_to_core_idx[&x.descriptor().para_id]
|
scheduled[&x.descriptor().para_id].cmp(&scheduled[&y.descriptor().para_id])
|
||||||
.cmp(&scheduled_paras_to_core_idx[&y.descriptor().para_id])
|
|
||||||
});
|
});
|
||||||
|
|
||||||
backed_candidates
|
backed_candidates
|
||||||
|
|||||||
@@ -963,10 +963,7 @@ mod sanitizers {
|
|||||||
|
|
||||||
use crate::mock::Test;
|
use crate::mock::Test;
|
||||||
use keyring::Sr25519Keyring;
|
use keyring::Sr25519Keyring;
|
||||||
use primitives::{
|
use primitives::PARACHAIN_KEY_TYPE_ID;
|
||||||
v5::{Assignment, ParasEntry},
|
|
||||||
PARACHAIN_KEY_TYPE_ID,
|
|
||||||
};
|
|
||||||
use sc_keystore::LocalKeystore;
|
use sc_keystore::LocalKeystore;
|
||||||
use sp_keystore::{Keystore, KeystorePtr};
|
use sp_keystore::{Keystore, KeystorePtr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -1239,21 +1236,10 @@ mod sanitizers {
|
|||||||
let has_concluded_invalid =
|
let has_concluded_invalid =
|
||||||
|_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false };
|
|_idx: usize, _backed_candidate: &BackedCandidate| -> bool { false };
|
||||||
|
|
||||||
let entry_ttl = 10_000;
|
|
||||||
let scheduled = (0_usize..2)
|
let scheduled = (0_usize..2)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|idx| {
|
.map(|idx| (ParaId::from(1_u32 + idx as u32), CoreIndex::from(idx as u32)))
|
||||||
let core_idx = CoreIndex::from(idx as u32);
|
.collect::<BTreeMap<_, _>>();
|
||||||
let ca = CoreAssignment {
|
|
||||||
paras_entry: ParasEntry::new(
|
|
||||||
Assignment::new(ParaId::from(1_u32 + idx as u32)),
|
|
||||||
entry_ttl,
|
|
||||||
),
|
|
||||||
core: core_idx,
|
|
||||||
};
|
|
||||||
ca
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let group_validators = |group_index: GroupIndex| {
|
let group_validators = |group_index: GroupIndex| {
|
||||||
match group_index {
|
match group_index {
|
||||||
@@ -1304,7 +1290,7 @@ mod sanitizers {
|
|||||||
|
|
||||||
// nothing is scheduled, so no paraids match, thus all backed candidates are skipped
|
// nothing is scheduled, so no paraids match, thus all backed candidates are skipped
|
||||||
{
|
{
|
||||||
let scheduled = &Vec::new();
|
let scheduled = &BTreeMap::new();
|
||||||
assert!(sanitize_backed_candidates::<Test, _>(
|
assert!(sanitize_backed_candidates::<Test, _>(
|
||||||
backed_candidates.clone(),
|
backed_candidates.clone(),
|
||||||
has_concluded_invalid,
|
has_concluded_invalid,
|
||||||
|
|||||||
@@ -18,17 +18,17 @@
|
|||||||
//! functions.
|
//! functions.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler,
|
disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent,
|
||||||
|
scheduler::{self, CoreOccupied},
|
||||||
session_info, shared,
|
session_info, shared,
|
||||||
};
|
};
|
||||||
use frame_system::pallet_prelude::*;
|
use frame_system::pallet_prelude::*;
|
||||||
use primitives::{
|
use primitives::{
|
||||||
slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt,
|
slashing, AuthorityDiscoveryId, CandidateEvent, CandidateHash, CommittedCandidateReceipt,
|
||||||
CoreIndex, CoreOccupied, CoreState, DisputeState, ExecutorParams, GroupIndex,
|
CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash,
|
||||||
GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
|
Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, OccupiedCore, OccupiedCoreAssumption,
|
||||||
OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement,
|
PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo,
|
||||||
ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash,
|
ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
|
||||||
ValidatorId, ValidatorIndex, ValidatorSignature,
|
|
||||||
};
|
};
|
||||||
use sp_runtime::traits::One;
|
use sp_runtime::traits::One;
|
||||||
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
use sp_std::{collections::btree_map::BTreeMap, prelude::*};
|
||||||
@@ -52,29 +52,15 @@ pub fn validator_groups<T: initializer::Config>(
|
|||||||
/// Implementation for the `availability_cores` function of the runtime API.
|
/// Implementation for the `availability_cores` function of the runtime API.
|
||||||
pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, BlockNumberFor<T>>> {
|
pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, BlockNumberFor<T>>> {
|
||||||
let cores = <scheduler::Pallet<T>>::availability_cores();
|
let cores = <scheduler::Pallet<T>>::availability_cores();
|
||||||
let config = <configuration::Pallet<T>>::config();
|
|
||||||
let now = <frame_system::Pallet<T>>::block_number() + One::one();
|
let now = <frame_system::Pallet<T>>::block_number() + One::one();
|
||||||
let rotation_info = <scheduler::Pallet<T>>::group_rotation_info(now);
|
|
||||||
|
|
||||||
let time_out_at = |backed_in_number, availability_period| {
|
// This explicit update is only strictly required for session boundaries:
|
||||||
let time_out_at = backed_in_number + availability_period;
|
//
|
||||||
|
// At the end of a session we clear the claim queues: Without this update call, nothing would be
|
||||||
|
// scheduled to the client.
|
||||||
|
<scheduler::Pallet<T>>::update_claimqueue(Vec::new(), now);
|
||||||
|
|
||||||
let current_window = rotation_info.last_rotation_at() + availability_period;
|
let time_out_for = <scheduler::Pallet<T>>::availability_timeout_predicate();
|
||||||
let next_rotation = rotation_info.next_rotation_at();
|
|
||||||
|
|
||||||
// If we are within `period` blocks of rotation, timeouts are being checked
|
|
||||||
// actively. We could even time out this block.
|
|
||||||
if time_out_at < current_window {
|
|
||||||
time_out_at
|
|
||||||
} else if time_out_at <= next_rotation {
|
|
||||||
// Otherwise, it will time out at the sooner of the next rotation
|
|
||||||
next_rotation
|
|
||||||
} else {
|
|
||||||
// or the scheduled time-out. This is by definition within `period` blocks
|
|
||||||
// of `next_rotation` and is thus a valid timeout block.
|
|
||||||
time_out_at
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let group_responsible_for =
|
let group_responsible_for =
|
||||||
|backed_in_number, core_index| match <scheduler::Pallet<T>>::group_assigned_to_core(
|
|backed_in_number, core_index| match <scheduler::Pallet<T>>::group_assigned_to_core(
|
||||||
@@ -93,7 +79,9 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, Bl
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut core_states: Vec<_> = cores
|
let scheduled: BTreeMap<_, _> = <scheduler::Pallet<T>>::scheduled_paras().collect();
|
||||||
|
|
||||||
|
cores
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, core)| match core {
|
.map(|(i, core)| match core {
|
||||||
@@ -108,7 +96,7 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, Bl
|
|||||||
i as u32,
|
i as u32,
|
||||||
)),
|
)),
|
||||||
occupied_since: backed_in_number,
|
occupied_since: backed_in_number,
|
||||||
time_out_at: time_out_at(backed_in_number, config.paras_availability_period),
|
time_out_at: time_out_for(backed_in_number).live_until,
|
||||||
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,
|
||||||
)),
|
)),
|
||||||
@@ -121,19 +109,15 @@ pub fn availability_cores<T: initializer::Config>() -> Vec<CoreState<T::Hash, Bl
|
|||||||
candidate_descriptor: pending_availability.candidate_descriptor().clone(),
|
candidate_descriptor: pending_availability.candidate_descriptor().clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
CoreOccupied::Free => CoreState::Free,
|
CoreOccupied::Free => {
|
||||||
})
|
if let Some(para_id) = scheduled.get(&CoreIndex(i as _)).cloned() {
|
||||||
.collect();
|
CoreState::Scheduled(primitives::ScheduledCore { para_id, collator: None })
|
||||||
|
} else {
|
||||||
// This will overwrite only `Free` cores if the scheduler module is working as intended.
|
CoreState::Free
|
||||||
for scheduled in <scheduler::Pallet<T>>::scheduled_claimqueue() {
|
|
||||||
core_states[scheduled.core.0 as usize] = CoreState::Scheduled(primitives::ScheduledCore {
|
|
||||||
para_id: scheduled.paras_entry.para_id(),
|
|
||||||
collator: None,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
core_states
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns current block number being processed and the corresponding root hash.
|
/// Returns current block number being processed and the corresponding root hash.
|
||||||
|
|||||||
@@ -39,11 +39,11 @@
|
|||||||
use crate::{configuration, initializer::SessionChangeNotification, paras};
|
use crate::{configuration, initializer::SessionChangeNotification, paras};
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::pallet_prelude::*;
|
||||||
use frame_system::pallet_prelude::BlockNumberFor;
|
use frame_system::pallet_prelude::BlockNumberFor;
|
||||||
|
pub use polkadot_core_primitives::v2::BlockNumber;
|
||||||
use primitives::{
|
use primitives::{
|
||||||
v5::ParasEntry, CoreIndex, CoreOccupied, GroupIndex, GroupRotationInfo, Id as ParaId,
|
CoreIndex, GroupIndex, GroupRotationInfo, Id as ParaId, ScheduledCore, ValidatorIndex,
|
||||||
ScheduledCore, ValidatorIndex,
|
|
||||||
};
|
};
|
||||||
use sp_runtime::traits::{One, Saturating};
|
use sp_runtime::traits::One;
|
||||||
use sp_std::{
|
use sp_std::{
|
||||||
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
|
collections::{btree_map::BTreeMap, vec_deque::VecDeque},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@@ -51,7 +51,7 @@ use sp_std::{
|
|||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
||||||
use common::{AssignmentProvider, AssignmentProviderConfig, CoreAssignment, FreedReason};
|
use common::{Assignment, AssignmentProvider, AssignmentProviderConfig};
|
||||||
|
|
||||||
pub use pallet::*;
|
pub use pallet::*;
|
||||||
|
|
||||||
@@ -101,6 +101,36 @@ pub mod pallet {
|
|||||||
pub(crate) type AvailabilityCores<T: Config> =
|
pub(crate) type AvailabilityCores<T: Config> =
|
||||||
StorageValue<_, Vec<CoreOccupied<BlockNumberFor<T>>>, ValueQuery>;
|
StorageValue<_, Vec<CoreOccupied<BlockNumberFor<T>>>, ValueQuery>;
|
||||||
|
|
||||||
|
/// Representation of a core in `AvailabilityCores`.
|
||||||
|
///
|
||||||
|
/// This is not to be confused with `CoreState` which is an enriched variant of this and exposed
|
||||||
|
/// to the node side. It also provides information about scheduled/upcoming assignments for
|
||||||
|
/// example and is computed on the fly in the `availability_cores` runtime call.
|
||||||
|
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
|
||||||
|
#[cfg_attr(feature = "std", derive(PartialEq))]
|
||||||
|
pub enum CoreOccupied<N> {
|
||||||
|
/// No candidate is waiting availability on this core right now (the core is not occupied).
|
||||||
|
Free,
|
||||||
|
/// A para is currently waiting for availability/inclusion on this core.
|
||||||
|
Paras(ParasEntry<N>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> CoreOccupied<N> {
|
||||||
|
/// Is core free?
|
||||||
|
pub fn is_free(&self) -> bool {
|
||||||
|
matches!(self, Self::Free)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reasons a core might be freed.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum FreedReason {
|
||||||
|
/// The core's work concluded and the parablock assigned to it is considered available.
|
||||||
|
Concluded,
|
||||||
|
/// The core's work timed out.
|
||||||
|
TimedOut,
|
||||||
|
}
|
||||||
|
|
||||||
/// The block number where the session start occurred. Used to track how many group rotations
|
/// The block number where the session start occurred. Used to track how many group rotations
|
||||||
/// have occurred.
|
/// have occurred.
|
||||||
///
|
///
|
||||||
@@ -124,6 +154,68 @@ pub mod pallet {
|
|||||||
BTreeMap<CoreIndex, VecDeque<Option<ParasEntry<BlockNumberFor<T>>>>>,
|
BTreeMap<CoreIndex, VecDeque<Option<ParasEntry<BlockNumberFor<T>>>>>,
|
||||||
ValueQuery,
|
ValueQuery,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/// Assignments as tracked in the claim queue.
|
||||||
|
#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
|
||||||
|
pub struct ParasEntry<N = BlockNumber> {
|
||||||
|
/// The underlying `Assignment`
|
||||||
|
pub assignment: Assignment,
|
||||||
|
/// The number of times the entry has timed out in availability already.
|
||||||
|
pub availability_timeouts: u32,
|
||||||
|
/// The block height until this entry needs to be backed.
|
||||||
|
///
|
||||||
|
/// If missed the entry will be removed from the claim queue without ever having occupied
|
||||||
|
/// the core.
|
||||||
|
pub ttl: N,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> ParasEntry<N> {
|
||||||
|
/// Return `Id` from the underlying `Assignment`.
|
||||||
|
pub fn para_id(&self) -> ParaId {
|
||||||
|
self.assignment.para_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `ParasEntry`.
|
||||||
|
pub fn new(assignment: Assignment, now: N) -> Self {
|
||||||
|
ParasEntry { assignment, availability_timeouts: 0, ttl: now }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// How a core is mapped to a backing group and a `ParaId`
|
||||||
|
#[derive(Clone, Encode, Decode, PartialEq, TypeInfo)]
|
||||||
|
#[cfg_attr(feature = "std", derive(Debug))]
|
||||||
|
pub struct CoreAssignment<BlockNumber> {
|
||||||
|
/// The core that is assigned.
|
||||||
|
pub core: CoreIndex,
|
||||||
|
/// The para id and accompanying information needed to collate and back a parablock.
|
||||||
|
pub paras_entry: ParasEntry<BlockNumber>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<BlockNumber> CoreAssignment<BlockNumber> {
|
||||||
|
/// Returns the [`ParaId`] of the assignment.
|
||||||
|
pub fn para_id(&self) -> ParaId {
|
||||||
|
self.paras_entry.para_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the inner [`ParasEntry`] of the assignment.
|
||||||
|
pub fn to_paras_entry(self) -> ParasEntry<BlockNumber> {
|
||||||
|
self.paras_entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Availability timeout status of a core.
|
||||||
|
pub(crate) struct AvailabilityTimeoutStatus<BlockNumber> {
|
||||||
|
/// Is the core already timed out?
|
||||||
|
///
|
||||||
|
/// If this is true the core will be freed at this block.
|
||||||
|
pub timed_out: bool,
|
||||||
|
|
||||||
|
/// When does this core timeout.
|
||||||
|
///
|
||||||
|
/// The block number the core times out. If `timed_out` is true, this will correspond to
|
||||||
|
/// now (current block number).
|
||||||
|
pub live_until: BlockNumber,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PositionInClaimqueue = u32;
|
type PositionInClaimqueue = u32;
|
||||||
@@ -368,48 +460,45 @@ impl<T: Config> Pallet<T> {
|
|||||||
Some(GroupIndex(group_idx as u32))
|
Some(GroupIndex(group_idx as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an optional predicate that should be used for timing out occupied cores.
|
/// Returns a predicate that should be used for timing out occupied cores.
|
||||||
///
|
///
|
||||||
/// If `None`, no timing-out should be done. The predicate accepts the index of the core, and
|
/// This only ever times out cores that have been occupied across a group rotation boundary.
|
||||||
/// the block number since which it has been occupied, and the respective parachain timeouts,
|
|
||||||
/// i.e. only within `config.paras_availability_period` of the last rotation would this return
|
|
||||||
/// `Some`, unless there are no rotations.
|
|
||||||
///
|
|
||||||
/// The timeout used to depend, but does not depend any more on group rotations. First of all
|
|
||||||
/// it only matters if a para got another chance (a retry). If there is a retry and it happens
|
|
||||||
/// still within the same group rotation a censoring backing group would need to censor again
|
|
||||||
/// and lose out again on backing rewards. This is bad for the censoring backing group, it does
|
|
||||||
/// not matter for the parachain as long as it is retried often enough (so it eventually gets a
|
|
||||||
/// try on another backing group) - the effect is similar to having a prolonged timeout. It
|
|
||||||
/// should also be noted that for both malicious and offline backing groups it is actually more
|
|
||||||
/// realistic that the candidate will not be backed to begin with, instead of getting backed
|
|
||||||
/// and then not made available.
|
|
||||||
pub(crate) fn availability_timeout_predicate(
|
pub(crate) fn availability_timeout_predicate(
|
||||||
) -> Option<impl Fn(CoreIndex, BlockNumberFor<T>) -> bool> {
|
) -> impl Fn(BlockNumberFor<T>) -> AvailabilityTimeoutStatus<BlockNumberFor<T>> {
|
||||||
let now = <frame_system::Pallet<T>>::block_number();
|
|
||||||
let config = <configuration::Pallet<T>>::config();
|
let config = <configuration::Pallet<T>>::config();
|
||||||
let session_start = <SessionStartBlock<T>>::get();
|
|
||||||
|
|
||||||
let blocks_since_session_start = now.saturating_sub(session_start);
|
|
||||||
let blocks_since_last_rotation =
|
|
||||||
blocks_since_session_start % config.group_rotation_frequency.max(1u8.into());
|
|
||||||
|
|
||||||
if blocks_since_last_rotation >= config.paras_availability_period {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(|core_index: CoreIndex, pending_since| {
|
|
||||||
let availability_cores = AvailabilityCores::<T>::get();
|
|
||||||
let AssignmentProviderConfig { availability_period, .. } =
|
|
||||||
T::AssignmentProvider::get_provider_config(core_index);
|
|
||||||
let now = <frame_system::Pallet<T>>::block_number();
|
let now = <frame_system::Pallet<T>>::block_number();
|
||||||
match availability_cores.get(core_index.0 as usize) {
|
let rotation_info = Self::group_rotation_info(now);
|
||||||
None => true, // out-of-bounds, doesn't really matter what is returned.
|
|
||||||
Some(CoreOccupied::Free) => true, // core free, still doesn't matter.
|
let next_rotation = rotation_info.next_rotation_at();
|
||||||
Some(CoreOccupied::Paras(_)) =>
|
|
||||||
now.saturating_sub(pending_since) >= availability_period,
|
let times_out = Self::availability_timeout_check_required();
|
||||||
|
|
||||||
|
move |pending_since| {
|
||||||
|
let time_out_at = if times_out {
|
||||||
|
// We are at the beginning of the rotation, here availability period is relevant.
|
||||||
|
// Note: blocks backed in this rotation will never time out here as backed_in +
|
||||||
|
// config.paras_availability_period will always be > now for these blocks, as
|
||||||
|
// otherwise above condition would not be true.
|
||||||
|
pending_since + config.paras_availability_period
|
||||||
|
} else {
|
||||||
|
next_rotation + config.paras_availability_period
|
||||||
|
};
|
||||||
|
|
||||||
|
AvailabilityTimeoutStatus { timed_out: time_out_at <= now, live_until: time_out_at }
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is evaluation of `availability_timeout_predicate` necessary at the current block?
|
||||||
|
///
|
||||||
|
/// This can be used to avoid calling `availability_timeout_predicate` for each core in case
|
||||||
|
/// this function returns false.
|
||||||
|
pub(crate) fn availability_timeout_check_required() -> bool {
|
||||||
|
let config = <configuration::Pallet<T>>::config();
|
||||||
|
let now = <frame_system::Pallet<T>>::block_number() + One::one();
|
||||||
|
let rotation_info = Self::group_rotation_info(now);
|
||||||
|
|
||||||
|
let current_window = rotation_info.last_rotation_at() + config.paras_availability_period;
|
||||||
|
now < current_window
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a helper for determining group rotation.
|
/// Returns a helper for determining group rotation.
|
||||||
@@ -508,7 +597,7 @@ impl<T: Config> Pallet<T> {
|
|||||||
pub(crate) fn update_claimqueue(
|
pub(crate) fn update_claimqueue(
|
||||||
just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>,
|
just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>,
|
||||||
now: BlockNumberFor<T>,
|
now: BlockNumberFor<T>,
|
||||||
) -> Vec<CoreAssignment<BlockNumberFor<T>>> {
|
) {
|
||||||
Self::move_claimqueue_forward();
|
Self::move_claimqueue_forward();
|
||||||
Self::free_cores_and_fill_claimqueue(just_freed_cores, now)
|
Self::free_cores_and_fill_claimqueue(just_freed_cores, now)
|
||||||
}
|
}
|
||||||
@@ -534,14 +623,14 @@ impl<T: Config> Pallet<T> {
|
|||||||
fn free_cores_and_fill_claimqueue(
|
fn free_cores_and_fill_claimqueue(
|
||||||
just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>,
|
just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>,
|
||||||
now: BlockNumberFor<T>,
|
now: BlockNumberFor<T>,
|
||||||
) -> Vec<CoreAssignment<BlockNumberFor<T>>> {
|
) {
|
||||||
let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores);
|
let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores);
|
||||||
|
|
||||||
// This can only happen on new sessions at which we move all assignments back to the
|
// This can only happen on new sessions at which we move all assignments back to the
|
||||||
// provider. Hence, there's nothing we need to do here.
|
// provider. Hence, there's nothing we need to do here.
|
||||||
if ValidatorGroups::<T>::get().is_empty() {
|
if ValidatorGroups::<T>::get().is_empty() {
|
||||||
vec![]
|
return
|
||||||
} else {
|
}
|
||||||
let n_lookahead = Self::claimqueue_lookahead();
|
let n_lookahead = Self::claimqueue_lookahead();
|
||||||
let n_session_cores = T::AssignmentProvider::session_core_count();
|
let n_session_cores = T::AssignmentProvider::session_core_count();
|
||||||
let cq = ClaimQueue::<T>::get();
|
let cq = ClaimQueue::<T>::get();
|
||||||
@@ -586,9 +675,6 @@ impl<T: Config> Pallet<T> {
|
|||||||
|
|
||||||
debug_assert!(timedout_paras.is_empty());
|
debug_assert!(timedout_paras.is_empty());
|
||||||
debug_assert!(concluded_paras.is_empty());
|
debug_assert!(concluded_paras.is_empty());
|
||||||
|
|
||||||
Self::scheduled_claimqueue()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_core_occupied(core_idx: CoreIndex) -> bool {
|
fn is_core_occupied(core_idx: CoreIndex) -> bool {
|
||||||
@@ -623,29 +709,22 @@ impl<T: Config> Pallet<T> {
|
|||||||
.ok_or("remove returned None")?
|
.ok_or("remove returned None")?
|
||||||
.ok_or("Element in Claimqueue was None.")?;
|
.ok_or("Element in Claimqueue was None.")?;
|
||||||
|
|
||||||
// Since the core is now occupied, the next entry in the claimqueue in order to achieve
|
|
||||||
// 12 second block times needs to be None
|
|
||||||
if core_claims.front() != Some(&None) {
|
|
||||||
core_claims.push_front(None);
|
|
||||||
}
|
|
||||||
Ok((pos as u32, pe))
|
Ok((pos as u32, pe))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Temporary to imitate the old schedule() call. Will be adjusted when we make the
|
/// Paras scheduled next in the claim queue.
|
||||||
// scheduler AB ready
|
pub(crate) fn scheduled_paras() -> impl Iterator<Item = (CoreIndex, ParaId)> {
|
||||||
pub(crate) fn scheduled_claimqueue() -> Vec<CoreAssignment<BlockNumberFor<T>>> {
|
Self::scheduled_entries().map(|(core_idx, e)| (core_idx, e.assignment.para_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal access to entries at the top of the claim queue.
|
||||||
|
fn scheduled_entries() -> impl Iterator<Item = (CoreIndex, ParasEntry<BlockNumberFor<T>>)> {
|
||||||
let claimqueue = ClaimQueue::<T>::get();
|
let claimqueue = ClaimQueue::<T>::get();
|
||||||
|
|
||||||
claimqueue
|
claimqueue
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|(core_idx, v)| {
|
.filter_map(|(core_idx, v)| v.front().cloned().flatten().map(|e| (core_idx, e)))
|
||||||
v.front()
|
|
||||||
.cloned()
|
|
||||||
.flatten()
|
|
||||||
.map(|pe| CoreAssignment { core: core_idx, paras_entry: pe })
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "runtime-benchmarks", test))]
|
#[cfg(any(feature = "runtime-benchmarks", test))]
|
||||||
|
|||||||
@@ -17,10 +17,7 @@
|
|||||||
//! Common traits and types used by the scheduler and assignment providers.
|
//! Common traits and types used by the scheduler and assignment providers.
|
||||||
|
|
||||||
use frame_support::pallet_prelude::*;
|
use frame_support::pallet_prelude::*;
|
||||||
use primitives::{
|
use primitives::{CoreIndex, Id as ParaId};
|
||||||
v5::{Assignment, ParasEntry},
|
|
||||||
CoreIndex, Id as ParaId,
|
|
||||||
};
|
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
@@ -28,21 +25,22 @@ use sp_std::prelude::*;
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::configuration::HostConfiguration;
|
use crate::configuration::HostConfiguration;
|
||||||
|
|
||||||
/// Reasons a core might be freed
|
/// An assignment for a parachain scheduled to be backed and included in a relay chain block.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, RuntimeDebug)]
|
||||||
pub enum FreedReason {
|
pub struct Assignment {
|
||||||
/// The core's work concluded and the parablock assigned to it is considered available.
|
/// Assignment's ParaId
|
||||||
Concluded,
|
pub para_id: ParaId,
|
||||||
/// The core's work timed out.
|
}
|
||||||
TimedOut,
|
|
||||||
|
impl Assignment {
|
||||||
|
/// Create a new `Assignment`.
|
||||||
|
pub fn new(para_id: ParaId) -> Self {
|
||||||
|
Self { para_id }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of variables required by the scheduler in order to operate.
|
/// A set of variables required by the scheduler in order to operate.
|
||||||
pub struct AssignmentProviderConfig<BlockNumber> {
|
pub struct AssignmentProviderConfig<BlockNumber> {
|
||||||
/// The availability period specified by the implementation.
|
|
||||||
/// See [`HostConfiguration::paras_availability_period`] for more information.
|
|
||||||
pub availability_period: BlockNumber,
|
|
||||||
|
|
||||||
/// How many times a collation can time out on availability.
|
/// How many times a collation can time out on availability.
|
||||||
/// Zero timeouts still means that a collation can be provided as per the slot auction
|
/// Zero timeouts still means that a collation can be provided as per the slot auction
|
||||||
/// assignment provider.
|
/// assignment provider.
|
||||||
@@ -72,25 +70,3 @@ pub trait AssignmentProvider<BlockNumber> {
|
|||||||
/// Returns a set of variables needed by the scheduler
|
/// Returns a set of variables needed by the scheduler
|
||||||
fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumber>;
|
fn get_provider_config(core_idx: CoreIndex) -> AssignmentProviderConfig<BlockNumber>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How a core is mapped to a backing group and a `ParaId`
|
|
||||||
#[derive(Clone, Encode, Decode, PartialEq, TypeInfo)]
|
|
||||||
#[cfg_attr(feature = "std", derive(Debug))]
|
|
||||||
pub struct CoreAssignment<BlockNumber> {
|
|
||||||
/// The core that is assigned.
|
|
||||||
pub core: CoreIndex,
|
|
||||||
/// The para id and accompanying information needed to collate and back a parablock.
|
|
||||||
pub paras_entry: ParasEntry<BlockNumber>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<BlockNumber> CoreAssignment<BlockNumber> {
|
|
||||||
/// Returns the [`ParaId`] of the assignment.
|
|
||||||
pub fn para_id(&self) -> ParaId {
|
|
||||||
self.paras_entry.para_id()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the inner [`ParasEntry`] of the assignment.
|
|
||||||
pub fn to_paras_entry(self) -> ParasEntry<BlockNumber> {
|
|
||||||
self.paras_entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ use super::*;
|
|||||||
use frame_support::{
|
use frame_support::{
|
||||||
pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight,
|
pallet_prelude::ValueQuery, storage_alias, traits::OnRuntimeUpgrade, weights::Weight,
|
||||||
};
|
};
|
||||||
use primitives::vstaging::Assignment;
|
|
||||||
|
|
||||||
mod v0 {
|
mod v0 {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use super::*;
|
|||||||
|
|
||||||
use frame_support::assert_ok;
|
use frame_support::assert_ok;
|
||||||
use keyring::Sr25519Keyring;
|
use keyring::Sr25519Keyring;
|
||||||
use primitives::{v5::Assignment, BlockNumber, SessionIndex, ValidationCode, ValidatorId};
|
use primitives::{BlockNumber, SessionIndex, ValidationCode, ValidatorId};
|
||||||
use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
|
use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -427,33 +427,27 @@ fn fill_claimqueue_fills() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
assert_eq!(Scheduler::claimqueue_len(), 2 * lookahead);
|
assert_eq!(Scheduler::claimqueue_len(), 2 * lookahead);
|
||||||
let scheduled = Scheduler::scheduled_claimqueue();
|
let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect();
|
||||||
|
|
||||||
// Cannot assert on indices anymore as they depend on the assignment providers
|
// Cannot assert on indices anymore as they depend on the assignment providers
|
||||||
assert!(claimqueue_contains_para_ids::<Test>(vec![chain_a, chain_b]));
|
assert!(claimqueue_contains_para_ids::<Test>(vec![chain_a, chain_b]));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[0],
|
scheduled.get(&CoreIndex(0)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(0),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_a },
|
assignment: Assignment { para_id: chain_a },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 6
|
ttl: 6
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[1],
|
scheduled.get(&CoreIndex(1)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(1),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_b },
|
assignment: Assignment { para_id: chain_b },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 6
|
ttl: 6
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,42 +475,33 @@ fn fill_claimqueue_fills() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
assert_eq!(Scheduler::claimqueue_len(), 5);
|
assert_eq!(Scheduler::claimqueue_len(), 5);
|
||||||
let scheduled = Scheduler::scheduled_claimqueue();
|
let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[0],
|
scheduled.get(&CoreIndex(0)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(0),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_a },
|
assignment: Assignment { para_id: chain_a },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 6
|
ttl: 6
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[1],
|
scheduled.get(&CoreIndex(1)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(1),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_b },
|
assignment: Assignment { para_id: chain_b },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 6
|
ttl: 6
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Was added a block later, note the TTL.
|
// Was added a block later, note the TTL.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[2],
|
scheduled.get(&CoreIndex(2)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(2),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_a },
|
assignment: Assignment { para_id: thread_a },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 7
|
ttl: 7
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
// Sits on the same core as `thread_a`
|
// Sits on the same core as `thread_a`
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -528,15 +513,12 @@ fn fill_claimqueue_fills() {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[3],
|
scheduled.get(&CoreIndex(3)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(3),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_c },
|
assignment: Assignment { para_id: thread_c },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 7
|
ttl: 7
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -608,7 +590,7 @@ fn schedule_schedules_including_just_freed() {
|
|||||||
let mut now = 2;
|
let mut now = 2;
|
||||||
run_to_block(now, |_| None);
|
run_to_block(now, |_| None);
|
||||||
|
|
||||||
assert_eq!(Scheduler::scheduled_claimqueue().len(), 4);
|
assert_eq!(Scheduler::scheduled_paras().collect::<Vec<_>>().len(), 4);
|
||||||
|
|
||||||
// cores 0, 1, 2, and 3 should be occupied. mark them as such.
|
// cores 0, 1, 2, and 3 should be occupied. mark them as such.
|
||||||
let mut occupied_map: BTreeMap<CoreIndex, ParaId> = BTreeMap::new();
|
let mut occupied_map: BTreeMap<CoreIndex, ParaId> = BTreeMap::new();
|
||||||
@@ -630,7 +612,7 @@ fn schedule_schedules_including_just_freed() {
|
|||||||
// core 4 is free
|
// core 4 is free
|
||||||
assert!(cores[4] == CoreOccupied::Free);
|
assert!(cores[4] == CoreOccupied::Free);
|
||||||
|
|
||||||
assert!(Scheduler::scheduled_claimqueue().is_empty());
|
assert!(Scheduler::scheduled_paras().collect::<Vec<_>>().is_empty());
|
||||||
|
|
||||||
// All core index entries in the claimqueue should have `None` in them.
|
// All core index entries in the claimqueue should have `None` in them.
|
||||||
Scheduler::claimqueue().iter().for_each(|(_core_idx, core_queue)| {
|
Scheduler::claimqueue().iter().for_each(|(_core_idx, core_queue)| {
|
||||||
@@ -657,21 +639,18 @@ fn schedule_schedules_including_just_freed() {
|
|||||||
run_to_block(now, |_| None);
|
run_to_block(now, |_| None);
|
||||||
|
|
||||||
{
|
{
|
||||||
let scheduled = Scheduler::scheduled_claimqueue();
|
let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect();
|
||||||
|
|
||||||
// cores 0 and 1 are occupied by lease holding parachains. cores 2 and 3 are occupied by
|
// cores 0 and 1 are occupied by lease holding parachains. cores 2 and 3 are occupied by
|
||||||
// on-demand parachain claims. core 4 was free.
|
// on-demand parachain claims. core 4 was free.
|
||||||
assert_eq!(scheduled.len(), 1);
|
assert_eq!(scheduled.len(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[0],
|
scheduled.get(&CoreIndex(4)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(4),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_b },
|
assignment: Assignment { para_id: thread_b },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 8
|
ttl: 8
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,54 +665,42 @@ fn schedule_schedules_including_just_freed() {
|
|||||||
Scheduler::update_claimqueue(just_updated, now);
|
Scheduler::update_claimqueue(just_updated, now);
|
||||||
|
|
||||||
{
|
{
|
||||||
let scheduled = Scheduler::scheduled_claimqueue();
|
let scheduled: BTreeMap<_, _> = Scheduler::scheduled_entries().collect();
|
||||||
|
|
||||||
// 1 thing scheduled before, + 3 cores freed.
|
// 1 thing scheduled before, + 3 cores freed.
|
||||||
assert_eq!(scheduled.len(), 4);
|
assert_eq!(scheduled.len(), 4);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[0],
|
scheduled.get(&CoreIndex(0)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(0),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: chain_a },
|
assignment: Assignment { para_id: chain_a },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 8
|
ttl: 8
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[1],
|
scheduled.get(&CoreIndex(2)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(2),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_d },
|
assignment: Assignment { para_id: thread_d },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 8
|
ttl: 8
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
// Although C was descheduled, the core `4` was occupied so C goes back to the queue.
|
// Although C was descheduled, the core `4` was occupied so C goes back to the queue.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[2],
|
scheduled.get(&CoreIndex(3)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(3),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_c },
|
assignment: Assignment { para_id: thread_c },
|
||||||
availability_timeouts: 1,
|
availability_timeouts: 1,
|
||||||
ttl: 8
|
ttl: 8
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
scheduled[3],
|
scheduled.get(&CoreIndex(4)).unwrap(),
|
||||||
CoreAssignment {
|
&ParasEntry {
|
||||||
core: CoreIndex(4),
|
|
||||||
paras_entry: ParasEntry {
|
|
||||||
assignment: Assignment { para_id: thread_b },
|
assignment: Assignment { para_id: thread_b },
|
||||||
availability_timeouts: 0,
|
availability_timeouts: 0,
|
||||||
ttl: 8
|
ttl: 8
|
||||||
},
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// The only assignment yet to be popped on to the claim queue is `thread_e`.
|
// The only assignment yet to be popped on to the claim queue is `thread_e`.
|
||||||
@@ -900,14 +867,14 @@ fn schedule_rotates_groups() {
|
|||||||
run_to_block(now, |_| None);
|
run_to_block(now, |_| None);
|
||||||
|
|
||||||
let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor<Test>| {
|
let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor<Test>| {
|
||||||
let scheduled = Scheduler::scheduled_claimqueue();
|
let scheduled: BTreeMap<_, _> = Scheduler::scheduled_paras().collect();
|
||||||
assert_eq!(scheduled.len(), 2);
|
assert_eq!(scheduled.len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Scheduler::group_assigned_to_core(scheduled[0].core, *now).unwrap(),
|
Scheduler::group_assigned_to_core(CoreIndex(0), *now).unwrap(),
|
||||||
GroupIndex((0u32 + rotations) % on_demand_cores)
|
GroupIndex((0u32 + rotations) % on_demand_cores)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Scheduler::group_assigned_to_core(scheduled[1].core, *now).unwrap(),
|
Scheduler::group_assigned_to_core(CoreIndex(1), *now).unwrap(),
|
||||||
GroupIndex((1u32 + rotations) % on_demand_cores)
|
GroupIndex((1u32 + rotations) % on_demand_cores)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -999,7 +966,7 @@ fn on_demand_claims_are_pruned_after_timing_out() {
|
|||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
let core_assignments = Scheduler::update_claimqueue(just_updated, now);
|
Scheduler::update_claimqueue(just_updated, now);
|
||||||
|
|
||||||
// ParaId a exists in the claim queue until max_retries is reached.
|
// ParaId a exists in the claim queue until max_retries is reached.
|
||||||
if n < max_retries + now {
|
if n < max_retries + now {
|
||||||
@@ -1008,13 +975,9 @@ fn on_demand_claims_are_pruned_after_timing_out() {
|
|||||||
assert!(!claimqueue_contains_para_ids::<Test>(vec![thread_a]));
|
assert!(!claimqueue_contains_para_ids::<Test>(vec![thread_a]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occupy the cores based on the output of update_claimqueue.
|
let core_assignments = Scheduler::scheduled_paras().collect();
|
||||||
Scheduler::occupied(
|
// Occupy the cores based on the result of update_claimqueue.
|
||||||
core_assignments
|
Scheduler::occupied(core_assignments);
|
||||||
.iter()
|
|
||||||
.map(|core_assignment| (core_assignment.core, core_assignment.para_id()))
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParaId a does not exist in the claimqueue/availability_cores after
|
// ParaId a does not exist in the claimqueue/availability_cores after
|
||||||
@@ -1054,7 +1017,7 @@ fn on_demand_claims_are_pruned_after_timing_out() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let core_assignments = Scheduler::update_claimqueue(just_updated, now);
|
Scheduler::update_claimqueue(just_updated, now);
|
||||||
|
|
||||||
// ParaId a exists in the claim queue until groups are rotated.
|
// ParaId a exists in the claim queue until groups are rotated.
|
||||||
if n < 31 {
|
if n < 31 {
|
||||||
@@ -1063,13 +1026,9 @@ fn on_demand_claims_are_pruned_after_timing_out() {
|
|||||||
assert!(!claimqueue_contains_para_ids::<Test>(vec![thread_a]));
|
assert!(!claimqueue_contains_para_ids::<Test>(vec![thread_a]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Occupy the cores based on the output of update_claimqueue.
|
let core_assignments = Scheduler::scheduled_paras().collect();
|
||||||
Scheduler::occupied(
|
// Occupy the cores based on the result of update_claimqueue.
|
||||||
core_assignments
|
Scheduler::occupied(core_assignments);
|
||||||
.iter()
|
|
||||||
.map(|core_assignment| (core_assignment.core, core_assignment.para_id()))
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParaId a does not exist in the claimqueue/availability_cores after
|
// ParaId a does not exist in the claimqueue/availability_cores after
|
||||||
@@ -1124,33 +1083,25 @@ fn availability_predicate_works() {
|
|||||||
|
|
||||||
run_to_block(1 + paras_availability_period, |_| None);
|
run_to_block(1 + paras_availability_period, |_| None);
|
||||||
|
|
||||||
assert!(Scheduler::availability_timeout_predicate().is_none());
|
assert!(!Scheduler::availability_timeout_check_required());
|
||||||
|
|
||||||
run_to_block(1 + group_rotation_frequency, |_| None);
|
run_to_block(1 + group_rotation_frequency, |_| None);
|
||||||
|
|
||||||
{
|
{
|
||||||
let pred = Scheduler::availability_timeout_predicate()
|
|
||||||
.expect("predicate exists recently after rotation");
|
|
||||||
|
|
||||||
let now = System::block_number();
|
let now = System::block_number();
|
||||||
|
assert!(Scheduler::availability_timeout_check_required());
|
||||||
|
let pred = Scheduler::availability_timeout_predicate();
|
||||||
|
let last_rotation = Scheduler::group_rotation_info(now).last_rotation_at();
|
||||||
|
|
||||||
let would_be_timed_out = now - paras_availability_period;
|
let would_be_timed_out = now - paras_availability_period;
|
||||||
for i in 0..AvailabilityCores::<Test>::get().len() {
|
let should_not_be_timed_out = last_rotation;
|
||||||
// returns true for unoccupied cores.
|
|
||||||
// And can time out paras at this stage.
|
|
||||||
assert!(pred(CoreIndex(i as u32), would_be_timed_out));
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(!pred(CoreIndex(0), now));
|
assert!(pred(would_be_timed_out).timed_out);
|
||||||
assert!(!pred(CoreIndex(1), now));
|
assert!(!pred(should_not_be_timed_out).timed_out);
|
||||||
assert!(pred(CoreIndex(2), now));
|
assert!(!pred(now).timed_out);
|
||||||
|
|
||||||
// check the tight bound.
|
|
||||||
assert!(pred(CoreIndex(0), now - paras_availability_period));
|
|
||||||
assert!(pred(CoreIndex(1), now - paras_availability_period));
|
|
||||||
|
|
||||||
// check the threshold is exact.
|
// check the threshold is exact.
|
||||||
assert!(!pred(CoreIndex(0), now - paras_availability_period + 1));
|
assert!(!pred(would_be_timed_out + 1).timed_out);
|
||||||
assert!(!pred(CoreIndex(1), now - paras_availability_period + 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
run_to_block(1 + group_rotation_frequency + paras_availability_period, |_| None);
|
run_to_block(1 + group_rotation_frequency + paras_availability_period, |_| None);
|
||||||
|
|||||||
Reference in New Issue
Block a user