// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see .
//! `V9` Primitives.
use alloc::{
collections::{BTreeMap, BTreeSet, VecDeque},
vec,
vec::{IntoIter, Vec},
};
use bitvec::{field::BitField, prelude::*, slice::BitSlice};
use codec::{Decode, DecodeWithMemTracking, Encode};
use scale_info::TypeInfo;
use core::{
marker::PhantomData,
slice::{Iter, IterMut},
};
use pezsp_application_crypto::{ByteArray, KeyTypeId};
use pezsp_arithmetic::{
traits::{BaseArithmetic, Saturating},
Perbill,
};
use bounded_collections::BoundedVec;
use pezsp_core::{ConstU32, RuntimeDebug};
use pezsp_inherents::InherentIdentifier;
use serde::{Deserialize, Serialize};
// ==========
// PUBLIC RE-EXPORTS
// ==========
pub use pezsp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
pub use pezsp_consensus_slots::Slot;
pub use pezsp_runtime::traits::{AppVerify, BlakeTwo256, Hash as HashT, Header as HeaderT};
pub use pezsp_staking::SessionIndex;
// Export some core primitives.
pub use pezkuwi_core_primitives::v2::{
AccountId, AccountIndex, AccountPublic, Balance, Block, BlockId, BlockNumber, CandidateHash,
ChainId, DownwardMessage, Hash, Header, InboundDownwardMessage, InboundHrmpMessage, Moment,
Nonce, OutboundHrmpMessage, Remark, Signature, UncheckedExtrinsic,
};
// Export some pezkuwi-teyrchain primitives
pub use pezkuwi_teyrchain_primitives::primitives::{
HeadData, HorizontalMessages, HrmpChannelId, Id, Id as ParaId, UpwardMessage, UpwardMessages,
ValidationCode, ValidationCodeHash, LOWEST_PUBLIC_ID,
};
/// Signed data.
mod signed;
pub use signed::{EncodeAs, Signed, UncheckedSigned};
pub mod async_backing;
pub mod executor_params;
pub mod slashing;
pub use async_backing::AsyncBackingParams;
pub use executor_params::{
ExecutorParam, ExecutorParamError, ExecutorParams, ExecutorParamsHash, ExecutorParamsPrepHash,
};
mod metrics;
pub use metrics::{
metric_definitions, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues,
RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate,
};
/// The key type ID for a collator key.
pub const COLLATOR_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"coll");
const LOG_TARGET: &str = "runtime::primitives";
mod collator_app {
use pezsp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::COLLATOR_KEY_TYPE_ID);
}
/// Identity that collators use.
pub type CollatorId = collator_app::Public;
/// A Teyrchain collator keypair.
#[cfg(feature = "std")]
pub type CollatorPair = collator_app::Pair;
/// Signature on candidate's block data by a collator.
pub type CollatorSignature = collator_app::Signature;
/// The key type ID for a teyrchain validator key.
pub const TEYRCHAIN_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"para");
mod validator_app {
use pezsp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::TEYRCHAIN_KEY_TYPE_ID);
}
/// Identity that teyrchain validators use when signing validation messages.
///
/// For now we assert that teyrchain validator set is exactly equivalent to the authority set, and
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
pub type ValidatorId = validator_app::Public;
/// Trait required for type specific indices e.g. `ValidatorIndex` and `GroupIndex`
pub trait TypeIndex {
/// Returns the index associated to this value.
fn type_index(&self) -> usize;
}
/// Index of the validator is used as a lightweight replacement of the `ValidatorId` when
/// appropriate.
#[derive(
Eq,
Ord,
PartialEq,
PartialOrd,
Copy,
Clone,
Encode,
Decode,
DecodeWithMemTracking,
TypeInfo,
RuntimeDebug,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
pub struct ValidatorIndex(pub u32);
/// Index of an availability chunk.
///
/// The underlying type is identical to `ValidatorIndex`, because
/// the number of chunks will always be equal to the number of validators.
/// However, the chunk index held by a validator may not always be equal to its `ValidatorIndex`, so
/// we use a separate type to make code easier to read.
#[derive(Eq, Ord, PartialEq, PartialOrd, Copy, Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))]
pub struct ChunkIndex(pub u32);
impl From for ValidatorIndex {
fn from(c_index: ChunkIndex) -> Self {
ValidatorIndex(c_index.0)
}
}
impl From for ChunkIndex {
fn from(v_index: ValidatorIndex) -> Self {
ChunkIndex(v_index.0)
}
}
impl From for ChunkIndex {
fn from(n: u32) -> Self {
ChunkIndex(n)
}
}
// We should really get https://github.com/pezkuwichain/pezkuwi-sdk/issues/278 going ..
impl From for ValidatorIndex {
fn from(n: u32) -> Self {
ValidatorIndex(n)
}
}
impl TypeIndex for ValidatorIndex {
fn type_index(&self) -> usize {
self.0 as usize
}
}
pezsp_application_crypto::with_pair! {
/// A Teyrchain validator keypair.
pub type ValidatorPair = validator_app::Pair;
}
/// Signature with which teyrchain validators sign blocks.
///
/// For now we assert that teyrchain validator set is exactly equivalent to the authority set, and
/// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
pub type ValidatorSignature = validator_app::Signature;
/// A declarations of storage keys where an external observer can find some interesting data.
pub mod well_known_keys {
use super::{HrmpChannelId, Id, WellKnownKey};
use alloc::vec::Vec;
use codec::Encode as _;
use hex_literal::hex;
use pezsp_io::hashing::twox_64;
// A note on generating these magic values below:
//
// The `StorageValue`, such as `ACTIVE_CONFIG` was obtained by calling:
//
// ActiveConfig::::hashed_key()
//
// The `StorageMap` values require `prefix`, and for example for `hrmp_egress_channel_index`,
// it could be obtained like:
//
// HrmpEgressChannelsIndex::::prefix_hash();
//
/// The current epoch index.
///
/// The storage item should be access as a `u64` encoded value.
pub const EPOCH_INDEX: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087f38316cbf8fa0da822a20ac1c55bf1be3"];
/// The current relay chain block randomness
///
/// The storage item should be accessed as a `schnorrkel::Randomness` encoded value.
pub const CURRENT_BLOCK_RANDOMNESS: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087fd077dfdb8adb10f78f10a5df8742c545"];
/// The randomness for one epoch ago
///
/// The storage item should be accessed as a `schnorrkel::Randomness` encoded value.
pub const ONE_EPOCH_AGO_RANDOMNESS: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087f7ce678799d3eff024253b90e84927cc6"];
/// The randomness for two epochs ago
///
/// The storage item should be accessed as a `schnorrkel::Randomness` encoded value.
pub const TWO_EPOCHS_AGO_RANDOMNESS: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087f7a414cb008e0e61e46722aa60abdd672"];
/// The current slot number.
///
/// The storage entry should be accessed as a `Slot` encoded value.
pub const CURRENT_SLOT: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087f06155b3cd9a8c9e5e9a23fd5dc13a5ed"];
/// The currently active host configuration.
///
/// The storage entry should be accessed as an `AbridgedHostConfiguration` encoded value.
pub const ACTIVE_CONFIG: &[u8] =
&hex!["06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385"];
/// The authorities for the current epoch.
///
/// The storage entry should be accessed as an `Vec<(AuthorityId, BabeAuthorityWeight)>` encoded
/// value.
pub const AUTHORITIES: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d"];
/// The authorities for the next epoch.
///
/// The storage entry should be accessed as an `Vec<(AuthorityId, BabeAuthorityWeight)>` encoded
/// value.
pub const NEXT_AUTHORITIES: &[u8] =
&hex!["1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c"];
/// Hash of the committed head data for a given registered para.
///
/// The storage entry stores wrapped `HeadData(Vec)`.
pub fn para_head(para_id: Id) -> Vec {
let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1941b3c252fcb29d88eff4f3de5de4476c3"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// The upward message dispatch queue for the given para id.
///
/// The storage entry stores a tuple of two values:
///
/// - `count: u32`, the number of messages currently in the queue for given para,
/// - `total_size: u32`, the total size of all messages in the queue.
#[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
pub fn relay_dispatch_queue_size(para_id: Id) -> Vec {
let prefix = hex!["f5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// Type safe version of `relay_dispatch_queue_size`.
#[deprecated = "Use `relay_dispatch_queue_remaining_capacity` instead"]
pub fn relay_dispatch_queue_size_typed(para: Id) -> WellKnownKey<(u32, u32)> {
#[allow(deprecated)]
relay_dispatch_queue_size(para).into()
}
/// The upward message dispatch queue remaining capacity for the given para id.
///
/// The storage entry stores a tuple of two values:
///
/// - `count: u32`, the number of additional messages which may be enqueued for the given para,
/// - `total_size: u32`, the total size of additional messages which may be enqueued for the
/// given para.
pub fn relay_dispatch_queue_remaining_capacity(para_id: Id) -> WellKnownKey<(u32, u32)> {
(b":relay_dispatch_queue_remaining_capacity", para_id).encode().into()
}
/// The HRMP channel for the given identifier.
///
/// The storage entry should be accessed as an `AbridgedHrmpChannel` encoded value.
pub fn hrmp_channels(channel: HrmpChannelId) -> Vec {
let prefix = hex!["6a0da05ca59913bc38a8630590f2627cb6604cff828a6e3f579ca6c59ace013d"];
channel.using_encoded(|channel: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(channel).iter())
.chain(channel.iter())
.cloned()
.collect()
})
}
/// The list of inbound channels for the given para.
///
/// The storage entry stores a `Vec`
pub fn hrmp_ingress_channel_index(para_id: Id) -> Vec {
let prefix = hex!["6a0da05ca59913bc38a8630590f2627c1d3719f5b0b12c7105c073c507445948"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// The list of outbound channels for the given para.
///
/// The storage entry stores a `Vec`
pub fn hrmp_egress_channel_index(para_id: Id) -> Vec {
let prefix = hex!["6a0da05ca59913bc38a8630590f2627cf12b746dcf32e843354583c9702cc020"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// The MQC head for the downward message queue of the given para. See more in the `Dmp` module.
///
/// The storage entry stores a `Hash`. This is pezkuwi hash which is at the moment
/// `blake2b-256`.
pub fn dmq_mqc_head(para_id: Id) -> Vec {
let prefix = hex!["63f78c98723ddc9073523ef3beefda0c4d7fefc408aac59dbfe80a72ac8e3ce5"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// The signal that indicates whether the teyrchain should go-ahead with the proposed validation
/// code upgrade.
///
/// The storage entry stores a value of `UpgradeGoAhead` type.
pub fn upgrade_go_ahead_signal(para_id: Id) -> Vec {
let prefix = hex!["cd710b30bd2eab0352ddcc26417aa1949e94c040f5e73d9b7addd6cb603d15d3"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
/// The signal that indicates whether the teyrchain is disallowed to signal an upgrade at this
/// relay-parent.
///
/// The storage entry stores a value of `UpgradeRestriction` type.
pub fn upgrade_restriction_signal(para_id: Id) -> Vec {
let prefix = hex!["cd710b30bd2eab0352ddcc26417aa194f27bbb460270642b5bcaf032ea04d56a"];
para_id.using_encoded(|para_id: &[u8]| {
prefix
.as_ref()
.iter()
.chain(twox_64(para_id).iter())
.chain(para_id.iter())
.cloned()
.collect()
})
}
}
/// Unique identifier for the Teyrchains Inherent
pub const TEYRCHAINS_INHERENT_IDENTIFIER: InherentIdentifier = *b"parachn0";
/// The key type ID for teyrchain assignment key.
pub const ASSIGNMENT_KEY_TYPE_ID: KeyTypeId = KeyTypeId(*b"asgn");
/// Compressed or not the wasm blob can never be less than 9 bytes.
pub const MIN_CODE_SIZE: u32 = 9;
/// Maximum compressed code size we support right now.
/// At the moment we have runtime upgrade on chain, which restricts scalability severely. If we want
/// to have bigger values, we should fix that first.
///
/// Used for:
/// * initial genesis for the Teyrchains configuration
/// * checking updates to this stored runtime configuration do not exceed this limit
/// * when detecting a code decompression bomb in the client
// NOTE: This value is used in the runtime so be careful when changing it.
pub const MAX_CODE_SIZE: u32 = 3 * 1024 * 1024;
/// Maximum head data size we support right now.
///
/// Used for:
/// * initial genesis for the Teyrchains configuration
/// * checking updates to this stored runtime configuration do not exceed this limit
// NOTE: This value is used in the runtime so be careful when changing it.
pub const MAX_HEAD_DATA_SIZE: u32 = 1 * 1024 * 1024;
/// Maximum PoV size we support right now.
///
/// Used for:
/// * initial genesis for the Teyrchains configuration
/// * checking updates to this stored runtime configuration do not exceed this limit
/// * when detecting a PoV decompression bomb in the client
// NOTE: This value is used in the runtime so be careful when changing it.
pub const MAX_POV_SIZE: u32 = 10 * 1024 * 1024;
/// Default queue size we use for the on-demand order book.
///
/// Can be adjusted in configuration.
pub const ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE: u32 = 10_000;
/// Maximum for maximum queue size.
///
/// Setting `on_demand_queue_max_size` to a value higher than this is unsound. This is more a
/// theoretical limit, just below enough what the target type supports, so comparisons are possible
/// even with indices that are overflowing the underyling type.
pub const ON_DEMAND_MAX_QUEUE_MAX_SIZE: u32 = 1_000_000_000;
/// Backing votes threshold used from the host prior to runtime API version 6 and from the runtime
/// prior to v9 configuration migration.
pub const LEGACY_MIN_BACKING_VOTES: u32 = 2;
/// Default value for `SchedulerParams.lookahead`
pub const DEFAULT_SCHEDULING_LOOKAHEAD: u32 = 3;
// The public key of a keypair used by a validator for determining assignments
/// to approve included teyrchain candidates.
mod assignment_app {
use pezsp_application_crypto::{app_crypto, sr25519};
app_crypto!(sr25519, super::ASSIGNMENT_KEY_TYPE_ID);
}
/// The public key of a keypair used by a validator for determining assignments
/// to approve included teyrchain candidates.
pub type AssignmentId = assignment_app::Public;
pezsp_application_crypto::with_pair! {
/// The full keypair used by a validator for determining assignments to approve included
/// teyrchain candidates.
pub type AssignmentPair = assignment_app::Pair;
}
/// The index of the candidate in the list of candidates fully included as-of the block.
pub type CandidateIndex = u32;
/// The validation data provides information about how to create the inputs for validation of a
/// candidate. This information is derived from the chain state and will vary from para to para,
/// although some fields may be the same for every para.
///
/// Since this data is used to form inputs to the validation function, it needs to be persisted by
/// the availability system to avoid dependence on availability of the relay-chain state.
///
/// Furthermore, the validation data acts as a way to authorize the additional data the collator
/// needs to pass to the validation function. For example, the validation function can check whether
/// the incoming messages (e.g. downward messages) were actually sent by using the data provided in
/// the validation data using so called MQC heads.
///
/// Since the commitments of the validation function are checked by the relay-chain, secondary
/// checkers can rely on the invariant that the relay-chain only includes para-blocks for which
/// these checks have already been done. As such, there is no need for the validation data used to
/// inform validators and collators about the checks the relay-chain will perform to be persisted by
/// the availability system.
///
/// The `PersistedValidationData` should be relatively lightweight primarily because it is
/// constructed during inclusion for each candidate and therefore lies on the critical path of
/// inclusion.
#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Default))]
pub struct PersistedValidationData {
/// The parent head-data.
pub parent_head: HeadData,
/// The relay-chain block number this is in the context of.
pub relay_parent_number: N,
/// The relay-chain block storage root this is in the context of.
pub relay_parent_storage_root: H,
/// The maximum legal size of a POV block, in bytes.
pub max_pov_size: u32,
}
impl PersistedValidationData {
/// Compute the blake2-256 hash of the persisted validation data.
pub fn hash(&self) -> Hash {
BlakeTwo256::hash_of(self)
}
}
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Default, Hash))]
pub struct CandidateCommitments {
/// Messages destined to be interpreted by the Relay chain itself.
pub upward_messages: UpwardMessages,
/// Horizontal messages sent by the teyrchain.
pub horizontal_messages: HorizontalMessages,
/// New validation code.
pub new_validation_code: Option,
/// The head-data produced as a result of execution.
pub head_data: HeadData,
/// The number of messages processed from the DMQ.
pub processed_downward_messages: u32,
/// The mark which specifies the block number up to which all inbound HRMP messages are
/// processed.
pub hrmp_watermark: N,
}
impl CandidateCommitments {
/// Compute the blake2-256 hash of the commitments.
pub fn hash(&self) -> Hash {
BlakeTwo256::hash_of(self)
}
}
/// A bitfield concerning availability of backed candidates.
///
/// Every bit refers to an availability core index.
#[derive(PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, TypeInfo)]
pub struct AvailabilityBitfield(pub BitVec);
impl From> for AvailabilityBitfield {
fn from(inner: BitVec) -> Self {
AvailabilityBitfield(inner)
}
}
/// A signed compact statement, suitable to be sent to the chain.
pub type SignedStatement = Signed;
/// A signed compact statement, with signature not yet checked.
pub type UncheckedSignedStatement = UncheckedSigned;
/// A bitfield signed by a particular validator about the availability of pending candidates.
pub type SignedAvailabilityBitfield = Signed;
/// A signed bitfield with signature not yet checked.
pub type UncheckedSignedAvailabilityBitfield = UncheckedSigned;
/// A set of signed availability bitfields. Should be sorted by validator index, ascending.
pub type SignedAvailabilityBitfields = Vec;
/// A set of unchecked signed availability bitfields. Should be sorted by validator index,
/// ascending.
pub type UncheckedSignedAvailabilityBitfields = Vec;
/// Verify the backing of the given candidate.
///
/// Provide a lookup from the index of a validator within the group assigned to this para,
/// as opposed to the index of the validator within the overall validator set, as well as
/// the number of validators in the group.
///
/// Also provide the signing context.
///
/// Returns either an error, indicating that one of the signatures was invalid or that the index
/// was out-of-bounds, or the number of signatures checked.
pub fn check_candidate_backing + Clone + Encode + core::fmt::Debug>(
candidate_hash: CandidateHash,
validity_votes: &[ValidityAttestation],
validator_indices: &BitSlice,
signing_context: &SigningContext,
group_len: usize,
validator_lookup: impl Fn(usize) -> Option,
) -> Result {
if validator_indices.len() != group_len {
log::debug!(
target: LOG_TARGET,
"Check candidate backing: indices mismatch: group_len = {} , indices_len = {}",
group_len,
validator_indices.len(),
);
return Err(());
}
if validity_votes.len() > group_len {
log::debug!(
target: LOG_TARGET,
"Check candidate backing: Too many votes, expected: {}, found: {}",
group_len,
validity_votes.len(),
);
return Err(());
}
let mut signed = 0;
for ((val_in_group_idx, _), attestation) in validator_indices
.iter()
.enumerate()
.filter(|(_, signed)| **signed)
.zip(validity_votes.iter())
{
let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
let payload = attestation.signed_payload(candidate_hash, signing_context);
let sig = attestation.signature();
if sig.verify(&payload[..], &validator_id) {
signed += 1;
} else {
log::debug!(
target: LOG_TARGET,
"Check candidate backing: Invalid signature. validator_id = {:?}, validator_index = {} ",
validator_id,
val_in_group_idx,
);
return Err(());
}
}
if signed != validity_votes.len() {
log::error!(
target: LOG_TARGET,
"Check candidate backing: Too many signatures, expected = {}, found = {}",
validity_votes.len(),
signed,
);
return Err(());
}
Ok(signed)
}
/// The unique (during session) index of a core.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Default,
PartialOrd,
Ord,
Eq,
PartialEq,
Clone,
Copy,
TypeInfo,
RuntimeDebug,
)]
#[cfg_attr(feature = "std", derive(Hash))]
pub struct CoreIndex(pub u32);
impl From for CoreIndex {
fn from(i: u32) -> CoreIndex {
CoreIndex(i)
}
}
impl TypeIndex for CoreIndex {
fn type_index(&self) -> usize {
self.0 as usize
}
}
/// The unique (during session) index of a validator group.
#[derive(
Encode,
Decode,
DecodeWithMemTracking,
Default,
Clone,
Copy,
Debug,
PartialEq,
Eq,
TypeInfo,
PartialOrd,
Ord,
)]
#[cfg_attr(feature = "std", derive(Hash))]
pub struct GroupIndex(pub u32);
impl From for GroupIndex {
fn from(i: u32) -> GroupIndex {
GroupIndex(i)
}
}
impl TypeIndex for GroupIndex {
fn type_index(&self) -> usize {
self.0 as usize
}
}
/// A claim on authoring the next block for a given parathread (on-demand teyrchain).
#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
pub struct ParathreadClaim(pub Id, pub Option);
/// An entry tracking a claim to ensure it does not pass the maximum number of retries.
#[derive(Clone, Encode, Decode, TypeInfo, PartialEq, RuntimeDebug)]
pub struct ParathreadEntry {
/// The claim.
pub claim: ParathreadClaim,
/// Number of retries
pub retries: u32,
}
/// A helper data-type for tracking validator-group rotations.
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct GroupRotationInfo {
/// The block number where the session started.
pub session_start_block: N,
/// How often groups rotate. 0 means never.
pub group_rotation_frequency: N,
/// The current block number.
pub now: N,
}
impl GroupRotationInfo {
/// Returns the index of the group needed to validate the core at the given index, assuming
/// the given number of cores.
///
/// `core_index` should be less than `cores`, which is capped at `u32::max()`.
pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
if self.group_rotation_frequency == 0 {
return GroupIndex(core_index.0);
}
if cores == 0 {
return GroupIndex(0);
}
let cores = core::cmp::min(cores, u32::MAX as usize);
let blocks_since_start = self.now.saturating_sub(self.session_start_block);
let rotations = blocks_since_start / self.group_rotation_frequency;
// g = c + r mod cores
let idx = (core_index.0 as usize + rotations as usize) % cores;
GroupIndex(idx as u32)
}
/// Returns the index of the group assigned to the given core. This does no checking or
/// whether the group index is in-bounds.
///
/// `core_index` should be less than `cores`, which is capped at `u32::max()`.
pub fn core_for_group(&self, group_index: GroupIndex, cores: usize) -> CoreIndex {
if self.group_rotation_frequency == 0 {
return CoreIndex(group_index.0);
}
if cores == 0 {
return CoreIndex(0);
}
let cores = core::cmp::min(cores, u32::MAX as usize);
let blocks_since_start = self.now.saturating_sub(self.session_start_block);
let rotations = blocks_since_start / self.group_rotation_frequency;
let rotations = rotations % cores as u32;
// g = c + r mod cores
// c = g - r mod cores
// x = x + cores mod cores
// c = (g + cores) - r mod cores
let idx = (group_index.0 as usize + cores - rotations as usize) % cores;
CoreIndex(idx as u32)
}
/// Create a new `GroupRotationInfo` with one further rotation applied.
pub fn bump_rotation(&self) -> Self {
GroupRotationInfo {
session_start_block: self.session_start_block,
group_rotation_frequency: self.group_rotation_frequency,
now: self.next_rotation_at(),
}
}
}
impl GroupRotationInfo {
/// Returns the block number of the next rotation after the current block. If the current block
/// is 10 and the rotation frequency is 5, this should return 15.
pub fn next_rotation_at(&self) -> N {
let cycle_once = self.now + self.group_rotation_frequency;
cycle_once
- (cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
}
/// Returns the block number of the last rotation before or including the current block. If the
/// current block is 10 and the rotation frequency is 5, this should return 10.
pub fn last_rotation_at(&self) -> N {
self.now
- (self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency)
}
}
/// Information about a core which is currently occupied.
#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct ScheduledCore {
/// The ID of a para scheduled.
pub para_id: Id,
/// DEPRECATED: see:
///
/// Will be removed in a future version.
pub collator: Option,
}
/// An assumption being made about the state of an occupied core.
#[derive(Clone, Copy, Encode, Decode, TypeInfo, RuntimeDebug)]
#[cfg_attr(feature = "std", derive(PartialEq, Eq, Hash))]
pub enum OccupiedCoreAssumption {
/// The candidate occupying the core was made available and included to free the core.
#[codec(index = 0)]
Included,
/// The candidate occupying the core timed out and freed the core without advancing the para.
#[codec(index = 1)]
TimedOut,
/// The core was not occupied to begin with.
#[codec(index = 2)]
Free,
}
/// A vote of approval on a candidate.
#[derive(Clone, RuntimeDebug)]
pub struct ApprovalVote(pub CandidateHash);
impl ApprovalVote {
/// Yields the signing payload for this approval vote.
pub fn signing_payload(&self, session_index: SessionIndex) -> Vec {
const MAGIC: [u8; 4] = *b"APPR";
(MAGIC, &self.0, session_index).encode()
}
}
/// A vote of approval for multiple candidates.
#[derive(Clone, RuntimeDebug)]
pub struct ApprovalVoteMultipleCandidates<'a>(pub &'a [CandidateHash]);
impl<'a> ApprovalVoteMultipleCandidates<'a> {
/// Yields the signing payload for this approval vote.
pub fn signing_payload(&self, session_index: SessionIndex) -> Vec {
const MAGIC: [u8; 4] = *b"APPR";
// Make this backwards compatible with `ApprovalVote` so if we have just on candidate the
// signature will look the same.
// This gives us the nice benefit that old nodes can still check signatures when len is 1
// and the new node can check the signature coming from old nodes.
if self.0.len() == 1 {
(MAGIC, self.0.first().expect("QED: we just checked"), session_index).encode()
} else {
(MAGIC, &self.0, session_index).encode()
}
}
}
/// Approval voting configuration parameters
#[derive(
RuntimeDebug,
Copy,
Clone,
PartialEq,
Encode,
Decode,
DecodeWithMemTracking,
TypeInfo,
serde::Serialize,
serde::Deserialize,
)]
pub struct ApprovalVotingParams {
/// The maximum number of candidates `approval-voting` can vote for with
/// a single signatures.
///
/// Setting it to 1, means we send the approval as soon as we have it available.
pub max_approval_coalesce_count: u32,
}
impl Default for ApprovalVotingParams {
fn default() -> Self {
Self { max_approval_coalesce_count: 1 }
}
}
/// Custom validity errors used in Pezkuwi while validating transactions.
#[repr(u8)]
pub enum ValidityError {
/// The Ethereum signature is invalid.
InvalidEthereumSignature = 0,
/// The signer has no claim.
SignerHasNoClaim = 1,
/// No permission to execute the call.
NoPermission = 2,
/// An invalid statement was made for a claim.
InvalidStatement = 3,
}
impl From for u8 {
fn from(err: ValidityError) -> Self {
err as u8
}
}
/// Abridged version of `HostConfiguration` (from the `Configuration` teyrchains host runtime
/// module) meant to be used by a teyrchain or PDK such as pezcumulus.
#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(PartialEq))]
pub struct AbridgedHostConfiguration {
/// The maximum validation code size, in bytes.
pub max_code_size: u32,
/// The maximum head-data size, in bytes.
pub max_head_data_size: u32,
/// Total number of individual messages allowed in the teyrchain -> relay-chain message queue.
pub max_upward_queue_count: u32,
/// Total size of messages allowed in the teyrchain -> relay-chain message queue before which
/// no further messages may be added to it. If it exceeds this then the queue may contain only
/// a single message.
pub max_upward_queue_size: u32,
/// The maximum size of an upward message that can be sent by a candidate.
///
/// This parameter affects the size upper bound of the `CandidateCommitments`.
pub max_upward_message_size: u32,
/// The maximum number of messages that a candidate can contain.
///
/// This parameter affects the size upper bound of the `CandidateCommitments`.
pub max_upward_message_num_per_candidate: u32,
/// The maximum number of outbound HRMP messages can be sent by a candidate.
///
/// This parameter affects the upper bound of size of `CandidateCommitments`.
pub hrmp_max_message_num_per_candidate: u32,
/// The minimum period, in blocks, between which teyrchains can update their validation code.
pub validation_upgrade_cooldown: BlockNumber,
/// The delay, in blocks, before a validation upgrade is applied.
pub validation_upgrade_delay: BlockNumber,
/// Asynchronous backing parameters.
pub async_backing_params: AsyncBackingParams,
}
/// Abridged version of `HrmpChannel` (from the `Hrmp` teyrchains host runtime module) meant to be
/// used by a teyrchain or PDK such as pezcumulus.
#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Default, PartialEq))]
pub struct AbridgedHrmpChannel {
/// 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.
pub max_total_size: u32,
/// The maximum message size that could be put into the channel.
pub max_message_size: u32,
/// The current number of messages pending in the channel.
/// Invariant: should be less or equal to `max_capacity`.s`.
pub msg_count: u32,
/// The total size in bytes of all message payloads in the channel.
/// Invariant: should be less or equal to `max_total_size`.
pub total_size: u32,
/// A head of the Message Queue Chain for this channel. Each link in this chain has a form:
/// `(prev_head, B, H(M))`, where
/// - `prev_head`: is the previous value of `mqc_head` or zero if none.
/// - `B`: is the [relay-chain] block number in which a message was appended
/// - `H(M)`: is the hash of the message being appended.
/// This value is initialized to a special value that consists of all zeroes which indicates
/// that no messages were previously added.
pub mqc_head: Option,
}
/// A possible upgrade restriction that prevents a teyrchain from performing an upgrade.
#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
pub enum UpgradeRestriction {
/// There is an upgrade restriction and there are no details about its specifics nor how long
/// it could last.
#[codec(index = 0)]
Present,
}
/// A struct that the relay-chain communicates to a teyrchain indicating what course of action the
/// teyrchain should take in the coordinated teyrchain validation code upgrade process.
///
/// This data type appears in the last step of the upgrade process. After the teyrchain observes it
/// and reacts to it the upgrade process concludes.
#[derive(Copy, Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)]
pub enum UpgradeGoAhead {
/// Abort the upgrade process. There is something wrong with the validation code previously
/// submitted by the teyrchain. This variant can also be used to prevent upgrades by the
/// governance should an emergency emerge.
///
/// The expected reaction on this variant is that the teyrchain will admit this message and
/// remove all the data about the pending upgrade. Depending on the nature of the problem (to
/// be examined offchain for now), it can try to send another validation code or just retry
/// later.
#[codec(index = 0)]
Abort,
/// Apply the pending code change. The parablock that is built on a relay-parent that is
/// descendant of the relay-parent where the teyrchain observed this signal must use the
/// upgraded validation code.
#[codec(index = 1)]
GoAhead,
}
/// Consensus engine id for pezkuwi v1 consensus engine.
pub const PEZKUWI_ENGINE_ID: pezsp_runtime::ConsensusEngineId = *b"POL1";
/// A consensus log item for pezkuwi validation. To be used with [`PEZKUWI_ENGINE_ID`].
#[derive(Decode, Encode, Clone, PartialEq, Eq)]
pub enum ConsensusLog {
/// A teyrchain upgraded its code.
#[codec(index = 1)]
ParaUpgradeCode(Id, ValidationCodeHash),
/// A teyrchain scheduled a code upgrade.
#[codec(index = 2)]
ParaScheduleUpgradeCode(Id, ValidationCodeHash, BlockNumber),
/// Governance requests to auto-approve every candidate included up to the given block
/// number in the current chain, inclusive.
#[codec(index = 3)]
ForceApprove(BlockNumber),
/// A signal to revert the block number in the same chain as the
/// header this digest is part of and all of its descendants.
///
/// It is a no-op for a block to contain a revert digest targeting
/// its own number or a higher number.
///
/// In practice, these are issued when on-chain logic has detected an
/// invalid teyrchain block within its own chain, due to a dispute.
#[codec(index = 4)]
Revert(BlockNumber),
}
impl ConsensusLog {
/// Attempt to convert a reference to a generic digest item into a consensus log.
pub fn from_digest_item(
digest_item: &pezsp_runtime::DigestItem,
) -> Result