mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 08:41:02 +00:00
Use same fmt and clippy configs as in Substrate (#7611)
* Use same rustfmt.toml as Substrate Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * format format file Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Format with new config Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Add Substrate Clippy config Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Print Clippy version in CI Otherwise its difficult to reproduce locally. Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Make fmt happy Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update node/core/pvf/src/error.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> * Update node/core/pvf/src/error.rs Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io> --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Tsvetomir Dimitrov <tsvetomir@parity.io>
This commit is contained in:
committed by
GitHub
parent
ac435c96cf
commit
342d720573
@@ -174,7 +174,8 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
|
||||
configuration::Pallet::<T>::config().max_validators.unwrap_or(200)
|
||||
}
|
||||
|
||||
/// Maximum number of validators participating in parachains consensus (a.k.a. active validators).
|
||||
/// Maximum number of validators participating in parachains consensus (a.k.a. active
|
||||
/// validators).
|
||||
fn max_validators(&self) -> u32 {
|
||||
self.max_validators.unwrap_or(Self::fallback_max_validators())
|
||||
}
|
||||
@@ -186,8 +187,8 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Maximum number of validators per core (a.k.a. max validators per group). This value is used if none is
|
||||
/// explicitly set on the builder.
|
||||
/// Maximum number of validators per core (a.k.a. max validators per group). This value is used
|
||||
/// if none is explicitly set on the builder.
|
||||
pub(crate) fn fallback_max_validators_per_core() -> u32 {
|
||||
configuration::Pallet::<T>::config().max_validators_per_core.unwrap_or(5)
|
||||
}
|
||||
@@ -479,7 +480,8 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
|
||||
/// Create backed candidates for `cores_with_backed_candidates`. You need these cores to be
|
||||
/// scheduled _within_ paras inherent, which requires marking the available bitfields as fully
|
||||
/// available.
|
||||
/// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number of
|
||||
/// - `cores_with_backed_candidates` Mapping of `para_id`/`core_idx`/`group_idx` seed to number
|
||||
/// of
|
||||
/// validity votes.
|
||||
fn create_backed_candidates(
|
||||
&self,
|
||||
@@ -687,9 +689,9 @@ impl<T: paras_inherent::Config> BenchBuilder<T> {
|
||||
);
|
||||
assert_eq!(inclusion::PendingAvailability::<T>::iter().count(), used_cores as usize,);
|
||||
|
||||
// Mark all the used cores as occupied. We expect that their are `backed_and_concluding_cores`
|
||||
// that are pending availability and that there are `used_cores - backed_and_concluding_cores `
|
||||
// which are about to be disputed.
|
||||
// Mark all the used cores as occupied. We expect that their are
|
||||
// `backed_and_concluding_cores` that are pending availability and that there are
|
||||
// `used_cores - backed_and_concluding_cores ` which are about to be disputed.
|
||||
scheduler::AvailabilityCores::<T>::set(vec![
|
||||
Some(CoreOccupied::Parachain);
|
||||
used_cores as usize
|
||||
|
||||
@@ -54,12 +54,12 @@ const LOG_TARGET: &str = "runtime::configuration";
|
||||
serde::Deserialize,
|
||||
)]
|
||||
pub struct HostConfiguration<BlockNumber> {
|
||||
// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct requires
|
||||
// special treatment.
|
||||
// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct
|
||||
// requires special treatment.
|
||||
//
|
||||
// A parachain requested this struct can only depend on the subset of this struct. Specifically,
|
||||
// only a first few fields can be depended upon. These fields cannot be changed without
|
||||
// corresponding migration of the parachains.
|
||||
// A parachain requested this struct can only depend on the subset of this struct.
|
||||
// Specifically, only a first few fields can be depended upon. These fields cannot be changed
|
||||
// without corresponding migration of the parachains.
|
||||
/**
|
||||
* The parameters that are required for the parachains.
|
||||
*/
|
||||
@@ -88,9 +88,9 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
pub hrmp_max_message_num_per_candidate: u32,
|
||||
/// The minimum period, in blocks, between which parachains can update their validation code.
|
||||
///
|
||||
/// This number is used to prevent parachains from spamming the relay chain with validation code
|
||||
/// upgrades. The only thing it controls is the number of blocks the `UpgradeRestrictionSignal`
|
||||
/// is set for the parachain in question.
|
||||
/// This number is used to prevent parachains from spamming the relay chain with validation
|
||||
/// code upgrades. The only thing it controls is the number of blocks the
|
||||
/// `UpgradeRestrictionSignal` is set for the parachain in question.
|
||||
///
|
||||
/// If PVF pre-checking is enabled this should be greater than the maximum number of blocks
|
||||
/// PVF pre-checking can take. Intuitively, this number should be greater than the duration
|
||||
@@ -113,14 +113,15 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
/// been completed.
|
||||
///
|
||||
/// Note, there are situations in which `expected_at` in the past. For example, if
|
||||
/// [`chain_availability_period`] or [`thread_availability_period`] is less than the delay set by
|
||||
/// this field or if PVF pre-check took more time than the delay. In such cases, the upgrade is
|
||||
/// further at the earliest possible time determined by [`minimum_validation_upgrade_delay`].
|
||||
/// [`chain_availability_period`] or [`thread_availability_period`] is less than the delay set
|
||||
/// by this field or if PVF pre-check took more time than the delay. In such cases, the upgrade
|
||||
/// is further at the earliest possible time determined by
|
||||
/// [`minimum_validation_upgrade_delay`].
|
||||
///
|
||||
/// The rationale for this delay has to do with relay-chain reversions. In case there is an
|
||||
/// invalid candidate produced with the new version of the code, then the relay-chain can revert
|
||||
/// [`validation_upgrade_delay`] many blocks back and still find the new code in the storage by
|
||||
/// hash.
|
||||
/// invalid candidate produced with the new version of the code, then the relay-chain can
|
||||
/// revert [`validation_upgrade_delay`] many blocks back and still find the new code in the
|
||||
/// storage by hash.
|
||||
///
|
||||
/// [#4601]: https://github.com/paritytech/polkadot/issues/4601
|
||||
pub validation_upgrade_delay: BlockNumber,
|
||||
@@ -179,13 +180,13 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
/// Must be non-zero.
|
||||
pub group_rotation_frequency: BlockNumber,
|
||||
/// The availability period, in blocks, for parachains. This is the amount of blocks
|
||||
/// after inclusion that validators have to make the block available and signal its availability to
|
||||
/// the chain.
|
||||
/// after inclusion that validators have to make the block available and signal its
|
||||
/// availability to the chain.
|
||||
///
|
||||
/// Must be at least 1.
|
||||
pub chain_availability_period: BlockNumber,
|
||||
/// The availability period, in blocks, for parathreads. Same as the `chain_availability_period`,
|
||||
/// but a differing timeout due to differing requirements.
|
||||
/// The availability period, in blocks, for parathreads. Same as the
|
||||
/// `chain_availability_period`, but a differing timeout due to differing requirements.
|
||||
///
|
||||
/// Must be at least 1.
|
||||
pub thread_availability_period: BlockNumber,
|
||||
@@ -217,8 +218,8 @@ pub struct HostConfiguration<BlockNumber> {
|
||||
pub needed_approvals: u32,
|
||||
/// The number of samples to do of the `RelayVRFModulo` approval assignment criterion.
|
||||
pub relay_vrf_modulo_samples: u32,
|
||||
/// If an active PVF pre-checking vote observes this many number of sessions it gets automatically
|
||||
/// rejected.
|
||||
/// If an active PVF pre-checking vote observes this many number of sessions it gets
|
||||
/// automatically rejected.
|
||||
///
|
||||
/// 0 means PVF pre-checking will be rejected on the first observed session unless the voting
|
||||
/// gained supermajority before that the session change.
|
||||
@@ -849,7 +850,8 @@ pub mod pallet {
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets the maximum total size of items that can present in a upward dispatch queue at once.
|
||||
/// Sets the maximum total size of items that can present in a upward dispatch queue at
|
||||
/// once.
|
||||
#[pallet::call_index(24)]
|
||||
#[pallet::weight((
|
||||
T::WeightInfo::set_config_with_u32(),
|
||||
@@ -1257,8 +1259,8 @@ impl<T: Config> Pallet<T> {
|
||||
// 3. pending_configs = [(cur+1, X)]
|
||||
// There is a pending configuration scheduled and it will be applied in the next session.
|
||||
//
|
||||
// We will use X as the base configuration. We need to schedule a new configuration change
|
||||
// for the `scheduled_session` and use X as the base for the new configuration.
|
||||
// We will use X as the base configuration. We need to schedule a new configuration
|
||||
// change for the `scheduled_session` and use X as the base for the new configuration.
|
||||
//
|
||||
// 4. pending_configs = [(cur+1, X), (cur+2, Y)]
|
||||
// There is a pending configuration change in the next session and for the scheduled
|
||||
|
||||
@@ -182,10 +182,12 @@ mod tests {
|
||||
// Steps:
|
||||
// 1. Go to Polkadot.js -> Developer -> Chain state -> Storage: https://polkadot.js.org/apps/#/chainstate
|
||||
// 2. Set these parameters:
|
||||
// 2.1. selected state query: configuration; activeConfig(): PolkadotRuntimeParachainsConfigurationHostConfiguration
|
||||
// 2.2. blockhash to query at: 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of the block)
|
||||
// 2.3. Note the value of encoded storage key -> 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the referenced block.
|
||||
// 2.4. You'll also need the decoded values to update the test.
|
||||
// 2.1. selected state query: configuration; activeConfig():
|
||||
// PolkadotRuntimeParachainsConfigurationHostConfiguration 2.2. blockhash to query at:
|
||||
// 0xf89d3ab5312c5f70d396dc59612f0aa65806c798346f9db4b35278baed2e0e53 (the hash of the
|
||||
// block) 2.3. Note the value of encoded storage key ->
|
||||
// 0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385 for the referenced
|
||||
// block. 2.4. You'll also need the decoded values to update the test.
|
||||
// 3. Go to Polkadot.js -> Developer -> Chain state -> Raw storage
|
||||
// 3.1 Enter the encoded storage key and you get the raw config.
|
||||
|
||||
@@ -196,8 +198,8 @@ mod tests {
|
||||
let v6 =
|
||||
V6HostConfiguration::<primitives::BlockNumber>::decode(&mut &raw_config[..]).unwrap();
|
||||
|
||||
// We check only a sample of the values here. If we missed any fields or messed up data types
|
||||
// that would skew all the fields coming after.
|
||||
// We check only a sample of the values here. If we missed any fields or messed up data
|
||||
// types that would skew all the fields coming after.
|
||||
assert_eq!(v6.max_code_size, 3_145_728);
|
||||
assert_eq!(v6.validation_upgrade_cooldown, 200);
|
||||
assert_eq!(v6.max_pov_size, 5_242_880);
|
||||
@@ -209,8 +211,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_migrate_to_v7() {
|
||||
// Host configuration has lots of fields. However, in this migration we only remove one field.
|
||||
// The most important part to check are a couple of the last fields. We also pick
|
||||
// Host configuration has lots of fields. However, in this migration we only remove one
|
||||
// field. The most important part to check are a couple of the last fields. We also pick
|
||||
// extra fields to check arbitrarily, e.g. depending on their position (i.e. the middle) and
|
||||
// also their type.
|
||||
//
|
||||
@@ -291,7 +293,8 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
// Test that migration doesn't panic in case there're no pending configurations upgrades in pallet's storage.
|
||||
// Test that migration doesn't panic in case there're no pending configurations upgrades in
|
||||
// pallet's storage.
|
||||
#[test]
|
||||
fn test_migrate_to_v7_no_pending() {
|
||||
let v6 = V6HostConfiguration::<primitives::BlockNumber>::default();
|
||||
|
||||
@@ -887,8 +887,8 @@ impl<T: Config> Pallet<T> {
|
||||
#[allow(deprecated)]
|
||||
<BackersOnDisputes<T>>::remove_prefix(to_prune, None);
|
||||
|
||||
// This is larger, and will be extracted to the `shared` pallet for more proper pruning.
|
||||
// TODO: https://github.com/paritytech/polkadot/issues/3469
|
||||
// This is larger, and will be extracted to the `shared` pallet for more proper
|
||||
// pruning. TODO: https://github.com/paritytech/polkadot/issues/3469
|
||||
#[allow(deprecated)]
|
||||
<Included<T>>::remove_prefix(to_prune, None);
|
||||
}
|
||||
@@ -1178,7 +1178,8 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
<Disputes<T>>::insert(&session, &candidate_hash, &summary.state);
|
||||
|
||||
// Freeze if the INVALID votes against some local candidate are above the byzantine threshold
|
||||
// Freeze if the INVALID votes against some local candidate are above the byzantine
|
||||
// threshold
|
||||
if summary.new_flags.contains(DisputeStateFlags::AGAINST_BYZANTINE) {
|
||||
if let Some(revert_to) = <Included<T>>::get(&session, &candidate_hash) {
|
||||
Self::revert_and_freeze(revert_to);
|
||||
|
||||
@@ -79,14 +79,16 @@ pub mod v1 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrates the pallet storage to the most recent version, checking and setting the `StorageVersion`.
|
||||
/// Migrates the pallet storage to the most recent version, checking and setting the
|
||||
/// `StorageVersion`.
|
||||
pub fn migrate_to_v1<T: Config>() -> Weight {
|
||||
let mut weight: Weight = Weight::zero();
|
||||
|
||||
// SpamSlots should not contain too many keys so removing everything at once should be safe
|
||||
let res = SpamSlots::<T>::clear(u32::MAX, None);
|
||||
// `loops` is the number of iterations => used to calculate read weights
|
||||
// `backend` is the number of keys removed from the backend => used to calculate write weights
|
||||
// `backend` is the number of keys removed from the backend => used to calculate write
|
||||
// weights
|
||||
weight = weight
|
||||
.saturating_add(T::DbWeight::get().reads_writes(res.loops as u64, res.backend as u64));
|
||||
|
||||
|
||||
@@ -871,7 +871,8 @@ mod unconfirmed_disputes {
|
||||
use assert_matches::assert_matches;
|
||||
use sp_runtime::ModuleError;
|
||||
|
||||
// Shared initialization code between `test_unconfirmed_are_ignored` and `test_unconfirmed_disputes_cause_block_import_error`
|
||||
// Shared initialization code between `test_unconfirmed_are_ignored` and
|
||||
// `test_unconfirmed_disputes_cause_block_import_error`
|
||||
fn generate_dispute_statement_set_and_run_to_block() -> DisputeStatementSet {
|
||||
// 7 validators needed for byzantine threshold of 2.
|
||||
let v0 = <ValidatorId as CryptoType>::Pair::generate().0;
|
||||
@@ -2060,7 +2061,8 @@ fn deduplication_and_sorting_works() {
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
// assert ordering of local only disputes, and at the same time, and being free of duplicates
|
||||
// assert ordering of local only disputes, and at the same time, and being free of
|
||||
// duplicates
|
||||
assert_eq!(disputes_orig.len(), disputes.len() + 1);
|
||||
|
||||
let are_these_equal = |a: &DisputeStatementSet, b: &DisputeStatementSet| {
|
||||
|
||||
@@ -117,12 +117,12 @@ pub struct HrmpOpenChannelRequest {
|
||||
#[derive(Encode, Decode, TypeInfo)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct HrmpChannel {
|
||||
// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct requires
|
||||
// special treatment.
|
||||
// NOTE: This structure is used by parachains via merkle proofs. Therefore, this struct
|
||||
// requires special treatment.
|
||||
//
|
||||
// A parachain requested this struct can only depend on the subset of this struct. Specifically,
|
||||
// only a first few fields can be depended upon (See `AbridgedHrmpChannel`). These fields cannot
|
||||
// be changed without corresponding migration of parachains.
|
||||
// A parachain requested this struct can only depend on the subset of this struct.
|
||||
// Specifically, only a first few fields can be depended upon (See `AbridgedHrmpChannel`).
|
||||
// These fields cannot be changed without corresponding migration of parachains.
|
||||
/// The maximum number of messages that can be pending in the channel at once.
|
||||
pub max_capacity: u32,
|
||||
/// The maximum total size of the messages that can be pending in the channel at once.
|
||||
@@ -370,7 +370,8 @@ pub mod pallet {
|
||||
|
||||
/// The HRMP watermark associated with each para.
|
||||
/// Invariant:
|
||||
/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a session.
|
||||
/// - each para `P` used here as a key should satisfy `Paras::is_valid_para(P)` within a
|
||||
/// session.
|
||||
#[pallet::storage]
|
||||
pub type HrmpWatermarks<T: Config> = StorageMap<_, Twox64Concat, ParaId, BlockNumberFor<T>>;
|
||||
|
||||
@@ -968,9 +969,9 @@ impl<T: Config> Pallet<T> {
|
||||
out_hrmp_msgs.iter().enumerate().map(|(idx, out_msg)| (idx as u32, out_msg))
|
||||
{
|
||||
match last_recipient {
|
||||
// the messages must be sorted in ascending order and there must be no two messages sent
|
||||
// to the same recipient. Thus we can check that every recipient is strictly greater than
|
||||
// the previous one.
|
||||
// the messages must be sorted in ascending order and there must be no two messages
|
||||
// sent to the same recipient. Thus we can check that every recipient is strictly
|
||||
// greater than the previous one.
|
||||
Some(last_recipient) if out_msg.recipient <= last_recipient =>
|
||||
return Err(OutboundHrmpAcceptanceErr::NotSorted { idx }),
|
||||
_ => last_recipient = Some(out_msg.recipient),
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
//! The inclusion pallet is responsible for inclusion and availability of scheduled parachains
|
||||
//! and parathreads.
|
||||
//!
|
||||
//! It is responsible for carrying candidates from being backable to being backed, and then from backed
|
||||
//! to included.
|
||||
//! It is responsible for carrying candidates from being backable to being backed, and then from
|
||||
//! backed to included.
|
||||
|
||||
use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
@@ -76,8 +76,8 @@ impl WeightInfo for () {
|
||||
|
||||
/// Maximum value that `config.max_upward_message_size` can be set to.
|
||||
///
|
||||
/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the `configuration`
|
||||
/// pallet to check these values before setting.
|
||||
/// This is used for benchmarking sanely bounding relevant storage items. It is expected from the
|
||||
/// `configuration` pallet to check these values before setting.
|
||||
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
|
||||
@@ -354,8 +354,8 @@ pub mod pallet {
|
||||
InvalidOutboundHrmp,
|
||||
/// The validation code hash of the candidate is not valid.
|
||||
InvalidValidationCodeHash,
|
||||
/// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual para head in the
|
||||
/// commitments.
|
||||
/// The `para_head` hash in the candidate descriptor doesn't match the hash of the actual
|
||||
/// para head in the commitments.
|
||||
ParaHeadMismatch,
|
||||
/// A bitfield that references a freed core,
|
||||
/// either intentionally or as part of a concluded
|
||||
@@ -492,8 +492,8 @@ impl<T: Config> Pallet<T> {
|
||||
///
|
||||
/// Updates storage items `PendingAvailability` and `AvailabilityBitfields`.
|
||||
///
|
||||
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became available,
|
||||
/// and cores free.
|
||||
/// Returns a `Vec` of `CandidateHash`es and their respective `AvailabilityCore`s that became
|
||||
/// available, and cores free.
|
||||
pub(crate) fn update_pending_availability_and_get_freed_cores<F>(
|
||||
expected_bits: usize,
|
||||
validators: &[ValidatorId],
|
||||
@@ -530,8 +530,8 @@ impl<T: Config> Pallet<T> {
|
||||
continue
|
||||
};
|
||||
|
||||
// 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.
|
||||
// defensive check - this is constructed by loading the availability bitfield
|
||||
// record, which is always `Some` if the core is occupied - that's why we're here.
|
||||
let validator_index = validator_index.0 as usize;
|
||||
if let Some(mut bit) =
|
||||
pending_availability.as_mut().and_then(|candidate_pending_availability| {
|
||||
@@ -591,8 +591,8 @@ impl<T: Config> Pallet<T> {
|
||||
freed_cores
|
||||
}
|
||||
|
||||
/// Process candidates that have been backed. Provide the relay storage root, a set of candidates
|
||||
/// and scheduled cores.
|
||||
/// Process candidates that have been backed. Provide the relay storage root, a set of
|
||||
/// candidates and scheduled cores.
|
||||
///
|
||||
/// Both should be sorted ascending by core index, and the candidates should be a subset of
|
||||
/// scheduled cores. If these conditions are not met, the execution of the function fails.
|
||||
@@ -968,7 +968,8 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
}
|
||||
// make sure that the queue is not overfilled.
|
||||
// we do it here only once since returning false invalidates the whole relay-chain block.
|
||||
// we do it here only once since returning false invalidates the whole relay-chain
|
||||
// block.
|
||||
if para_queue_size.saturating_add(msg_size as u64) > config.max_upward_queue_size as u64
|
||||
{
|
||||
return Err(UmpAcceptanceCheckErr::TotalSizeExceeded {
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
//! This module is responsible for maintaining a consistent initialization order for all other
|
||||
//! parachains modules. It's also responsible for finalization and session change notifications.
|
||||
//!
|
||||
//! This module can throw fatal errors if session-change notifications are received after initialization.
|
||||
//! This module can throw fatal errors if session-change notifications are received after
|
||||
//! initialization.
|
||||
|
||||
use crate::{
|
||||
configuration::{self, HostConfiguration},
|
||||
@@ -128,9 +129,9 @@ pub mod pallet {
|
||||
/// Semantically a `bool`, but this guarantees it should never hit the trie,
|
||||
/// as this is cleared in `on_finalize` and Frame optimizes `None` values to be empty values.
|
||||
///
|
||||
/// As a `bool`, `set(false)` and `remove()` both lead to the next `get()` being false, but one of
|
||||
/// them writes to the trie and one does not. This confusion makes `Option<()>` more suitable for
|
||||
/// the semantics of this variable.
|
||||
/// As a `bool`, `set(false)` and `remove()` both lead to the next `get()` being false, but one
|
||||
/// of them writes to the trie and one does not. This confusion makes `Option<()>` more suitable
|
||||
/// for the semantics of this variable.
|
||||
#[pallet::storage]
|
||||
pub(super) type HasInitialized<T: Config> = StorageValue<_, ()>;
|
||||
|
||||
@@ -190,7 +191,8 @@ pub mod pallet {
|
||||
// Apply buffered session changes as the last thing. This way the runtime APIs and the
|
||||
// next block will observe the next session.
|
||||
//
|
||||
// Note that we only apply the last session as all others lasted less than a block (weirdly).
|
||||
// Note that we only apply the last session as all others lasted less than a block
|
||||
// (weirdly).
|
||||
if let Some(BufferedSessionChange { session_index, validators, queued }) =
|
||||
BufferedSessionChanges::<T>::take().pop()
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@ where
|
||||
/// belongs to.
|
||||
///
|
||||
/// This module fulfills only the single purpose of housing the `Origin` in `construct_runtime`.
|
||||
///
|
||||
// ideally, though, the `construct_runtime` should support a free-standing origin.
|
||||
#[frame_support::pallet]
|
||||
pub mod pallet {
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
//!
|
||||
//! The conditions that must be met before the para can use the new validation code are:
|
||||
//!
|
||||
//! 1. The validation code should have been "soaked" in the storage for a given number of blocks. That
|
||||
//! is, the validation code should have been stored in on-chain storage for some time, so that in
|
||||
//! case of a revert with a non-extreme height difference, that validation code can still be
|
||||
//! found on-chain.
|
||||
//! 1. The validation code should have been "soaked" in the storage for a given number of blocks.
|
||||
//! That is, the validation code should have been stored in on-chain storage for some time, so
|
||||
//! that in case of a revert with a non-extreme height difference, that validation code can still
|
||||
//! be found on-chain.
|
||||
//!
|
||||
//! 2. The validation code was vetted by the validators and declared as non-malicious in a processes
|
||||
//! known as PVF pre-checking.
|
||||
@@ -105,7 +105,6 @@
|
||||
//! start──────▶│reset│
|
||||
//! └─────┘
|
||||
//! ```
|
||||
//!
|
||||
|
||||
use crate::{
|
||||
configuration,
|
||||
@@ -152,8 +151,8 @@ pub struct ReplacementTimes<N> {
|
||||
/// first parablock included with a relay-parent with number >= this value.
|
||||
expected_at: N,
|
||||
/// The relay-chain block number at which the parablock activating the code upgrade was
|
||||
/// actually included. This means considered included and available, so this is the time at which
|
||||
/// that parablock enters the acceptance period in this fork of the relay-chain.
|
||||
/// actually included. This means considered included and available, so this is the time at
|
||||
/// which that parablock enters the acceptance period in this fork of the relay-chain.
|
||||
activated_at: N,
|
||||
}
|
||||
|
||||
@@ -332,7 +331,8 @@ impl<'de> Deserialize<'de> for ParaKind {
|
||||
}
|
||||
}
|
||||
|
||||
// Manual encoding, decoding, and TypeInfo as the parakind field in ParaGenesisArgs used to be a bool
|
||||
// Manual encoding, decoding, and TypeInfo as the parakind field in ParaGenesisArgs used to be a
|
||||
// bool
|
||||
impl Encode for ParaKind {
|
||||
fn size_hint(&self) -> usize {
|
||||
true.size_hint()
|
||||
@@ -373,12 +373,15 @@ pub(crate) enum PvfCheckCause<BlockNumber> {
|
||||
Onboarding(ParaId),
|
||||
/// PVF vote was initiated by signalling of an upgrade by the given para.
|
||||
Upgrade {
|
||||
/// The ID of the parachain that initiated or is waiting for the conclusion of pre-checking.
|
||||
/// The ID of the parachain that initiated or is waiting for the conclusion of
|
||||
/// pre-checking.
|
||||
id: ParaId,
|
||||
/// The relay-chain block number of **inclusion** of candidate that that initiated the upgrade.
|
||||
/// The relay-chain block number of **inclusion** of candidate that that initiated the
|
||||
/// upgrade.
|
||||
///
|
||||
/// It's important to count upgrade enactment delay from the inclusion of this candidate instead
|
||||
/// of its relay parent -- in order to keep PVF available in case of chain reversions.
|
||||
/// It's important to count upgrade enactment delay from the inclusion of this candidate
|
||||
/// instead of its relay parent -- in order to keep PVF available in case of chain
|
||||
/// reversions.
|
||||
///
|
||||
/// See https://github.com/paritytech/polkadot/issues/4601 for detailed explanation.
|
||||
included_at: BlockNumber,
|
||||
@@ -681,11 +684,11 @@ pub mod pallet {
|
||||
pub(super) type PastCodeMeta<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ParaPastCodeMeta<BlockNumberFor<T>>, ValueQuery>;
|
||||
|
||||
/// Which paras have past code that needs pruning and the relay-chain block at which the code was replaced.
|
||||
/// Note that this is the actual height of the included block, not the expected height at which the
|
||||
/// code upgrade would be applied, although they may be equal.
|
||||
/// This is to ensure the entire acceptance period is covered, not an offset acceptance period starting
|
||||
/// from the time at which the parachain perceives a code upgrade as having occurred.
|
||||
/// Which paras have past code that needs pruning and the relay-chain block at which the code
|
||||
/// was replaced. Note that this is the actual height of the included block, not the expected
|
||||
/// height at which the code upgrade would be applied, although they may be equal.
|
||||
/// This is to ensure the entire acceptance period is covered, not an offset acceptance period
|
||||
/// starting from the time at which the parachain perceives a code upgrade as having occurred.
|
||||
/// Multiple entries for a single para are permitted. Ordered ascending by block number.
|
||||
#[pallet::storage]
|
||||
pub(super) type PastCodePruning<T: Config> =
|
||||
@@ -706,12 +709,13 @@ pub mod pallet {
|
||||
pub(super) type FutureCodeHash<T: Config> =
|
||||
StorageMap<_, Twox64Concat, ParaId, ValidationCodeHash>;
|
||||
|
||||
/// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade procedure.
|
||||
/// This is used by the relay-chain to communicate to a parachain a go-ahead with in the upgrade
|
||||
/// procedure.
|
||||
///
|
||||
/// This value is absent when there are no upgrades scheduled or during the time the relay chain
|
||||
/// performs the checks. It is set at the first relay-chain block when the corresponding parachain
|
||||
/// can switch its upgrade function. As soon as the parachain's block is included, the value
|
||||
/// gets reset to `None`.
|
||||
/// performs the checks. It is set at the first relay-chain block when the corresponding
|
||||
/// parachain can switch its upgrade function. As soon as the parachain's block is included, the
|
||||
/// value gets reset to `None`.
|
||||
///
|
||||
/// NOTE that this field is used by parachains via merkle storage proofs, therefore changing
|
||||
/// the format will require migration of parachains.
|
||||
@@ -896,8 +900,9 @@ pub mod pallet {
|
||||
/// Otherwise, the code will be added into the storage. Note that the code will be added
|
||||
/// into storage with reference count 0. This is to account the fact that there are no users
|
||||
/// for this code yet. The caller will have to make sure that this code eventually gets
|
||||
/// used by some parachain or removed from the storage to avoid storage leaks. For the latter
|
||||
/// prefer to use the `poke_unused_validation_code` dispatchable to raw storage manipulation.
|
||||
/// used by some parachain or removed from the storage to avoid storage leaks. For the
|
||||
/// latter prefer to use the `poke_unused_validation_code` dispatchable to raw storage
|
||||
/// manipulation.
|
||||
///
|
||||
/// This function is mainly meant to be used for upgrading parachains that do not follow
|
||||
/// the go-ahead signal while the PVF pre-checking feature is enabled.
|
||||
@@ -1569,10 +1574,11 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
match cause {
|
||||
PvfCheckCause::Onboarding(id) => {
|
||||
// Here we need to undo everything that was done during `schedule_para_initialize`.
|
||||
// Essentially, the logic is similar to offboarding, with exception that before
|
||||
// actual onboarding the parachain did not have a chance to reach to upgrades.
|
||||
// Therefore we can skip all the upgrade related storage items here.
|
||||
// Here we need to undo everything that was done during
|
||||
// `schedule_para_initialize`. Essentially, the logic is similar to offboarding,
|
||||
// with exception that before actual onboarding the parachain did not have a
|
||||
// chance to reach to upgrades. Therefore we can skip all the upgrade related
|
||||
// storage items here.
|
||||
weight += T::DbWeight::get().writes(3);
|
||||
UpcomingParasGenesis::<T>::remove(&id);
|
||||
CurrentCodeHash::<T>::remove(&id);
|
||||
@@ -1629,8 +1635,8 @@ impl<T: Config> Pallet<T> {
|
||||
//
|
||||
// - Doing it within the context of the PR that introduces this change is undesirable, since
|
||||
// it is already a big change, and that change would require a migration. Moreover, if we
|
||||
// run the new version of the runtime, there will be less things to worry about during
|
||||
// the eventual proper migration.
|
||||
// run the new version of the runtime, there will be less things to worry about during the
|
||||
// eventual proper migration.
|
||||
//
|
||||
// - This data type already is used for generating genesis, and changing it will probably
|
||||
// introduce some unnecessary burden.
|
||||
@@ -1641,8 +1647,8 @@ impl<T: Config> Pallet<T> {
|
||||
// get rid of hashing of the validation code when onboarding.
|
||||
//
|
||||
// - Replace `validation_code` with a sentinel value: an empty vector. This should be fine
|
||||
// as long we do not allow registering parachains with empty code. At the moment of writing
|
||||
// this should already be the case.
|
||||
// as long we do not allow registering parachains with empty code. At the moment of
|
||||
// writing this should already be the case.
|
||||
//
|
||||
// - Empty value is treated as the current code is already inserted during the onboarding.
|
||||
//
|
||||
@@ -1670,7 +1676,8 @@ impl<T: Config> Pallet<T> {
|
||||
///
|
||||
/// Will return error if either is true:
|
||||
///
|
||||
/// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is `false`)
|
||||
/// - para is not a stable parachain or parathread (i.e. [`ParaLifecycle::is_stable`] is
|
||||
/// `false`)
|
||||
/// - para has a pending upgrade.
|
||||
/// - para has unprocessed messages in its UMP queue.
|
||||
///
|
||||
@@ -1683,7 +1690,8 @@ impl<T: Config> Pallet<T> {
|
||||
// ongoing PVF pre-checking votes. It also removes some nasty edge cases.
|
||||
//
|
||||
// However, an upcoming upgrade on its own imposes no restrictions. An upgrade is enacted
|
||||
// with a new para head, so if a para never progresses we still should be able to offboard it.
|
||||
// with a new para head, so if a para never progresses we still should be able to offboard
|
||||
// it.
|
||||
//
|
||||
// This implicitly assumes that the given para exists, i.e. it's lifecycle != None.
|
||||
if let Some(future_code_hash) = FutureCodeHash::<T>::get(&id) {
|
||||
@@ -1768,13 +1776,14 @@ impl<T: Config> Pallet<T> {
|
||||
/// the relay-chain block number will be determined at which the upgrade will take place. We
|
||||
/// call that block `expected_at`.
|
||||
///
|
||||
/// Once the candidate with the relay-parent >= `expected_at` is enacted, the new validation code
|
||||
/// will be applied. Therefore, the new code will be used to validate the next candidate.
|
||||
/// Once the candidate with the relay-parent >= `expected_at` is enacted, the new validation
|
||||
/// code will be applied. Therefore, the new code will be used to validate the next candidate.
|
||||
///
|
||||
/// The new code should not be equal to the current one, otherwise the upgrade will be aborted.
|
||||
/// If there is already a scheduled code upgrade for the para, this is a no-op.
|
||||
///
|
||||
/// Inclusion block number specifies relay parent which enacted candidate initiating the upgrade.
|
||||
/// Inclusion block number specifies relay parent which enacted candidate initiating the
|
||||
/// upgrade.
|
||||
pub(crate) fn schedule_code_upgrade(
|
||||
id: ParaId,
|
||||
new_code: ValidationCode,
|
||||
@@ -1905,8 +1914,8 @@ impl<T: Config> Pallet<T> {
|
||||
// We increase the code RC here in any case. Intuitively the parachain that requested this
|
||||
// action is now a user of that PVF.
|
||||
//
|
||||
// If the result of the pre-checking is reject, then we would decrease the RC for each cause,
|
||||
// including the current.
|
||||
// If the result of the pre-checking is reject, then we would decrease the RC for each
|
||||
// cause, including the current.
|
||||
//
|
||||
// If the result of the pre-checking is accept, then we do nothing to the RC because the PVF
|
||||
// will continue be used by the same users.
|
||||
@@ -1918,9 +1927,9 @@ impl<T: Config> Pallet<T> {
|
||||
weight
|
||||
}
|
||||
|
||||
/// Note that a para has progressed to a new head, where the new head was executed in the context
|
||||
/// of a relay-chain block with given number. This will apply pending code upgrades based
|
||||
/// on the relay-parent block number provided.
|
||||
/// Note that a para has progressed to a new head, where the new head was executed in the
|
||||
/// context of a relay-chain block with given number. This will apply pending code upgrades
|
||||
/// based on the relay-parent block number provided.
|
||||
pub(crate) fn note_new_head(
|
||||
id: ParaId,
|
||||
new_head: HeadData,
|
||||
|
||||
@@ -649,7 +649,8 @@ fn submit_code_change_when_not_allowed_is_err() {
|
||||
Paras::schedule_code_upgrade(para_id, newer_code.clone(), 2, &Configuration::config());
|
||||
assert_eq!(
|
||||
FutureCodeUpgrades::<Test>::get(¶_id),
|
||||
Some(1 + validation_upgrade_delay), // did not change since the same assertion from the last time.
|
||||
Some(1 + validation_upgrade_delay), /* did not change since the same assertion from
|
||||
* the last time. */
|
||||
);
|
||||
assert_eq!(FutureCodeHash::<Test>::get(¶_id), Some(new_code.hash()));
|
||||
check_code_is_not_stored(&newer_code);
|
||||
@@ -1554,8 +1555,9 @@ fn increase_code_ref_doesnt_have_allergy_on_add_trusted_validation_code() {
|
||||
|
||||
#[test]
|
||||
fn add_trusted_validation_code_insta_approval() {
|
||||
// In particular, this tests that `kick_off_pvf_check` reacts to the `add_trusted_validation_code`
|
||||
// and uses the `CodeByHash::contains_key` which is what `add_trusted_validation_code` uses.
|
||||
// In particular, this tests that `kick_off_pvf_check` reacts to the
|
||||
// `add_trusted_validation_code` and uses the `CodeByHash::contains_key` which is what
|
||||
// `add_trusted_validation_code` uses.
|
||||
let para_id = 100.into();
|
||||
let validation_code = ValidationCode(vec![1, 2, 3]);
|
||||
let validation_upgrade_delay = 25;
|
||||
|
||||
@@ -285,8 +285,9 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Create the `ParachainsInherentData` that gets passed to [`Self::enter`] in [`Self::create_inherent`].
|
||||
/// This code is pulled out of [`Self::create_inherent`] so it can be unit tested.
|
||||
/// Create the `ParachainsInherentData` that gets passed to [`Self::enter`] in
|
||||
/// [`Self::create_inherent`]. This code is pulled out of [`Self::create_inherent`] so it can be
|
||||
/// unit tested.
|
||||
fn create_inherent_inner(data: &InherentData) -> Option<ParachainsInherentData<HeaderFor<T>>> {
|
||||
let parachains_inherent_data = match data.get_data(&Self::INHERENT_IDENTIFIER) {
|
||||
Ok(Some(d)) => d,
|
||||
@@ -313,11 +314,11 @@ impl<T: Config> Pallet<T> {
|
||||
/// The given inherent data is processed and state is altered accordingly. If any data could
|
||||
/// not be applied (inconsitencies, weight limit, ...) it is removed.
|
||||
///
|
||||
/// When called from `create_inherent` the `context` must be set to `ProcessInherentDataContext::ProvideInherent`
|
||||
/// so it guarantees the invariant that inherent is not overweight.
|
||||
///
|
||||
/// It is **mandatory** that calls from `enter` set `context` to `ProcessInherentDataContext::Enter` to ensure
|
||||
/// the weight invariant is checked.
|
||||
/// When called from `create_inherent` the `context` must be set to
|
||||
/// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent
|
||||
/// is not overweight.
|
||||
/// It is **mandatory** that calls from `enter` set `context` to
|
||||
/// `ProcessInherentDataContext::Enter` to ensure the weight invariant is checked.
|
||||
///
|
||||
/// Returns: Result containing processed inherent data and weight, the processed inherent would
|
||||
/// consume.
|
||||
@@ -379,8 +380,8 @@ impl<T: Config> Pallet<T> {
|
||||
let dispatch_class = DispatchClass::Mandatory;
|
||||
let max_block_weight_full = <T as frame_system::Config>::BlockWeights::get();
|
||||
log::debug!(target: LOG_TARGET, "Max block weight: {}", max_block_weight_full.max_block);
|
||||
// Get max block weight for the mandatory class if defined, otherwise total max weight of
|
||||
// the block.
|
||||
// Get max block weight for the mandatory class if defined, otherwise total max weight
|
||||
// of the block.
|
||||
let max_weight = max_block_weight_full
|
||||
.per_class
|
||||
.get(dispatch_class)
|
||||
@@ -412,7 +413,8 @@ impl<T: Config> Pallet<T> {
|
||||
T::DisputesHandler::filter_dispute_data(set, post_conclusion_acceptance_period)
|
||||
};
|
||||
|
||||
// Limit the disputes first, since the following statements depend on the votes include here.
|
||||
// Limit the disputes first, since the following statements depend on the votes include
|
||||
// here.
|
||||
let (checked_disputes_sets, checked_disputes_sets_consumed_weight) =
|
||||
limit_and_sanitize_disputes::<T, _>(
|
||||
disputes,
|
||||
@@ -449,8 +451,8 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
all_weight_after
|
||||
} else {
|
||||
// This check is performed in the context of block execution. Ensures inherent weight invariants guaranteed
|
||||
// by `create_inherent_data` for block authorship.
|
||||
// This check is performed in the context of block execution. Ensures inherent weight
|
||||
// invariants guaranteed by `create_inherent_data` for block authorship.
|
||||
if all_weight_before.any_gt(max_block_weight) {
|
||||
log::error!(
|
||||
"Overweight para inherent data reached the runtime {:?}: {} > {}",
|
||||
@@ -714,13 +716,14 @@ fn random_sel<X, F: Fn(&X) -> Weight>(
|
||||
/// If there is sufficient space, all bitfields and all candidates
|
||||
/// will be included.
|
||||
///
|
||||
/// Otherwise tries to include all disputes, and then tries to fill the remaining space with bitfields and then candidates.
|
||||
/// Otherwise tries to include all disputes, and then tries to fill the remaining space with
|
||||
/// bitfields and then candidates.
|
||||
///
|
||||
/// The selection process is random. For candidates, there is an exception for code upgrades as they are preferred.
|
||||
/// And for disputes, local and older disputes are preferred (see `limit_and_sanitize_disputes`).
|
||||
/// for backed candidates, since with a increasing number of parachains their chances of
|
||||
/// inclusion become slim. All backed candidates are checked beforehands in `fn create_inherent_inner`
|
||||
/// which guarantees sanity.
|
||||
/// The selection process is random. For candidates, there is an exception for code upgrades as they
|
||||
/// are preferred. And for disputes, local and older disputes are preferred (see
|
||||
/// `limit_and_sanitize_disputes`). for backed candidates, since with a increasing number of
|
||||
/// parachains their chances of inclusion become slim. All backed candidates are checked
|
||||
/// beforehands in `fn create_inherent_inner` which guarantees sanity.
|
||||
///
|
||||
/// Assumes disputes are already filtered by the time this is called.
|
||||
///
|
||||
@@ -977,7 +980,8 @@ fn compute_entropy<T: Config>(parent_hash: T::Hash) -> [u8; 32] {
|
||||
/// 1. If weight is exceeded by locals, pick the older ones (lower indices)
|
||||
/// until the weight limit is reached.
|
||||
///
|
||||
/// Returns the consumed weight amount, that is guaranteed to be less than the provided `max_consumable_weight`.
|
||||
/// Returns the consumed weight amount, that is guaranteed to be less than the provided
|
||||
/// `max_consumable_weight`.
|
||||
fn limit_and_sanitize_disputes<
|
||||
T: Config,
|
||||
CheckValidityFn: FnMut(DisputeStatementSet) -> Option<CheckedDisputeStatementSet>,
|
||||
|
||||
@@ -68,9 +68,9 @@ mod enter {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Validate that if we create 2 backed candidates which are assigned to 2 cores that will be freed via
|
||||
// becoming fully available, the backed candidates will not be filtered out in `create_inherent` and
|
||||
// will not cause `enter` to early.
|
||||
// Validate that if we create 2 backed candidates which are assigned to 2 cores that will be
|
||||
// freed via becoming fully available, the backed candidates will not be filtered out in
|
||||
// `create_inherent` and will not cause `enter` to early.
|
||||
fn include_backed_candidates() {
|
||||
new_test_ext(MockGenesisConfig::default()).execute_with(|| {
|
||||
let dispute_statements = BTreeMap::new();
|
||||
@@ -252,7 +252,8 @@ mod enter {
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 3 disputes => 3 cores, 15 validators)
|
||||
// * 1 bitfield per validator (5 validators per core, 3 disputes => 3 cores, 15
|
||||
// validators)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 15);
|
||||
// * 0 backed candidate per core
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 0);
|
||||
@@ -389,7 +390,8 @@ mod enter {
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (4 validators per core, 2 backed candidates, 3 disputes => 4*5 = 20)
|
||||
// * 1 bitfield per validator (4 validators per core, 2 backed candidates, 3 disputes =>
|
||||
// 4*5 = 20)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 20);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
@@ -408,7 +410,8 @@ mod enter {
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
assert!(limit_inherent_data != expected_para_inherent_data);
|
||||
|
||||
// Three disputes is over weight (see previous test), so we expect to only see 2 disputes
|
||||
// Three disputes is over weight (see previous test), so we expect to only see 2
|
||||
// disputes
|
||||
assert_eq!(limit_inherent_data.disputes.len(), 2);
|
||||
// Ensure disputes are filtered as expected
|
||||
assert_eq!(limit_inherent_data.disputes[0].session, 1);
|
||||
@@ -418,7 +421,8 @@ mod enter {
|
||||
limit_inherent_data.bitfields.len(),
|
||||
expected_para_inherent_data.bitfields.len()
|
||||
);
|
||||
// Ensure that all backed candidates are filtered out as either would make the block over weight
|
||||
// Ensure that all backed candidates are filtered out as either would make the block
|
||||
// over weight
|
||||
assert_eq!(limit_inherent_data.backed_candidates.len(), 0);
|
||||
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
@@ -470,7 +474,8 @@ mod enter {
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 4*5 = 20),
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes =>
|
||||
// 4*5 = 20),
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 25);
|
||||
// * 2 backed candidates,
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
@@ -493,14 +498,16 @@ mod enter {
|
||||
assert!(inherent_data_weight(&limit_inherent_data)
|
||||
.all_lte(max_block_weight_proof_size_adjusted()));
|
||||
|
||||
// Three disputes is over weight (see previous test), so we expect to only see 2 disputes
|
||||
// Three disputes is over weight (see previous test), so we expect to only see 2
|
||||
// disputes
|
||||
assert_eq!(limit_inherent_data.disputes.len(), 2);
|
||||
// Ensure disputes are filtered as expected
|
||||
assert_eq!(limit_inherent_data.disputes[0].session, 1);
|
||||
assert_eq!(limit_inherent_data.disputes[1].session, 2);
|
||||
// Ensure all bitfields are included as these are still not over weight
|
||||
assert_eq!(limit_inherent_data.bitfields.len(), 20,);
|
||||
// Ensure that all backed candidates are filtered out as either would make the block over weight
|
||||
// Ensure that all backed candidates are filtered out as either would make the block
|
||||
// over weight
|
||||
assert_eq!(limit_inherent_data.backed_candidates.len(), 0);
|
||||
|
||||
assert_ok!(Pallet::<Test>::enter(
|
||||
@@ -551,7 +558,8 @@ mod enter {
|
||||
let expected_para_inherent_data = scenario.data.clone();
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 5*5 = 25)
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes =>
|
||||
// 5*5 = 25)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 25);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
@@ -632,7 +640,8 @@ mod enter {
|
||||
.any_lt(inherent_data_weight(&expected_para_inherent_data)));
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes => 5*5 = 25)
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 3 disputes =>
|
||||
// 5*5 = 25)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 25);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
@@ -645,7 +654,8 @@ mod enter {
|
||||
|
||||
let limit_inherent_data =
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2
|
||||
// disputes
|
||||
assert!(limit_inherent_data != expected_para_inherent_data);
|
||||
assert!(
|
||||
max_block_weight_proof_size_adjusted()
|
||||
@@ -727,7 +737,8 @@ mod enter {
|
||||
.unwrap();
|
||||
let limit_inherent_data =
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2
|
||||
// disputes
|
||||
assert!(limit_inherent_data != expected_para_inherent_data);
|
||||
assert!(
|
||||
max_block_weight_proof_size_adjusted()
|
||||
@@ -792,7 +803,8 @@ mod enter {
|
||||
|
||||
let limit_inherent_data =
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2
|
||||
// disputes
|
||||
assert!(limit_inherent_data != expected_para_inherent_data);
|
||||
assert!(
|
||||
max_block_weight_proof_size_adjusted()
|
||||
@@ -841,7 +853,8 @@ mod enter {
|
||||
.any_lt(inherent_data_weight(&expected_para_inherent_data)));
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 0 disputes => 2*5 = 10)
|
||||
// * 1 bitfield per validator (5 validators per core, 2 backed candidates, 0 disputes =>
|
||||
// 2*5 = 10)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 10);
|
||||
// * 2 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 2);
|
||||
@@ -854,7 +867,8 @@ mod enter {
|
||||
|
||||
let limit_inherent_data =
|
||||
Pallet::<Test>::create_inherent_inner(&inherent_data.clone()).unwrap();
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2 disputes
|
||||
// Expect that inherent data is filtered to include only 1 backed candidate and 2
|
||||
// disputes
|
||||
assert!(limit_inherent_data != expected_para_inherent_data);
|
||||
assert!(
|
||||
max_block_weight_proof_size_adjusted()
|
||||
@@ -903,7 +917,8 @@ mod enter {
|
||||
.any_lt(inherent_data_weight(&expected_para_inherent_data)));
|
||||
|
||||
// Check the para inherent data is as expected:
|
||||
// * 1 bitfield per validator (5 validators per core, 30 backed candidates, 3 disputes => 5*33 = 165)
|
||||
// * 1 bitfield per validator (5 validators per core, 30 backed candidates, 3 disputes
|
||||
// => 5*33 = 165)
|
||||
assert_eq!(expected_para_inherent_data.bitfields.len(), 165);
|
||||
// * 30 backed candidates
|
||||
assert_eq!(expected_para_inherent_data.backed_candidates.len(), 30);
|
||||
|
||||
@@ -393,7 +393,8 @@ pub fn pvfs_require_precheck<T: paras::Config>() -> Vec<ValidationCodeHash> {
|
||||
<paras::Pallet<T>>::pvfs_require_precheck()
|
||||
}
|
||||
|
||||
/// Returns the validation code hash for the given parachain making the given `OccupiedCoreAssumption`.
|
||||
/// Returns the validation code hash for the given parachain making the given
|
||||
/// `OccupiedCoreAssumption`.
|
||||
pub fn validation_code_hash<T>(
|
||||
para_id: ParaId,
|
||||
assumption: OccupiedCoreAssumption,
|
||||
|
||||
@@ -21,19 +21,20 @@
|
||||
//! - Scheduling parachains and parathreads
|
||||
//!
|
||||
//! It aims to achieve these tasks with these goals in mind:
|
||||
//! - It should be possible to know at least a block ahead-of-time, ideally more,
|
||||
//! which validators are going to be assigned to which parachains.
|
||||
//! - Parachains that have a candidate pending availability in this fork of the chain
|
||||
//! should not be assigned.
|
||||
//! - It should be possible to know at least a block ahead-of-time, ideally more, which validators
|
||||
//! are going to be assigned to which parachains.
|
||||
//! - Parachains that have a candidate pending availability in this fork of the chain should not be
|
||||
//! assigned.
|
||||
//! - Validator assignments should not be gameable. Malicious cartels should not be able to
|
||||
//! manipulate the scheduler to assign themselves as desired.
|
||||
//! - High or close to optimal throughput of parachains and parathreads. Work among validator groups should be balanced.
|
||||
//! - High or close to optimal throughput of parachains and parathreads. Work among validator groups
|
||||
//! should be balanced.
|
||||
//!
|
||||
//! The Scheduler manages resource allocation using the concept of "Availability Cores".
|
||||
//! There will be one availability core for each parachain, and a fixed number of cores
|
||||
//! used for multiplexing parathreads. Validators will be partitioned into groups, with the same
|
||||
//! number of groups as availability cores. Validator groups will be assigned to different availability cores
|
||||
//! over time.
|
||||
//! number of groups as availability cores. Validator groups will be assigned to different
|
||||
//! availability cores over time.
|
||||
|
||||
use frame_support::pallet_prelude::*;
|
||||
use frame_system::pallet_prelude::BlockNumberFor;
|
||||
@@ -169,8 +170,9 @@ pub mod pallet {
|
||||
/// broader set of Polkadot validators, but instead just the subset used for parachains during
|
||||
/// this session.
|
||||
///
|
||||
/// Bound: The number of cores is the sum of the numbers of parachains and parathread multiplexers.
|
||||
/// Reasonably, 100-1000. The dominant factor is the number of validators: safe upper bound at 10k.
|
||||
/// Bound: The number of cores is the sum of the numbers of parachains and parathread
|
||||
/// multiplexers. Reasonably, 100-1000. The dominant factor is the number of validators: safe
|
||||
/// upper bound at 10k.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn validator_groups)]
|
||||
pub(crate) type ValidatorGroups<T> = StorageValue<_, Vec<Vec<ValidatorIndex>>, ValueQuery>;
|
||||
@@ -182,8 +184,8 @@ pub mod pallet {
|
||||
#[pallet::storage]
|
||||
pub(crate) type ParathreadQueue<T> = StorageValue<_, ParathreadClaimQueue, ValueQuery>;
|
||||
|
||||
/// One entry for each availability core. Entries are `None` if the core is not currently occupied. Can be
|
||||
/// temporarily `Some` if scheduled but not occupied.
|
||||
/// One entry for each availability core. Entries are `None` if the core is not currently
|
||||
/// occupied. Can be temporarily `Some` if scheduled but not occupied.
|
||||
/// The i'th parachain belongs to the i'th core, with the remaining cores all being
|
||||
/// parathread-multiplexers.
|
||||
///
|
||||
@@ -197,11 +199,13 @@ pub mod pallet {
|
||||
/// An index used to ensure that only one claim on a parathread exists in the queue or is
|
||||
/// currently being handled by an occupied core.
|
||||
///
|
||||
/// Bounded by the number of parathread cores and scheduling lookahead. Reasonably, 10 * 50 = 500.
|
||||
/// Bounded by the number of parathread cores and scheduling lookahead. Reasonably, 10 * 50 =
|
||||
/// 500.
|
||||
#[pallet::storage]
|
||||
pub(crate) type ParathreadClaimIndex<T> = StorageValue<_, Vec<ParaId>, ValueQuery>;
|
||||
|
||||
/// The block number where the session start occurred. Used to track how many group rotations have occurred.
|
||||
/// The block number where the session start occurred. Used to track how many group rotations
|
||||
/// have occurred.
|
||||
///
|
||||
/// Note that in the context of parachains modules the session change is signaled during
|
||||
/// the block and enacted at the end of the block (at the finalization stage, to be exact).
|
||||
@@ -215,8 +219,8 @@ pub mod pallet {
|
||||
///
|
||||
/// Bounded by the number of cores: one for each parachain and parathread multiplexer.
|
||||
///
|
||||
/// The value contained here will not be valid after the end of a block. Runtime APIs should be used to determine scheduled cores/
|
||||
/// for the upcoming block.
|
||||
/// The value contained here will not be valid after the end of a block. Runtime APIs should be
|
||||
/// used to determine scheduled cores/ for the upcoming block.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn scheduled)]
|
||||
pub(crate) type Scheduled<T> = StorageValue<_, Vec<CoreAssignment>, ValueQuery>;
|
||||
@@ -380,8 +384,9 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Free unassigned cores. Provide a list of cores that should be considered newly-freed along with the reason
|
||||
/// for them being freed. The list is assumed to be sorted in ascending order by core index.
|
||||
/// Free unassigned cores. Provide a list of cores that should be considered newly-freed along
|
||||
/// with the reason for them being freed. The list is assumed to be sorted in ascending order by
|
||||
/// core index.
|
||||
pub(crate) fn free_cores(just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>) {
|
||||
let config = <configuration::Pallet<T>>::config();
|
||||
|
||||
@@ -403,8 +408,8 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
},
|
||||
FreedReason::TimedOut => {
|
||||
// If a parathread candidate times out, it's not the collator's fault,
|
||||
// so we don't increment retries.
|
||||
// If a parathread candidate times out, it's not the collator's
|
||||
// fault, so we don't increment retries.
|
||||
ParathreadQueue::<T>::mutate(|queue| {
|
||||
queue.enqueue_entry(entry, config.parathread_cores);
|
||||
})
|
||||
@@ -417,9 +422,9 @@ impl<T: Config> Pallet<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Schedule all unassigned cores, where possible. Provide a list of cores that should be considered
|
||||
/// newly-freed along with the reason for them being freed. The list is assumed to be sorted in
|
||||
/// ascending order by core index.
|
||||
/// Schedule all unassigned cores, where possible. Provide a list of cores that should be
|
||||
/// considered newly-freed along with the reason for them being freed. The list is assumed to be
|
||||
/// sorted in ascending order by core index.
|
||||
pub(crate) fn schedule(
|
||||
just_freed_cores: impl IntoIterator<Item = (CoreIndex, FreedReason)>,
|
||||
now: BlockNumberFor<T>,
|
||||
@@ -455,10 +460,10 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
// check the first entry already scheduled with core index >= than the one we
|
||||
// are looking at. 3 cases:
|
||||
// 1. No such entry, clearly this core is not scheduled, so we need to schedule and put at the end.
|
||||
// 2. Entry exists and has same index as the core we are inspecting. do not schedule again.
|
||||
// 3. Entry exists and has higher index than the core we are inspecting. schedule and note
|
||||
// insertion position.
|
||||
// 1. No such entry, clearly this core is not scheduled, so we need to schedule
|
||||
// and put at the end. 2. Entry exists and has same index as the core we are
|
||||
// inspecting. do not schedule again. 3. Entry exists and has higher index than
|
||||
// the core we are inspecting. schedule and note insertion position.
|
||||
prev_scheduled_in_order.peek().map_or(
|
||||
Some(scheduled.len()),
|
||||
|(idx_in_scheduled, assign)| {
|
||||
@@ -509,8 +514,9 @@ impl<T: Config> Pallet<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, because `Scheduled` is guaranteed to be sorted and we navigated unassigned
|
||||
// core indices in ascending order, we can enact the updates prepared by the previous actions.
|
||||
// at this point, because `Scheduled` is guaranteed to be sorted and we navigated
|
||||
// unassigned core indices in ascending order, we can enact the updates prepared by the
|
||||
// previous actions.
|
||||
//
|
||||
// while inserting, we have to account for the amount of insertions already done.
|
||||
//
|
||||
@@ -522,20 +528,20 @@ impl<T: Config> Pallet<T> {
|
||||
scheduled.insert(insert_at, to_insert);
|
||||
}
|
||||
|
||||
// scheduled is guaranteed to be sorted after this point because it was sorted before, and we
|
||||
// applied sorted updates at their correct positions, accounting for the offsets of previous
|
||||
// insertions.
|
||||
// scheduled is guaranteed to be sorted after this point because it was sorted before,
|
||||
// and we applied sorted updates at their correct positions, accounting for the offsets
|
||||
// of previous insertions.
|
||||
}
|
||||
|
||||
Scheduled::<T>::set(scheduled);
|
||||
ParathreadQueue::<T>::set(parathread_queue);
|
||||
}
|
||||
|
||||
/// Note that the given cores have become occupied. Behavior undefined if any of the given cores were not scheduled
|
||||
/// or the slice is not sorted ascending by core index.
|
||||
/// Note that the given cores have become occupied. Behavior undefined if any of the given cores
|
||||
/// were not scheduled or the slice is not sorted ascending by core index.
|
||||
///
|
||||
/// Complexity: O(n) in the number of scheduled cores, which is capped at the number of total cores.
|
||||
/// This is efficient in the case that most scheduled cores are occupied.
|
||||
/// Complexity: O(n) in the number of scheduled cores, which is capped at the number of total
|
||||
/// cores. This is efficient in the case that most scheduled cores are occupied.
|
||||
pub(crate) fn occupied(now_occupied: &[CoreIndex]) {
|
||||
if now_occupied.is_empty() {
|
||||
return
|
||||
@@ -568,8 +574,8 @@ impl<T: Config> Pallet<T> {
|
||||
AvailabilityCores::<T>::set(availability_cores);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// 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).and_then(|c| c.as_ref()) {
|
||||
@@ -587,8 +593,9 @@ impl<T: Config> Pallet<T> {
|
||||
ValidatorGroups::<T>::get().get(group_index.0 as usize).map(|g| g.clone())
|
||||
}
|
||||
|
||||
/// Get the group assigned to a specific core by index at the current block number. Result undefined if the core index is unknown
|
||||
/// or the block number is less than the session start index.
|
||||
/// Get the group assigned to a specific core by index at the current block number. Result
|
||||
/// undefined if the core index is unknown or the block number is less than the session start
|
||||
/// index.
|
||||
pub(crate) fn group_assigned_to_core(
|
||||
core: CoreIndex,
|
||||
at: BlockNumberFor<T>,
|
||||
@@ -622,10 +629,11 @@ impl<T: Config> Pallet<T> {
|
||||
|
||||
/// Returns an optional 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 the
|
||||
/// block number since which it has been occupied, and the respective parachain and parathread
|
||||
/// timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)`
|
||||
/// of the last rotation would this return `Some`, unless there are no rotations.
|
||||
/// If `None`, no timing-out should be done. The predicate accepts the index of the core, and
|
||||
/// the block number since which it has been occupied, and the respective parachain and
|
||||
/// parathread timeouts, i.e. only within `max(config.chain_availability_period,
|
||||
/// config.thread_availability_period)` of the last rotation would this return `Some`, unless
|
||||
/// there are no rotations.
|
||||
///
|
||||
/// This really should not be a box, but is working around a compiler limitation filed here:
|
||||
/// https://github.com/rust-lang/rust/issues/73226
|
||||
|
||||
@@ -56,7 +56,8 @@ fn run_to_block(
|
||||
|
||||
if let Some(notification) = new_session(b + 1) {
|
||||
let mut notification_with_session_index = notification;
|
||||
// We will make every session change trigger an action queue. Normally this may require 2 or more session changes.
|
||||
// We will make every session change trigger an action queue. Normally this may require
|
||||
// 2 or more session changes.
|
||||
if notification_with_session_index.session_index == SessionIndex::default() {
|
||||
notification_with_session_index.session_index = ParasShared::scheduled_session();
|
||||
}
|
||||
@@ -104,8 +105,9 @@ fn default_config() -> HostConfiguration<BlockNumber> {
|
||||
scheduling_lookahead: 2,
|
||||
parathread_retries: 1,
|
||||
// This field does not affect anything that scheduler does. However, `HostConfiguration`
|
||||
// is still a subject to consistency test. It requires that `minimum_validation_upgrade_delay`
|
||||
// is greater than `chain_availability_period` and `thread_availability_period`.
|
||||
// is still a subject to consistency test. It requires that
|
||||
// `minimum_validation_upgrade_delay` is greater than `chain_availability_period` and
|
||||
// `thread_availability_period`.
|
||||
minimum_validation_upgrade_delay: 6,
|
||||
..Default::default()
|
||||
}
|
||||
@@ -626,9 +628,9 @@ fn schedule_schedules_including_just_freed() {
|
||||
assert!(Scheduler::scheduled().is_empty());
|
||||
}
|
||||
|
||||
// add a couple more parathread claims - the claim on `b` will go to the 3rd parathread core (4)
|
||||
// and the claim on `d` will go back to the 1st parathread core (2). The claim on `e` then
|
||||
// will go for core `3`.
|
||||
// add a couple more parathread claims - the claim on `b` will go to the 3rd parathread core
|
||||
// (4) and the claim on `d` will go back to the 1st parathread core (2). The claim on `e`
|
||||
// then will go for core `3`.
|
||||
Scheduler::add_parathread_claim(ParathreadClaim(thread_b, collator.clone()));
|
||||
Scheduler::add_parathread_claim(ParathreadClaim(thread_d, collator.clone()));
|
||||
Scheduler::add_parathread_claim(ParathreadClaim(thread_e, collator.clone()));
|
||||
|
||||
@@ -62,8 +62,8 @@ pub mod pallet {
|
||||
pub(super) type ActiveValidatorIndices<T: Config> =
|
||||
StorageValue<_, Vec<ValidatorIndex>, ValueQuery>;
|
||||
|
||||
/// The parachain attestation keys of the validators actively participating in parachain consensus.
|
||||
/// This should be the same length as `ActiveValidatorIndices`.
|
||||
/// The parachain attestation keys of the validators actively participating in parachain
|
||||
/// consensus. This should be the same length as `ActiveValidatorIndices`.
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn active_validator_keys)]
|
||||
pub(super) type ActiveValidatorKeys<T: Config> = StorageValue<_, Vec<ValidatorId>, ValueQuery>;
|
||||
|
||||
@@ -48,7 +48,7 @@ pub fn make_persisted_validation_data<T: paras::Config + hrmp::Config>(
|
||||
/// the order of the `active` vec, the second item will contain the rest, in the original order.
|
||||
///
|
||||
/// ```ignore
|
||||
/// split_active_subset(active, all).0 == take_active_subset(active, all)
|
||||
/// split_active_subset(active, all).0 == take_active_subset(active, all)
|
||||
/// ```
|
||||
pub fn split_active_subset<T: Clone>(active: &[ValidatorIndex], all: &[T]) -> (Vec<T>, Vec<T>) {
|
||||
let active_set: BTreeSet<_> = active.iter().cloned().collect();
|
||||
@@ -76,7 +76,7 @@ pub fn split_active_subset<T: Clone>(active: &[ValidatorIndex], all: &[T]) -> (V
|
||||
/// Uses `split_active_subset` and concatenates the inactive to the active vec.
|
||||
///
|
||||
/// ```ignore
|
||||
/// split_active_subset(active, all)[0..active.len()]) == take_active_subset(active, all)
|
||||
/// split_active_subset(active, all)[0..active.len()]) == take_active_subset(active, all)
|
||||
/// ```
|
||||
pub fn take_active_subset_and_inactive<T: Clone>(active: &[ValidatorIndex], all: &[T]) -> Vec<T> {
|
||||
let (mut a, mut i) = split_active_subset(active, all);
|
||||
|
||||
Reference in New Issue
Block a user